feat(station): Bedienung ueber einen Taster mit Panel-Rueckmeldung
Ein Taster auf GPIO23 (active low, 50 ms entprellt) bedient die Station am Geraet: kurz oeffnet das Menue bzw. blaettert, gehalten waehlt (1,5 s), bricht ab (3 s, feuert sofort) und faehrt herunter (10 s, nur ueber die sichtbare Abbruchstufe hinweg). Menue schliesst nach 20 s, Rueckfrage verfaellt nach 10 s als Abbruch; jede veraendernde Auswahl bekommt eine Rueckfrage. Noetig, weil "on"/"migrate on" wlan0 zum Zugangspunkt macht und damit jede SSH-Sitzung abreisst - bisher blieb dort nur warten oder Stecker ziehen. "Migration starten" startet ueber das Menue IMMER mit --listen: der Migrations-AP hat ein oeffentlich bekanntes Passwort, ein Tastendruck im Automatikmodus wuerde jede alte Klyqa-Lampe in Reichweite ungefragt migrieren. Der Tasterdienst fasst den SPI-Bus nicht an (sonst "GPIO busy"), sondern schreibt seinen Bedienzustand atomar mit 0644 nach /run/ninlight-button/ui.json - bewusst nicht ins RuntimeDirectory der Hauptunit, das systemd beim "off" aufraeumt. Der Anzeigedienst liest die Datei jede halbe Sekunde (der teure build_state()-Fork bleibt beim 5-Sekunden-Takt) und zeichnet sie als Teilaufbau, kostet dem Panel also keinen Vollaufbau je Tastendruck. Fehlt gpiozero oder der Taster, gibt es genau eine Protokollzeile und sys.exit(0) - dieselbe Zusage wie bei der Anzeige. Ausliefern/Einrichten folgt in einem eigenen Durchgang.
This commit is contained in:
@@ -186,6 +186,16 @@ def blocks(state: dict) -> list[tuple[str, str]]:
|
||||
Bild - die Rolle ist ein reiner Bezeichner, die zugehoerigen Schriftgroessen kennt
|
||||
ausschliesslich compose()."""
|
||||
state = state if isinstance(state, dict) else {}
|
||||
|
||||
# Laeuft gerade eine Bedienung am Taster, ERSETZT sie das Statusbild komplett - eine
|
||||
# Bedienung, die neben dem Statusbild um Platz kaempft, waere auf 250x122 unlesbar,
|
||||
# und in diesem Moment ist der Bedienzustand die einzige Auskunft, auf die der
|
||||
# Bediener wartet. display.read_ui() liefert {} (und damit kein "ui"), sobald nichts
|
||||
# laeuft - dann geht es unveraendert weiter wie zuvor.
|
||||
ui = state.get("ui")
|
||||
if isinstance(ui, dict) and ui.get("view") not in (None, "", "idle"):
|
||||
return _ui_blocks(ui)
|
||||
|
||||
mode = state.get("mode")
|
||||
out: list[tuple[str, str]] = []
|
||||
|
||||
@@ -311,6 +321,36 @@ def blocks(state: dict) -> list[tuple[str, str]]:
|
||||
return out
|
||||
|
||||
|
||||
def _ui_blocks(ui: dict) -> list[tuple[str, str]]:
|
||||
"""Der Bedienzustand des Tasterdienstes in Zeilen mit Rolle. Bewusst DUMM: welcher
|
||||
Text bei welcher Geste erscheint, entscheidet allein der Tasterdienst (dort ist es
|
||||
ohne Hardware pruefbar) - hier wird er nur noch den vorhandenen Rollen zugeordnet,
|
||||
damit Kopfbalken, Schriftgroessen, Breitenkuerzung und unterer Rand dieselben bleiben
|
||||
wie im Statusbild.
|
||||
|
||||
Jedes Feld wird auf seinen Typ geprueft: die Datei kommt aus einem anderen Prozess
|
||||
(der aelter, neuer oder halb geschrieben sein kann) - genau wie status.json darf sie
|
||||
die Anzeige nie zum Absturz bringen."""
|
||||
out: list[tuple[str, str]] = []
|
||||
title = ui.get("title")
|
||||
if isinstance(title, str) and title:
|
||||
out.append((title, ROLE_HEADER))
|
||||
hero = ui.get("hero")
|
||||
if isinstance(hero, str) and hero:
|
||||
out.append((hero, ROLE_HERO))
|
||||
details = ui.get("details")
|
||||
if isinstance(details, list):
|
||||
for detail in details:
|
||||
if isinstance(detail, str) and detail:
|
||||
out.append((detail, ROLE_DETAIL))
|
||||
if not out:
|
||||
# Es laeuft eine Bedienung, aber die Datei traegt keinen brauchbaren Text
|
||||
# (abgeschnitten, fremde Fassung). Lieber gross sagen, dass bedient wird, als
|
||||
# ein leeres Panel zu zeigen, das nach "haengt" aussieht.
|
||||
out.append(("Bedienung", ROLE_BIG))
|
||||
return out
|
||||
|
||||
|
||||
def lines(state: dict) -> list[str]:
|
||||
"""Nur die Texte aus blocks(), ohne Rollen - unveraenderte Schnittstelle fuer
|
||||
display.run_daemon(), das damit erkennt, ob sich der Inhalt geaendert hat (die Rolle
|
||||
|
||||
Reference in New Issue
Block a user