Files
visitor-signin/.claude-context/sessions/2026-09-07-native-ql-protocol.md
T

3.4 KiB
Raw Blame History

Native Brother QL Protocol (replacing brother_ql subprocess)

Date: 2026-09-07 Project: visitor-signin Status: ongoing Tags: printing, brother-ql, ql-820nwb, raster, tcp, node, dithering, feature-branch

Context

Badge printing shells out to Python brother_ql, whose network backend never reads the socket — so jobs the printer refuses can look successful — and which needed special handling for the two-colour DK-22251 roll. A native Node.js implementation of the QL raster protocol was built on a feature branch to remove the Python dependency and get honest error handling. This work is on feature/native-ql-protocol and has not been merged into deploy.

Key Decisions

  • Native Node raster builder + TCP transport instead of brother_ql — removes the Python subprocess and lets the app control the byte stream directly.
  • Command stream written against Brother's raster command manual, not reverse-engineered from brother_ql — e.g. the invalidate sequence for this series is 400 bytes, not 200.
  • Printer status is best effort, not a precondition — the QL-820NWB does not return status frames over TCP (only USB, per the manual), so a silent printer is treated as normal. Flush before closing the socket.
  • Drop-in printPng API so printer.js can switch with a small patch rather than a rewrite.
  • Patch scripts instead of hand-edits — scripts/wire-native-printing.mjs is brace-matching, idempotent and writes a .bak first.
  • Keep Python/brother_ql in the Dockerfile for now as a rollback path; remove only after a stable day of native printing.
  • Floyd–Steinberg dithering targeting a fixed ink coverage (default 33.3%) for badge photos, to reduce blotchy faces.

Technical Details

  • New modules: ql-raster.js (command builder), ql-status.js (status frame decoder), ql-transport.js (TCP 9100), ql-print.js (printPng drop-in).
  • Patch scripts: scripts/wire-native-printing.mjs; a second patch script adds photo dithering.
  • Docs: docs/PRINTING.md.
  • Badge bitmap width 696 dots (62 mm head) via @napi-rs/canvas.
  • DK-22205 and DK-22251 share 62×90 mm dimensions — roll type must be part of media matching.
  • Two labels printed successfully in shell-level testing.

Code Changes

  • (feature branch) ql-raster.js, ql-status.js, ql-transport.js, ql-print.js — new.
  • (feature branch) printer.js wired to the native module (a9e07b3).
  • (feature branch) Floyd–Steinberg dithering + fixed ink coverage.
  • (feature branch) docs/PRINTING.md.

Open Questions / Next Steps

  • deploy has since gained its own photo halftoning and printing fixes (2026-09-16). Before merging, diff the feature branch against deploy — expect conflicts in printer.js and the photo pipeline.
  • Handle the tri-state printer ready value (true / false / null = unknown) in the admin console.
  • After merge and a stable day: remove Python from the Dockerfile, delete dead explainPrintError / runBrotherQl.

Artifacts

  • Branch: feature/native-ql-protocol (head 8664a1d)
  • 1b4b9d6 — Add native Brother QL raster command builder
  • b4001c9 — Correct the command stream against Brother's raster manual
  • 851e021 — Make printer status best effort, not a precondition
  • a9e07b3 — Wire printer.js to the native QL protocol module
  • Repo: https://gitea.hideawaygaming.com.au/jessikitty/visitor-signin