feat(station): E-Paper-Anzeige fuer Modus, Lampe und Auslieferungen
render.lines() zerlegt den zusammengefuehrten Zustand (status.json + control.json + SSID aus der Konfigurationsdatei) in Textzeilen, ohne Pillow und ohne Hardware zu brauchen - render.compose() importiert Pillow erst innerhalb der Funktion. epdconfig.py ist eine eigene GPIO/SPI-Schicht auf gpiozero/spidev, weil RPi.GPIO auf Debian 13 mit Python 3.13 nicht mehr traegt; epd2in13_V2.py/epd2in13_V3.py sind unveraendert aus dem Waveshare-Repository uebernommen (siehe HERKUNFT.md), nur der epdconfig-Import zeigt auf unser Modul. display.py laeuft als eigener systemd-Dienst (Wants=, Restart=on-failure), fehlendes Panel/SPI/Bibliothek beendet ihn sauber mit sys.exit(0) statt einer Neustartschleife - eine Migration darf davon nie abhaengen. Verdrahtung in setup_pi.sh/deploy.sh/ninlight-station folgt in einem eigenen Durchgang.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "display"))
|
||||
|
||||
import render # noqa: E402
|
||||
|
||||
|
||||
def test_off_mode_says_so_and_shows_nothing_else():
|
||||
lines = render.lines({"mode": "off"})
|
||||
assert any("Station aus" in l for l in lines)
|
||||
assert not any("SSID" in l for l in lines)
|
||||
|
||||
|
||||
def test_migration_shows_detected_lamp():
|
||||
lines = render.lines({
|
||||
"mode": "migration", "phase": "auto", "served": 3,
|
||||
"ssid": "qconnex-firmware",
|
||||
"last_seen": {"product_name": "Klyqa GU10 RGB CW/WW", "target": "gu10_rgb",
|
||||
"variant": "prod", "lamp_version": "V1.1.0.1138"},
|
||||
"recent": [{"target": "gu10_rgb", "status": "ok", "ts": "2026-09-13T13:04:02Z"}]})
|
||||
text = "\n".join(lines)
|
||||
assert "MIGRATION" in text
|
||||
assert "Klyqa GU10 RGB CW/WW" in text
|
||||
assert "V1.1.0.1138" in text
|
||||
assert "prod" in text
|
||||
assert "13:04" in text
|
||||
|
||||
|
||||
def test_recovery_mode_without_traffic():
|
||||
lines = render.lines({"mode": "recovery", "ssid": "ninlight-recovery",
|
||||
"served": 0, "recent": []})
|
||||
text = "\n".join(lines)
|
||||
assert "RETTUNG" in text
|
||||
assert "ninlight-recovery" in text
|
||||
|
||||
|
||||
def test_long_product_name_is_truncated_not_wrapped():
|
||||
"""Das Panel ist 250 px breit - eine zu lange Zeile darf das Layout nicht sprengen."""
|
||||
lines = render.lines({"mode": "migration", "phase": "listen", "served": 0, "recent": [],
|
||||
"ssid": "qconnex-firmware",
|
||||
"last_seen": {"product_name": "X" * 90, "target": "e27_rgb",
|
||||
"variant": "dev", "lamp_version": "V1"}})
|
||||
assert all(len(l) <= render.MAX_COLS for l in lines)
|
||||
|
||||
|
||||
def test_missing_fields_do_not_raise():
|
||||
"""status.json kann jederzeit halb geschrieben oder aus einer aelteren Version sein."""
|
||||
for state in ({}, {"mode": "migration"}, {"mode": "migration", "last_seen": {}}):
|
||||
assert render.lines(state)
|
||||
|
||||
|
||||
def test_armed_phase_is_visible():
|
||||
lines = render.lines({"mode": "migration", "phase": "armed", "armed_target": "g95_cw",
|
||||
"served": 0, "recent": [], "ssid": "qconnex-firmware"})
|
||||
assert "FREIGEGEBEN" in "\n".join(lines)
|
||||
Reference in New Issue
Block a user