Przejdź do treści

Etap 5 — Kiosk hardware integration

Droga Modbus jest martwa — ten etap jest historyczny

Cały etap 5 opisuje bezpośredni sterownik Modbus TCP w kiosku (ModbusLockerHardware). Od etapu 9 kiosk nie steruje sprzętem bezpośrednio — gada z agentem SmartConf po lokalnym API 127.0.0.1:8800 (POST /v1/doors/{N}/open, POST /v1/jobs/open + poll). Ścieżki Modbus zostały zakomentowane w etapie 9/«G», a pole adresu Modbus skrytki usunięte z bazy w etapie 20. Pełny opis nowej drogi → Komunikacja kiosk ↔ agent.

Bugi lifecycle z v0.78v0.83 (poniżej) nadal mają wartość historyczną — opisują realne wyścigi otwarcia/zamknięcia, które dziś rozwiązuje pre-check lockerOpenPreCheck (na SmartConf = NO-OP) oraz Job API (agent zarządza cyklem i re-ryglem).

Etap 5 took the Flutter kiosk from a MockLockerHardware proof-of-concept to a Modbus-driven production kiosk on LOCKER-SZB-SDI-001. It also closed several lifecycle bugs that only surfaced once a real lock + sensor was on the bus.

Production state (aktualne na v0.78–0.83) — NIEAKTUALNE

LOCKER-SZB-SDI-001 na TEMREXLOCKERBOX runs Modbus TCP locker driver since v0.78, hardened through v0.83. Dziś ta sama maszyna obsługiwana jest przez agenta SmartConf (127.0.0.1:8800), nie przez bezpośredni Modbus. Sterownik ModbusLockerHardware pozostaje w drzewie jako martwy/dev-only.

Hardware

  • Locker rig: TEMREXLOCKERBOX with Modbus TCP latch controller on 172.31.0.201.
  • Driver: lib/hardware/modbus_locker_hardware.dart. Implements the same LockerHardware interface as the mock — pulses the lock coil for ~300 ms to release, then polls the door-contact register at ~5 Hz to emit LockerEvent.opened and LockerEvent.closed.
  • App wiring: app.dart constructs ModbusLockerHardware in production builds (config-driven; mock kept available for dev / CI).

Lifecycle bugs that landed in v0.78v0.83

Numbered by the version that fixed them:

  • v0.78 — first Modbus build wired into the production kiosk; replaces MockLockerHardware end-to-end.
  • v0.79"kliknąłem otwórz ponownie a była otwarta skrytka": LockerOpenScreen would deadlock if the user re-tapped "Otwórz ponownie" while the cell was already open. Fix: open() is now idempotent on an already-released latch (no-op + immediate opened event).
  • v0.80 — broken contact sensor flicker would emit a phantom closed event mid-pickup. Fix: debounce on the sensor poll — close needs two consecutive sampled-closed reads.
  • v0.81"chcę nadać przesyłkę, skrytka 10 wolna": an orphaned ASSIGNED shipment could grab a locker that had been physically reused. Fix: /deposit/begin-existing now refuses if the existing reservation points to a different machine, and the kiosk reconciles its cached_lockers view against availableFunctions from /machines/me.
  • v0.82 — UX hardening drop:
  • Bigger touch targets on Wyloguj / Anuluj / Cofnij (footer buttons).
  • PIN buffer is wiped on auth failure (was previously left intact, leading to silent re-attempts on top of stale digits).
  • Pickup is gated when the locker isn't reporting closed — refuses to send confirm-pickup until the latch sensor agrees.
  • Deposit is gated when the cell hasn't returned to closed since the previous transaction.
  • v0.83"poszło w otwartą skrzynkę nie wykrył otwartej skrytki i jest w pętli": a deposit could go into an already-open cell because the isClosed check was racing the latch open/close cycle. Fix: LockerOpenScreen blocks Nadaj if the cell is reporting open, and the deposit flow polls isClosed() before flipping to the success screen.

All of the above are persisted in Machine.currentVersion after the OTA agent installs the corresponding release.

Operational notes

Nieaktualne od etapu 9

Poniższe wskazówki dotyczą martwej drogi Modbus. Dziś: kiosk → agent SmartConf (127.0.0.1:8800); gdy agent nie odpowiada, maszyna wchodzi w auto-maintenance, a log /v1 widać w panelu (MachineApiLog).

  • The Modbus driver shares the kiosk's network with the backend — check the kiosk's externalIp in Machine and confirm it can reach the latch controller before reporting "kiosk hangs".
  • A latch that won't acknowledge will leave the locker in RESERVED until ShipmentWorker.shipment.auto-expire frees it on expiresAt. To free it sooner, use the panel's emergency-open (POST /machines/:id/lockers/:lockerId/emergency-open) — that spawns an OPEN_LOCKER task and the kiosk drives the cell open.
  • The MockLockerHardware is still in the tree for dev — toggle by env var or by editing app.dart. CI uses the mock; production never does.

What's next

Etap 5 closes out kiosk hardware. Etap 7 (multi-machine sync…) and etap 8 (real notifications, OIDC code-flow, Gitea Actions, monitoring) remain.

Co faktycznie weszło później

Mapa etapów rozwinęła się inaczej niż zakładał ten akapit. Sprzęt został w całości przeprojektowany na agenta SmartConf (etap 9), DynaBox bęben (etapy 8/12), Job API (etapy 16/17), funkcje skrytek (etap 19) i Kiosk Helper (etapy 11/22). Aktualna mapa → roadmapa.