0016. Printing
- Status: Accepted
- Date: 2026-10-27
Context
Section titled “Context”Shops use many brands of thermal printer, mostly cheap ESC/POS models from China plus Epson, and Sunmi Android terminals with built-in printers. Printer vendors ship SDKs, but several are closed binaries or carry “all rights reserved” licences that conflict with the AGPL. Printers also disagree on less common commands, and they go offline, run out of paper or get unplugged during service.
Decision
Section titled “Decision”- OpenKedai builds ESC/POS bytes itself (
packages/escpos) from a small command subset that common printers share. Each job starts by resetting the printer and leaving Chinese double-byte mode (ESC @,FS .); text is ASCII, with accents and symbols transliterated. - Network printers get raw bytes over TCP port 9100 from our own native module (Network.framework
on iOS,
java.net.Socketon Android). Bytes go in 4 KB chunks with short pauses, and every connect and send has a timeout. - Sunmi built-in printers go through Sunmi’s SDKs (both Apache-2.0):
com.sunmi:printerlibraryfor the classic print service, withcom.sunmi:printerxas the fallback for newer devices such as the P-series. No other vendor SDK is used: the Epson ePOS SDK and closed binaries such aslibPrinterSDK.aare not AGPL-compatible, and raw TCP works on those printers anyway. - QR codes print as images (
GS v 0) by default, because not every printer has a QR command; the printer’s own QR command is an option. - Every printer’s profile (characters per line, cutter, QR mode, drawer) is a setting with defaults by paper width (ADR 0014).
- All printing goes through a stored queue that sends one job at a time per printer, in order, and retries with growing delays. Checkout and kitchen actions only add jobs to the queue, so a printer can never block a sale (ADR 0002).
Consequences
Section titled “Consequences”- No printer app or driver to install, and nothing proprietary in the build except Sunmi’s
Apache-2.0 libraries (listed in
THIRD_PARTY_NOTICES.md). - Chinese text needs a raster fallback or a printer font (M8); until then it prints as “?”.
- Printer status queries (
DLE EOT) aren’t used yet. A failed connection is the offline signal. - Before targeting Android 17 (SDK 37), the app must request
ACCESS_LOCAL_NETWORK. Without it, network printing fails with timeouts that look like an offline printer.
For AI tools: llms.txt ·llms-full.txtopenkedai.com