diff --git a/README.md b/README.md index 99834bd..f7f1464 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,22 @@ InvenTree imports so it is unit-tested here: | any other fault | `ERROR`, carrying the reason | | agent will / shutdown | `DISCONNECTED` | +### When it refreshes + +The status is read from the retained topic in three places, which between them keep the +page honest without polling the printer itself: + +| when | hook | +|---|---| +| machine initialisation | `init_machine` | +| a manual restart from the Admin Center | `restart_machine` | +| periodically | `ping_machines`, driven by InvenTree's `MACHINE_PING_ENABLED` (on by default) | + +The periodic one is not a nicety. Machine status lives in the Django cache, so clearing +that cache drops every `machine:*` key at once — and this deployment runs Redis without +persistence, so a restart does exactly that. With only `init_machine` the page then sat +at `UNKNOWN` with an empty status text until someone printed or the pods restarted. + Two deliberate distinctions. **Unreported media is not healthy media**: `media_ok` is a tri-state, and a printer that has said nothing shows "media unreported" rather than "media ok". And **battery percentage alone is not enough** — it pins at 100% whenever diff --git a/inventree_label_dispatch/driver.py b/inventree_label_dispatch/driver.py index 892e2da..00305f5 100644 --- a/inventree_label_dispatch/driver.py +++ b/inventree_label_dispatch/driver.py @@ -110,6 +110,37 @@ def _apply(self, machine, member: str, text: str) -> None: machine.set_status(getattr(LabelPrinterStatus, member)) machine.set_status_text(text) + def restart_machine(self, machine) -> None: + """Re-read the printer's state after a manual restart. + + A restart clears the machine's shared state, and without this nothing puts it + back: the page then shows UNKNOWN with an empty status text -- the defaults + `get_shared_state` returns for missing keys -- while the machine itself + reports `initialized`, no errors and a driver available. An empty status text + is diagnostic on its own, since no path in this driver produces one. + """ + self._refresh_status(machine) + + def ping_machines(self) -> None: + """Periodic refresh, driven by InvenTree's MACHINE_PING_ENABLED (default on). + + This is what keeps the page honest between prints. It matters more than it + looks: machine status lives in the Django cache, so when that cache is cleared + -- a Redis restart, and this deployment runs Redis deliberately without + persistence -- every `machine:*` key vanishes at once. Before this hook the + only thing that re-read the retained topic was machine initialisation, so the + page stayed blank until someone printed or the pods restarted. + + One machine's broker trouble must not stop the others being refreshed, hence + the per-machine guard. `_refresh_status` already turns an unreachable broker + into an UNKNOWN status rather than an exception; this catches anything else. + """ + for machine in self.get_machines(): + try: + self._refresh_status(machine) + except Exception as exc: # noqa: BLE001 - one machine must not break the loop + machine.handle_error(exc) + def _refresh_status(self, machine) -> None: printer_id = machine.get_setting("PRINTER_ID", "D") try: diff --git a/inventree_label_dispatch/version.py b/inventree_label_dispatch/version.py index 91ce6a5..77d41e4 100644 --- a/inventree_label_dispatch/version.py +++ b/inventree_label_dispatch/version.py @@ -1,3 +1,3 @@ """Single source of truth for the plugin version.""" -__version__ = "0.2.0" +__version__ = "0.2.1"