Skip to content

feat: key real printers by serial number, not the volatile USB id — closes #40#41

Merged
szrudi merged 2 commits into
mainfrom
feat/stable-printer-id
Jun 13, 2026
Merged

feat: key real printers by serial number, not the volatile USB id — closes #40#41
szrudi merged 2 commits into
mainfrom
feat/stable-printer-id

Conversation

@szrudi

@szrudi szrudi commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Closes #40.

Why

A real printer's PrinterInfo.id was labelle's usb_id:

f"Bus {bus:03} Device {address:03}: ID {vendor_product_id}"

address is the kernel-assigned USB device address, reassigned on every re-enumeration — replug, reboot, and (critically) this app's own USB power-save cycle (power off when idle → on at page load). Keying anything by it means the identity drifts constantly on the Pi deployment.

What

_printer_id(dev): prefer serial:<serial_number> (stable across re-enumeration — the Dymo LabelManager PnP reports one), fall back to the usb_id only when no serial is present. Used in both places that matter so they always agree:

  • list_printers() — the id emitted to the client,
  • print_label / print_bitmap — resolving a request's printer_id back to a device.

USB power feature is untouched (keyed by hub/port via VID:PID). Virtual printers untouched (virtual:<name> already stable). Client is untouched — the id is opaque to it.

Why now (stacked under the per-printer-settings PR)

This is the stable-identity foundation that makes per-printer settings (#20, PR #39) actually durable on the hardware — otherwise saved settings would orphan after each idle power-off→on. PR #39 will rebase on top of this and key off the stable id for free. Also feeds the status/alias work in #38.

Tests

_printer_id serial vs usb_id-fallback; list_printers emits the serial id; print resolves a device by its serial id and raises on a non-match. Full backend suite green (223).

Versioning

None — stacked under #39; left at 1.7.0 so merging triggers no separate release. Ships in the single v1.8.0 that #39 cuts.

Note

Edge case left as documented behavior: a device reporting no serial falls back to the volatile usb_id (unavoidable without a serial), and two devices reporting identical serials would collide — neither applies to the single Dymo target.

🤖 Generated with Claude Code

labelle's usb_id embeds the kernel-assigned Bus/Device address, which is
reassigned on every re-enumeration — replug, reboot, and this app's own
USB power-cycling (power off when idle, on at page load). Keying a printer
by it means any saved per-printer state orphans the moment the device
re-enumerates. Introduce _printer_id(dev): prefer "serial:<sn>" (stable
across re-enumeration), fall back to the usb_id only when the device
reports no serial. Use it both in list_printers and in the print/
print_bitmap device resolution so the emitted id always resolves back.

Lays the stable-identity groundwork for per-printer settings (#20) and
the status/alias work in #38. Closes #40.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the backend’s real-printer identity scheme so USB printers are keyed by a stable serial-number-based ID (serial:<sn>) when available, falling back to the existing volatile USB bus/address ID only when a serial is not reported. This prevents printer identity drift across USB re-enumeration (replug/reboot/power-cycle), which is foundational for durable per-printer persisted settings.

Changes:

  • Add _printer_id(dev) and use it consistently for real-printer IDs in list_printers(), print_label(), and print_bitmap().
  • Add backend tests covering serial-vs-fallback behavior, list emission, print resolution by serial, and non-match error behavior.
  • Update architecture docs to describe the new real-printer ID format; bump project version 1.7.0 -> 1.8.0.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
server/printer_service.py Introduces _printer_id() and switches real-printer list/resolve logic to stable serial-based IDs.
server/tests/test_printer_service.py Adds coverage ensuring serial IDs are emitted and resolved correctly (with fallback and error cases).
docs/ARCHITECTURE.md Documents the real-printer ID format change (serial preferred; bus/address fallback).
package.json Increments version to 1.8.0.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

This PR is stacked under the per-printer-settings work (#39); no separate
release is wanted. Leave package.json at 1.7.0 so merging this triggers no
tag/publish — the changes ride into the single v1.8.0 that #39 ships.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@szrudi szrudi merged commit a5d2905 into main Jun 13, 2026
5 checks passed
@szrudi szrudi deleted the feat/stable-printer-id branch June 13, 2026 07:38
szrudi added a commit that referenced this pull request Jun 13, 2026
Brings in #41 (serial ids), #42 (virtual ids), #44 (default printer
selection), #45 (shared state_store + UTF-8). Conflict resolution:
- state_store.py / usb_power.py / test_state_store.py: took main's (the
  #45 versions with UTF-8 read/write + corrected comment + non-ASCII
  test) — they supersede #39's older extracted copies.
- test_smoke.py: kept #39's (superset — adds printer_settings module and
  the /api/printers/<id>/settings route on top of #45's ownership guard).
- useLabelStore setAvailablePrinters: combined main's default-printer
  selection with #39's availablePrintersLoaded flag.
- SettingsBar + its tests, useLabelStore tests, ARCHITECTURE.md:
  unioned #44's selector changes with #39's persist/load-gate.

Frontend 81, backend 276, build green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Key per-printer settings by serial number, not the unstable USB bus/address id

2 participants