macOS auto-adds a USB LabelWriter 450 with the GENERIC CUPS driver (dymo.ppd, ModelName "DYMO Label Printer"), which has 10 fixed sizes and no CustomPageSize block — so a custom paper size made in the page-setup dialog can never reach the printer. CUPS falls back to w81h252 (Address, 28.6x88.9mm) and the 54x24mm design prints rotated 90 degrees and shrunk. Cost a bench session to diagnose; the extension's labels.js was never at fault. Adds the stock in both feed orientations (pg55x25 / pg55x25L — John's price roll is the landscape-feed one) plus patch_ppd.py to regenerate. Lives here because mac/dymo.py drives the same printer. Must be re-applied after any macOS update or after re-adding the printer, so the file and the lpadmin invocation are both written down in the README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
99 lines
4.9 KiB
Markdown
99 lines
4.9 KiB
Markdown
# pricegod-urovo-daemon
|
||
|
||
The **Windows** counterpart to the Mac `rfid-daemon`. Instead of a Chafon gun writing a
|
||
loose chip while a Dymo prints a separate sticker, this drives the **Urovo D812R+ (RFID)**
|
||
to **print the label AND encode the UHF chip in one pass** on the composite (paper+chip) rolls.
|
||
|
||
It listens on `http://localhost:7790/` with `CORS *`, so it's a drop-in for the PriceGod
|
||
extension's existing `daemon.js` client — same port, same JSON shape.
|
||
|
||
## Run it
|
||
Double-click **`start-daemon.cmd`** (leave the window open while you work). That's it —
|
||
no Node, no .NET SDK, no gitea clone. It's a self-contained `.exe`.
|
||
|
||
To rebuild after editing `daemon.cs`: double-click **`build.cmd`**.
|
||
|
||
## What's inside
|
||
- `daemon.cs` — the service (C#, .NET Framework 4.x).
|
||
- `pricegod-urovo-daemon.exe` — the compiled daemon.
|
||
- `GTSPL_SDK.dll`, `GTSPL_SDK_C.dll`, `zlib.net.dll` — the Gainscha/Urovo print SDK
|
||
(must sit beside the .exe). Copied from the vendor Windows SDK.
|
||
|
||
The print/encode sequence is a straight port of the proven `gtcheck.cs` `rfidgo` path:
|
||
`SET RIBBON OFF` → continuous geometry (`GAP 0`, RFID rolls blind the optical gap sensor)
|
||
→ `writeUHF` → draw text + QR → `printlabel` → read-back verify.
|
||
|
||
## Routes
|
||
| method | path | body | returns |
|
||
|---|---|---|---|
|
||
| GET | `/status` | — | `{ok, ready, status, statusText, printer}` |
|
||
| POST | `/print-encode` | `{sku, releaseId, artist?, title?, price?, condition?, w?, h?, gap?}` | `{ok, sku, releaseId, epc, verified, status}` |
|
||
| POST | `/write-tag` | alias of `/print-encode` (the daemon.js name) | same |
|
||
| GET | `/read-tag` | — | `{ok, epc, sku, releaseId, recognized}` |
|
||
| POST | `/calibrate` | — | RFID auto-calibration |
|
||
| POST | `/recover` | — | ribbon-off + one feed to clear a fault |
|
||
|
||
Quick test (PowerShell):
|
||
```powershell
|
||
Invoke-RestMethod http://localhost:7790/status
|
||
```
|
||
|
||
## SKU ↔ EPC scheme (⚠ verify)
|
||
The 96-bit EPC (12 bytes) is packed as: **6 bytes** 14-digit timestamp SKU · **4 bytes**
|
||
release_id · **2 bytes** `0xEC01` marker. This lives in the `Epc` class in `daemon.cs` and
|
||
is the **only** thing that needs to change if it must match a different (Mac/Chafon) layout —
|
||
nothing else depends on the byte order. Confirm by reading an existing tag: put a
|
||
Chafon-written record at the antenna and `GET /read-tag`.
|
||
|
||
## DYMO LabelWriter 450 on macOS — the PPD you will need again
|
||
|
||
Not the daemon, but it lives here because `mac/dymo.py` drives the same printer.
|
||
|
||
macOS auto-adds a USB LabelWriter 450 with the **generic** CUPS driver
|
||
(`*PCFileName: "dymo.ppd"`, `*ModelName: "DYMO Label Printer"`). That PPD ships 10 fixed
|
||
label sizes and **no** `CustomPageSize`/`VariablePaperSize` block — so a custom paper size
|
||
made in the macOS page-setup dialog can never reach the printer. CUPS silently falls back
|
||
to `w81h252` (Address, 28.6 × 88.9 mm), and a 54×24 mm label design comes out **rotated 90°
|
||
and shrunk**, with a big blank area. Nothing is wrong with the extension's `labels.js`.
|
||
|
||
`mac/dymo-24x55.ppd` is the generic PPD patched to add the shop's 24×55 mm price stock, in
|
||
both feed orientations, so the right one can be picked in the print dialog:
|
||
|
||
| PageSize | pt | mm | roll |
|
||
|---|---|---|---|
|
||
| `pg55x25` | 72 × 155 | 25.4 × 54.7 | ~25 mm wide, label runs 55 mm along the feed |
|
||
| `pg55x25L` | 155 × 72 | 54.7 × 25.4 | ~55 mm wide, label runs 25 mm along the feed |
|
||
|
||
**John's price roll is the landscape-feed kind → use `pg55x25L`.**
|
||
|
||
```sh
|
||
sudo lpadmin -p <queue> -P mac/dymo-24x55.ppd # apply (queue on JING5: make_it_soso)
|
||
sudo lpadmin -p <queue> -m drv:///sample.drv/dymo.ppd # revert to stock
|
||
```
|
||
|
||
**Re-apply after any macOS update or after re-adding the printer** — both revert the queue to
|
||
the generic driver and the symptom comes straight back.
|
||
|
||
Regenerate from the **pristine** driver PPD — once applied, the queue's own PPD is already
|
||
patched and `patch_ppd.py` will refuse it:
|
||
|
||
```sh
|
||
ppdc -d /tmp/ppdout /usr/share/cups/drv/sample.drv
|
||
python3 mac/patch_ppd.py mac/dymo-24x55.ppd /tmp/ppdout/dymo.ppd # byte-identical, PASSes cupstestppd
|
||
```
|
||
|
||
Two traps it handles: margins are set to 2 pt sides / 4 pt ends instead of the driver's
|
||
stock 14.9 pt, which would eat 10.5 mm of a 55 mm label; and every one of the 31 languages
|
||
in `*cupsLanguages` needs a translation string per new choice or `cupstestppd` FAILs.
|
||
|
||
Dead end for next time: `LabelPrinter-*.pkg` in `~/Documents` is **not** the DYMO driver —
|
||
it's the generic bundle for the PM-246S/Wagtail printers.
|
||
|
||
## Notes / open items
|
||
- Default label geometry is `65×37 mm`, continuous (`GAP 0`). Adjust to your actual RFID
|
||
roll via the `w`/`h`/`gap` fields, or change the `DEF_*` constants.
|
||
- The label layout (text lines + QR) is functional, not yet pixel-matched to the 51×19
|
||
Dymo design in the extension's `labels.js`.
|
||
- The Chafon gun is still needed for **reading a loose tag off a shelf** — the Urovo can
|
||
only read/write a tag physically inside the printer.
|