Przejdź do treści

Komunikacja kiosk ↔ sprzęt: z bezpośredniej (Modbus) na API agenta SmartConf

TL;DR

Kiosk nie rozmawia już bezpośrednio ze sterownikiem zamków (Modbus TCP). Całe sterowanie sprzętem idzie teraz przez lokalnego agenta SmartConf po HTTP na 127.0.0.1:8800 (/v1/...). Modbus pozostał w kodzie jako sterownik dev/awaryjny, ale w produkcji jest martwy (etap-20 usunął nawet adres Modbus skrytek). To kluczowa zmiana architektury z etapów 8–9, dokończona w 16–20.

Dlaczego zmiana

Bezpośredni Modbus z kiosku miał wady: - Współbieżność i sekwencje DynaBoxa (obrót bębna, re-rygiel, prezentacja kolumny) wymagały złożonej logiki w kiosku, podatnej na wyścigi. - Brak jednego miejsca na telemetrię, discovery, diagnostykę i wersję firmware sterownika. - Trudny serwis zdalny i podgląd, co maszyna faktycznie robi z zamkami.

Agent SmartConf (osobny proces na maszynie, C#) bierze to na siebie: zna sprzęt (LockerBox/DynaBox), zarządza cyklem otwarcia, kolejką, timeoutami i re-ryglem, a kioskowi wystawia proste, idempotentne API HTTP.

Przed → po

flowchart LR
    subgraph PRZED["PRZED — bezpośrednio"]
        K1[Kiosk Flutter] -- Modbus TCP :502 --> C1[Sterownik zamków]
    end
    subgraph PO["PO — przez agenta"]
        K2[Kiosk Flutter] -- HTTP /v1 127.0.0.1:8800 --> A[Agent SmartConf]
        A -- sterowanie sprzętem --> C2[Sterownik zamków]
        A -- telemetria/zgłoszenia --> Cloud[(Backend SmartBox)]
    end

Powierzchnia API agenta (/v1, na 127.0.0.1:8800)

Nagłówki: X-Api-Key (klucz agenta), X-Client-Name / X-Client-Version (tożsamość kiosku).

Wywołanie Po co
GET /v1/machine typ maszyny (DynaBox / LockerBox)
GET /v1/compartments geometria bębna + rozmiary komórek (DynaBox)
GET /v1/status ostatni znany stan drzwi (cache)
GET /v1/events?after=<seq> strumień zdarzeń sprzętu (sekwencyjny)
POST /v1/doors/{N}/open pojedyncze otwarcie wirtualnej skrytki N (wydawanie/odbiór)
POST /v1/jobs/open {doors[]} masowe otwarcie (uzupełnianie/inwentaryzacja) — etap-16
GET /v1/jobs[/{id}] poll stanu joba (queued→opening→unlocked→open→done/failed/timeout)
POST /v1/jobs/{id}/cancel anulowanie kolejki (queued → skipped)
POST /v1/master/clear kasowanie alarmów mastera

Dwie ścieżki otwierania

  1. Pojedyncza skrytka (locker_open_screen / JobOpenScreen, etap-17) — wydawanie i odbiór, zawsze 1 naraz; DynaBox po otwarciu re-rygluje (close(N)).
  2. Masowa (Job API, etap-16) — uzupełnianie + inwentaryzacja; agent zarządza współbieżnością (≤3 dla LockerBox, 1 dla DynaBox), kolejką, cyklem i timeoutami; kiosk tylko pollu je i renderuje stan per skrytka.

Pre-check przed otwarciem (lockerOpenPreCheck)

NIE czytaj drzwi jako bramki przed otwarciem na SmartConf (DynaBox)

Na DynaBoxie wirtualna komórka z niezaprezentowanej kolumny czyta złe drzwi fizyczne → fałszywe „skrytka otwarta", blokujące nadanie i odbiór. Dlatego wspólny lockerOpenPreCheck(hardware, N):

  • SmartConf (DynaBox + LockerBox) = NO-OP — pre-flight agenta wewnątrz POST /v1/jobs/open jest świadomy zaprezentowanej kolumny i sam bramkuje gotowość.
  • mock / dev / Modbus — zachowują bramkę isClosed(N).

Każda przyszła operacja otwierająca skrytkę MUSI korzystać z tej wspólnej metody (flutter-machine-ui/lib/hardware/locker_open_precheck.dart). Audyt 5 operacji (nadanie/odbiór/wydanie/uzupełnienie/inwentaryzacja) = czysty.

Tryb serwisowy i discovery

  • Maszyna po rejestracji startuje w maintenanceMode=true → kiosk pokazuje Service Mode, póki admin nie połączy SmartConf.
  • Discovery: kiosk skanuje localhost + podsieci /24 swoich kart sieciowych (zadanie DISCOVER_SMARTCONF); kandydaci lądują w panelu.
  • Połączenie: admin ustawia URL agenta + opcjonalny klucz (PATCH /machines/:id/smartconf); kiosk czyta to z /machines/me i rekonfiguruje sterownik na żywo (SmartConfHardware.applyConfig) — bez restartu.
  • Auto-maintenance: gdy agent staje się nieosiągalny, backend (worker) parkuje maszynę w trybie serwisowym (maintenanceAuto=true) i zdejmuje po odzyskaniu — ale tylko jeśli park był automatyczny.

Audyt /v1 (etap-14)

Każde wywołanie /v1 jest logowane w kiosku (ring-buffer) i relayowane do backendu → panel maszyny → „Log API /v1" (mutacje zawsze, idle-polle próbkowane, w oknie capture wszystko). Retencja 7 dni (MachineApiLog). Bezcenne przy diagnostyce „co maszyna zrobiła z zamkami".

Status drogi Modbus

Modbus (bezpośrednio) SmartConf (agent)
LockerBox sterownik w repo (modbus_locker_hardware.dart), nieaktywny aktywny
DynaBox nigdy nie był drogą produkcyjną aktywny
Adres Modbus skrytki usunięty z DB/schema (etap-20)
Kiedy używany tylko mock/dev/ewentualny fallback produkcja

Plik abstrakcji: flutter-machine-ui/lib/hardware/locker_hardware.dart (interfejs open/openMany/events/isClosed), implementacje: modbus_locker_hardware.dart (martwy) i smartconf_hardware.dart (aktywny).

Powiązane

  • Roadmapa etapów — etapy 8, 9, 14, 16, 17, 19, 20
  • Kiosk Helper — Helper nie zarządza zamkami (to robi SmartConf); nadzoruje proces kiosku, RFID i OTA