phomemo thermal printing

This commit is contained in:
Wouter Groeneveld 2023-02-03 10:28:23 +01:00
parent ba1cfb9e8c
commit 540a9703b2
4 changed files with 46 additions and 1 deletions

View File

@ -5,6 +5,7 @@ categories:
- learning
tags:
- journaling
- printer
---
My Polaroid Pogo mini printer, the one [I've been using for years](/post/2017/07/journaling-in-practice/) to instant-print-and-stick tiny and ugly but serviceable photos into my journals, broke. The battery died a long time ago but the power adapter still worked. Recently though, nine out of ten attempts to send a photo through Bluetooth wouldn't get accepted. Instead, I was greeted with flashing red lights---the error code for "jammed paper"---liar! After several salvaging attempts, I had enough, threw it out, and bought a replacement: the hip and flashy [HP Sprocket](https://sprocketprinters.com/).

View File

@ -45,7 +45,7 @@ Without a doubt the best modern Bond incarnation, and just like _On Her Majesty'
> Nothing to declare! Just a cello!
_Sod the rules!_ shouts Timothy Dalton's James Bond to Felix Leiter, when the latter reprimanded him about purposely missing a shot. That's right, sod 'em! Dalton is an excellent Bond actor that I feel is perhaps even darker than Daniel Craig's movies, and the over-the-top double crossing by Koskov a.k.a. Jeroen Krabbé is just hilarious. A weird combination that somehow works, and to top it all of, a staged death in an opera, _For Your Eyes Only_. No wait, that _happened to the other fellow_. Wait.
_Sod the rules!_ shouts Timothy Dalton's James Bond to Felix Leiter, when the latter reprimanded him about purposely missing a shot. That's right, sod 'em! Dalton is an excellent Bond actor that I feel is perhaps even darker than Daniel Craig's movies, and the over-the-top double crossing by Koskov a.k.a. Jeroen Krabbé is just hilarious. A weird combination that somehow works, and to top it all of, a staged death in an opera, _For Your Eyes Only_. No, wait, that _happened to the other fellow_. No, wait.
![](../living-daylights.jpg "A spontaneous applause by Kara and James.")

View File

@ -0,0 +1,44 @@
---
title: Phomemo Thermal Printing On MacOS
date: 2023-02-03T10:00:00+01:00
tags:
- printer
categories:
- software
---
My wife bought another set of mini printers for scrapbooking, including the [Phomemo M02 mini printer](https://phomemo.com/collections/phomemo-m02). Phomemo is a Chinese brand I've never heard of before, and sadly, as I expected, it requires the use of a proprietary mobile app in order to send something to the printer. That very much stinks---and I've complained about this before in 2021 when I replaced my mini printer [with a HP Sprocket one](/post/2021/09/hp-sprocket-mini-printer). I just don't get it why a simple "share via Bluetooth" functionality can't be implemented. It's just a few lines of extra code in that hardware. But no.
Anyway, I thought I'd put on my hacking hat and try to see if I could come up with some code that would be able to send stuff to the thermal printer, without the usage of their app. A quick search on the good ol' web taught me [vivier at GitHub](https://github.com/vivier/phomemo-tools) already wrote a set of Phomemo tools that connects it to a CUPS printer server on Linux using a few Python filters---great! But does it work on macOS? Drivers being hardware-dependent, the answer is a probable no. After an hour of trying, the answer was a definite no.
The problem is twofold:
1. vivier's scripts use Python's deprecated Pybluez, that has been forked a couple of times, but ultimately, doesn't work on macOS (at least not on my M1 with Ventura 13.2). Mac's Bluetooth drivers, [CoreBluetooth](https://developer.apple.com/documentation/corebluetooth?language=objc), aren't properly supported. Great.
2. The part where the script is connected to a virtual printer driver doesn't work on macOS. Granted, Ventura also runs a CUPS service; but its file/driver locations are different, as is its structure. Great.
The first problem was fixed by turning to Go and utilizing [TinyGo's Bluetooth modules](https://pkg.go.dev/tinygo.org/x/bluetooth#section-readme) that sit on top of CoreBluetooth[^corebl] and is also compatible with Linux, Windows, and bare metal microcontrollers. I had no idea how Bluetooth---or printer drivers---works, and I still barely do, but "it just works". `adapter.Scan()` found our Phomemo M02, connecting to the MAC works, discovering services works (there's only one), and finding characteristics works (`0000ff01-x` for reading results, `0000ff02-x` for writing, and `0000ff03-x` for... no idea!).
[^corebl]: I later learned that, in Python, through PyObjC, you can also call CoreBluetooth directly. I would probably have preferred to keep everything in Python.
The source code is available at my Git repository called [phomemo-printer](https://git.brainbaking.com/wgroeneveld). It's very hacky and works for our specific situation but could do with a week of fine-tuning---which I don't have. For the second problem, I've had to cut many corners. For instance; I wanted my wife to be able to use it as a "printer" to select in a generic print dialog instead of running a CLI script. The options were:
- Try to get it to integrate with Mac's version of CUPS. My knowledge and time is just too limited to do that.
- Create a virtual printer driver using for example IPP or the [Internet Printing Protocol](https://istopwg.github.io/ipp/ippguide.html). That involves implementing a lot of HTTP endpoints and would probably work but the effort is just too high. I only found existing IPP clients, not servers (one in Java, though).
- In macOS, you can modify the drop-down menu of the "PDF" print button; these are called "PDF Services" and are apps/scripts/folders located in `~/Library/PDF\ Services`. I read about it [on John M. Simpson's blog](https://jms1.net/osx-pdf-services.shtml), but of course, that doesn't work anymore in modern macOS versions, because `printtool` [runs in a sandbox](https://apple.stackexchange.com/questions/423478/fix-restore-print-to-pdf-to-preset-location-in-big-sur) and has access to pretty much nothing. I gave up after two hours of debugging and digging through Mac system logs. I couldn't get past:
```
[kernel] Sandbox: zsh(34634) deny(1) file-read-data /Users/user/.zshenv
[printtool] Workflow (344546) stopped with status 1
```
Using Automator to wrap the script in a "native" workflow or app folder didn't work, granting `printtool` disc access didn't work, adding `Sandboxing Relaxed` to a mysterious cupsd config file didn't work.
I settled with a sup-par but working solution: drop images in `~/Downloads/phomemo`, and have a cron job---I'm sorry, [a pretty XML launchd job](https://alvinalexander.com/mac-os-x/mac-osx-startup-crontab-launchd-jobs/)---pick up, print, then delete these files every minute. I'm annoyed I have to settle with this, but it's been a constant struggle between putting in enough time and going (too) deep trying to understand how every moving part works. It turned out to be surprisingly complex.
The most important part was already done by vivier. You can't simply send a JPG/PNG byte stream to the printer: it expects EPSON ESC/POS commands, and thus a header, a footer, and every block of 255 bytes, a block marker in 16-bit little-endian. Images can't be more than 384 points per line, so scaling and transforming is needed as well, as is grayscale conversion. I currently simply run the Python script from within my Go script; but of course it should have been ported; yet the "batteries included" part of Python's image processing library PIL is just too difficult to quickly do that.
Still, at least _something_ rolls out of the printer with the help of some code I wrote:
![](../phomemo.jpg "The Phomemo M02, after printing a test image.")
Yay! Feel free to improve/steal/hack away.

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB