sases d97d139d52 Pasek statusu ukryty przez CSS (nakładał się na dane ALS w iframe)
Ukrycie WYŁĄCZNIE przez display:none — element zostaje w DOM. Usunięcie go
z HTML to dokładnie ten błąd, który w starej wersji ubijał reconnect
(TypeError w onclose; README, Historia). refreshStatus() i tak ma osłonę na
brak elementu, ale osłona jest siatką bezpieczeństwa, nie zaproszeniem.
Do diagnostyki: jedna linia CSS albo style.display="block" w konsoli.

Pomarańczowy pasek offline zostaje bez zmian — pojawia się tylko przy utracie
łączności, czyli dokładnie wtedy, gdy MA przykryć nieaktualne dane.

10/10 testów przechodzi (testy sprawdzają logikę i klasy, nie widoczność
paska, więc ukrycie ich nie dotyka).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 08:09:12 +02:00

ALS Alert Screen

Jednostronicowa aplikacja HTML/JS wyświetlająca alarmy maszyn na podstawie danych WebSocket z LuPort. Przeznaczona do montażu na monitorze halowym (Chromium na Debianie).


Działanie

Strona utrzymuje jedno połączenie WebSocket ze zbiorczym kanałem ALS nowego systemu (/ws/als-data/ bez maszyny w adresie) — kanał niesie aktualizacje wszystkich maszyn, a zaraz po połączeniu serwer wysyła migawkę ich bieżącego stanu, więc trwający alarm pojawia się na ekranie natychmiast, także po każdym wznowieniu połączenia.

Sytuacja Widok
Brak maszyny w alarmie Iframe z infoterminalem ALS
Co najmniej jedna maszyna w alarmie Ekran alarmowy z kartami maszyn
Brak łączności z LuPort > 10 s Pomarańczowy pasek u góry (na obu widokach)

Alarm jest wykrywany, gdy pole status maszyny zawiera słowo alarm (bez rozróżnienia wielkości liter), np. "Alarm - awaria", "ALARM".

Pomarańczowy pasek to celowo INNY kolor niż czerwień alarmów: mówi „ekran może pokazywać nieświeży obraz", a nie „maszyna stoi".


Konfiguracja

Wszystkie parametry na początku sekcji <script> w als_alert_screen.html:

Stała Znaczenie
WS_URL adres kanału zbiorczego, np. ws://luport.local/ws/als-data/
WS_TOKEN token konta ApiUser (patrz niżej)
MACHINES filtr maszyn pokazywanych na ekranie; [] = wszystkie
WATCHDOG_SILENCE_MS po jakiej ciszy uznać połączenie za martwe (90 s)
STALE_MS po jakim czasie dane maszyny znikają z ekranu (5 min)
OFFLINE_BANNER_AFTER_MS po jakim czasie bez łączności pokazać pasek (10 s)

Oba kluczowe parametry można też nadpisać w adresie strony — wygodne przy konfiguracji kiosku bez edycji pliku:

als_alert_screen.html?ws=ws%3A%2F%2Fluport.local%2Fws%2Fals-data%2F&token=...

Token (wymagany przez nowy system)

Nowy LuPort wymaga uwierzytelnienia WebSocket. Utwórz dedykowane konto: Django Admin → Users → Api users → dodaj bot-als-alert-screen bez żadnych uprawnień (sam odbiór strumienia ALS ich nie wymaga — konto ma minimalny możliwy dostęp). Wygenerowany token wpisz w WS_TOKEN.

Format wiadomości

Strona obsługuje dwa typy ramek — obydwa tak samo (liczy się najnowszy stan):

  • machine_data — migawka wysyłana przez serwer zaraz po połączeniu,
  • machine_update — aktualizacje na żywo.
{
  "type": "machine_update",
  "machine": "2.60",
  "data": { "status": "Automatyczny", "orders": ["202605350"], "progress": 25, "...": "..." },
  "timestamp": "2026-07-31T12:00:32"
}

Odporność na awarie — dlaczego cron-restart nie jest już potrzebny

  1. Reconnect z wykładniczym odstępem i jitterem (1 s → 30 s). Odstęp wraca do minimum dopiero po 60 s stabilnego połączenia — serwer, który przyjmuje i zaraz zrywa (np. zły token), nie jest młócony co sekundę.
  2. Watchdog martwego połączenia. Przeglądarka nie wystawia ping/pong do JS, więc połączenie zabite bez zamknięcia TCP potrafi wisieć „otwarte" w nieskończoność. Na kanale zbiorczym dane płyną praktycznie ciągle (35 maszyn × cykl scrapera 30 s) — cisza dłuższa niż 90 s oznacza martwe połączenie i wymusza reconnect.
  3. Wygasanie danych. Dane maszyny starsze niż 5 min znikają z ekranu — alarm maszyny usuniętej z widgetu ALS nie wisi w nieskończoność.
  4. Widoczna utrata łączności. Pasek offline + pasek statusu w rogu. Ekran nigdy nie pokazuje po cichu nieświeżego obrazu.

Historia: dlaczego alarmy „przestawały wyskakiwać" (do 2026-07-31)

Poprzednia wersja utrzymywała 35 osobnych połączeń (po jednym na maszynę) i miała błąd, który ujawnił się po ukryciu paska statusu: element #status-bar został zakomentowany w HTML, ale refreshStatus() nadal po niego sięgał. TypeError na null przerywał handler ws.onclose przed zaplanowaniem reconnectu — każda maszyna po pierwszym zerwaniu połączenia milkła na zawsze. Maszyny odpadały jedna po drugiej przy każdym czknięciu sieci, a restart z crona co 2 h maskował problem, zaczynając od zera.

Wnioski utrwalone w obecnym kodzie:

  • element statusu musi istnieć w DOM (ukrywanie wyłącznie przez CSS), a refreshStatus() i tak ma osłonę na jego brak,
  • brak ws.onerror jest celowy — po błędzie przeglądarka i tak wywołuje onclose, a osobny handler był tylko drugim miejscem, z którego dało się rzucić wyjątkiem,
  • scenariusz 6 w testach (test/testy_ekranu.py) jest bezpośrednim testem regresji tego błędu.

Poprawki robione na kiosku w czerwcu (timery świeżości per-maszyna, ubijanie „zombie" połączeń, jitter reconnectu) szły w dobrą stronę, ale nieświadomie POGORSZYŁY objaw: watchdog celowo zamykał ciche połączenie, a każde zamknięcie przechodziło przez ten sam wadliwy onclose — czyli własna obrona uśmiercała maszynę na stałe. Ich sedno (wykrywanie ciszy, jitter) jest zachowane w obecnej wersji; nakładkowy iframe („iframe optimalization") również. Zrezygnowano z czyszczenia danych przy rozłączeniu: alarm nie znika przy 3-sekundowym czknięciu sieci — o niepewności informuje pomarańczowy pasek, a migawka po reconnexie przywraca prawdę.

Cron restartujący przeglądarkę co 2 h można usunąć.


Testy

python3 test/testy_ekranu.py
# lub na kiosku:
CHROME_BIN=/usr/bin/chromium python3 test/testy_ekranu.py

Deterministyczne, bez sieci: skrypt aplikacji jest wycinany z żywego als_alert_screen.html, window.WebSocket podmieniany na fałszywkę, a scenariusz (10 asercji: migawka, aktualizacje, reconnect, baner offline, watchdog, wygasanie danych) jedzie na wirtualnym czasie Chromium — całość trwa kilka sekund mimo symulowania ~6 minut.


Tryb debug

Podgląd ekranu alarmowego bez danych i bez połączeń WS:

als_alert_screen.html?debug

albo w konsoli przeglądarki: DEBUG_ALARM = true; updateDisplay(); (powrót: DEBUG_ALARM = false; updateDisplay();).


Wymagania

  • Chromium/Chrome 105+ (CSS Container Queries, min()) — kiosk działa na Chromium pod Debianem.
  • Dostęp sieciowy do LuPort (WebSocket) oraz infoterminala ALS (iframe).
S
Description
Ekran informujący o alarmach na maszynach wyświetlany na ekranie informacyjnym produkcji.
Readme 128 KiB
Languages
HTML 69.9%
Python 30.1%