DYMO LabelManager 280 label printing - #78
Open
abbyfluoroethane wants to merge 3 commits into
Open
Conversation
The existing part/inventory label templates target a 4in-class label with a QR code, which doesn't fit the LabelManager 280 (max 12mm/1/2in D1 tape, 180dpi over USB) — a QR isn't legible at that height. Add fmt=dymo to /label, rendering a compact single-line text label sized for the tape instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014jPbhRuDUZLie159gQxTDZ
Physical testing against a real LabelManager 280 over USB surfaced several things the first pass got wrong that couldn't have been caught without a printer in hand: - The driver's native page is portrait (narrow = 12mm tape width, long = feed direction); content has to be pre-rotated -90deg in CSS to read correctly off the tape, and the @page size has to match one of the driver's declared presets exactly. - QR is unreadable at this print width (~1.5px/module at 180dpi) — a 1D barcode was tried next but its narrow bars bled together at this resolution too. Data Matrix needs far fewer modules per side for a short identifier (~16x16 vs QR's 21x21+) and is what actually scans. - A fixed-width content box left blank tape wherever content was shorter than the cap; sizing to content, and picking between the two validated page-length presets based on actual label content, fixes the excess tape. Also switches the label format itself to PN / name / SN·LOT · OPAL# · QTY per request, applies to both the part and inventory label routes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014jPbhRuDUZLie159gQxTDZ
Browsers don't expose a printer-selection API to web pages, so getting "pick a printer in our own UI, hit Print, job just goes" requires the server to render the label and dispatch it itself. Adds: - core/dymo_label.py: reportlab-based native PDF renderer for the DYMO format, geometry carried over from the hardware-validated HTML/CSS version (rotation, page presets, cross-tape budget). Data Matrix goes through pystrich's own get_pilimage() — its `.matrix` attribute turned out to be stale data that dropped the finder-pattern border and only produced a scannable code once discovered and fixed on hardware. - core/printing.py: CUPS printer discovery/dispatch via `lpstat`/`lp`. OPAL runs on one machine, so this talks straight to that machine's print system rather than through a client-side dialog. - /label/printers and /label/print-direct web routes, a shared modal partial, and wiring on both the part and inventory detail pages. This is a second implementation of the label layout alongside the HTML one (a deliberate tradeoff over bundling a headless browser at runtime) and was validated with real test prints against the LM280 over USB. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014jPbhRuDUZLie159gQxTDZ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/labelroutes.What's in here, and why it looks the way it does
Everything here was tuned against a real LabelManager 280 over USB, not guessed from datasheets — several details only became obvious with a printer in hand:
label_dymo.html, HTML/CSS +window.print()) and a new nativecore/dymo_label.py(reportlab) for direct-print, so OPAL doesn't need to bundle a headless browser at runtime. This is a deliberate tradeoff — the layout is maintained in two places instead of one — discussed and chosen explicitly over the Playwright alternative.lpstat/lp(core/printing.py) rather than a client-side print API, since OPAL runs on one machine and "print" means print to whatever's attached to that machine.Test plan
uv run pytest— 932 passed, 1 skippeduv run ruff check src/ tests/— cleanhttps://claude.ai/code/session_014jPbhRuDUZLie159gQxTDZ