Files
ninlight-w600/tools/station
Michael Sauer 300edafc3e feat(station): Umschalter fuer Migrationsimages mit/ohne WLAN-Daten
Die WLAN-Zugangsdaten stecken zur Bauzeit in der Firmware, es gibt also
zwei Abzuege je Ziel. Die Station haelt jetzt beide vor - images/
migrate-nocreds (aus tools/build_nocreds.sh, Lampe startet im
Onboarding-AP) und images/migrate-wlan (aus build/, Lampe haengt sofort
im eigenen WLAN) - und der Bediener waehlt per Umschalter, welcher
ausgeliefert wird: "ninlight-station bildsatz" oder der Menueeintrag am
Taster.

Der Zustand liegt in /var/lib/ninlight-station/imageset, ueberlebt
Neustarts und steht dauerhaft in der Fusszeile des Panels - in jedem
Modus, auch bei ausgeschalteter Station: man soll vor dem Einschalten
sehen, was gilt.

Vorgabe und Rueckfallwert in JEDEM Zweifelsfall ist "ohne-wlan". Im
Automatikmodus wird jede Klyqa-Lampe in Reichweite migriert, auch
fremde; ein Abzug ohne Zugangsdaten ist dann ein harmloser Fehlgriff,
einer mit Zugangsdaten traegt das eigene WLAN-Passwort in ein fremdes
Geraet.

Fehlt der gewaehlte Satz (Verzeichnis weg oder leer), wird NICHTS
ausgeliefert - kein stilles Ausweichen auf den anderen Satz. Der Server
antwortet 404 mit Status "noimageset", CLI und Panel sagen "FEHLT".

server.py und die Stations-Unit muessen mit: die Auswahl der
ausgelieferten Datei ist genau die Aufgabe des Servers, und ein
Symlink-Tausch haette "gewaehlt, aber nicht vorhanden" von "dieses
Modell fehlt" nicht mehr unterscheidbar gemacht.
2026-09-15 02:17:36 +02:00
..

ninlight-Recovery-Station

Ein Raspberry Pi spannt den Zugangspunkt ninlight-recovery auf und liefert unter http://192.168.8.1/ninlight_<target>_ota.img Firmware-Images aus.

Jede ninlight-Lampe sucht beim Booten bis zu drei Sekunden nach dieser Station. Findet sie sie, lädt sie das Image für ihren Gerätetyp und flasht es — ohne dass die Lampe im WLAN erreichbar sein muss. Das ist der Rettungsweg für Lampen, an die man sonst nur noch mit dem Lötkolben käme.

Trägt das angebotene Image dieselbe Version, die bereits läuft, lehnt die Lampe es ab und bootet normal weiter. Eine angelassene Station flasht also nicht in einer Endlosschleife.

Voraussetzung

Der SSH-Benutzer auf dem Pi braucht passwortloses sudo — beide Skripte und die CLI (ninlight-station on|off|status) rufen sudo nicht-interaktiv auf; ein Passwort-Prompt würde dort nur mit einer Fehlermeldung enden.

Bedienung

tools/station/setup_pi.sh <pi-host>        einmalig einrichten
tools/station/deploy.sh <pi-host> [target] Images ausliefern
ssh <pi-host> ninlight-station on          einschalten
ssh <pi-host> ninlight-station status      Zustand und letzte Auslieferungen
ssh <pi-host> ninlight-station bildsatz    welcher Migrations-Bildsatz gilt
ssh <pi-host> ninlight-station off         ausschalten

Bildsatz: mit oder ohne WLAN-Zugangsdaten

Die WLAN-Zugangsdaten stecken zur Bauzeit in der Firmware (config.local.cmake). Es gibt deshalb zwei Abzüge je Ziel, und die Station hält beide vor:

Umschalterstellung Verzeichnis auf dem Pi gebaut mit die migrierte Lampe …
ohne-wlan (Vorgabe) images/migrate-nocreds/ tools/build_nocreds.sh startet im eigenen Onboarding-Zugangspunkt und wartet auf ein WLAN
mit-wlan images/migrate-wlan/ build/ hängt sofort im WLAN aus config.local.cmake

Umgeschaltet wird per ninlight-station bildsatz ohne-wlan|mit-wlan oder am Taster (Menüeintrag „Umschalten: …"). Das ist ein Umschalter, keine Abfrage je Migration: der Zustand steht in /var/lib/ninlight-station/imageset, überlebt Neustarts und bleibt, bis ihn jemand ändert. Genau deshalb steht er auch dauerhaft in der Fußzeile des Panels — in jedem Modus, auch bei ausgeschalteter Station: man soll vor jedem Einschalten sehen, was gilt, statt zwanzig Lampen mit den eigenen Zugangsdaten zu flashen, weil die Einstellung von vorletzter Woche noch stand.

Warum ohne-wlan die Vorgabe ist (und warum jeder Zweifelsfall — Datei fehlt, unlesbar, unbekannter Inhalt — dorthin führt): im Automatikmodus wird jede alte Klyqa-Lampe in Funkreichweite migriert, auch fremde. Mit dem Abzug ohne Zugangsdaten ist ein Fehlgriff ärgerlich, aber harmlos — die Lampe steht im Onboarding-AP und wartet. Mit dem Abzug mit Zugangsdaten steht das eigene WLAN-Passwort unwiderruflich in einem fremden Gerät. Der teurere Fehler darf nie der sein, der ohne Zutun passiert.

Fehlt der gewählte Satz (nie ausgeliefert, oder tools/build_nocreds.sh nie gelaufen), wird nichts ausgeliefert — kein stilles Ausweichen auf den anderen Satz. Der Server antwortet mit 404 und status: noimageset, ninlight-station status sagt „FEHLT", und auf dem Panel steht „SATZ FEHLT". „Vorhanden" heißt dabei überall dasselbe: Verzeichnis da und mindestens ein Image darin.

deploy.sh liefert beide Sätze aus. Fehlt build-nocreds/, bleibt der Satz ohne-wlan auf dem Pi unangetastet (statt geleert zu werden) und der Lauf meldet, womit er entsteht.

Taster am Gerät

Sobald die Station läuft, wird wlan0 zum Zugangspunkt und jede SSH-Sitzung reißt ab. Für genau diesen Zustand gibt es einen Taster auf GPIO23; die Rückmeldung kommt aufs E-Paper. Ein Taster, zwei Zusammenhänge:

kurz (unter 1 s) gehalten
Ruhe (Statusbild) Menü öffnen 3 s → Abbruch (Station aus), weiter 10 s → Herunterfahren
Menü offen nächster Eintrag 1,5 s → Eintrag auswählen
Rückfrage abbrechen 1,5 s → bestätigen

Der Abbruch feuert bei 3 s, nicht erst beim Loslassen — danach läuft auf dem Panel ein Countdown bis zum Herunterfahren, den Loslassen jederzeit abbricht. Das Menü schließt nach 20 s ohne Eingabe, eine Rückfrage verfällt nach 10 s als Abbruch. Die Einträge hängen vom Zustand ab (Station aus / Rettung läuft / Migration läuft); jede verändernde Auswahl bekommt eine Rückfrage.

Die beiden Migrationsarten sind getrennte Einträge. „Migration: horchen" (migrate on --listen) steht zuerst und ist der naheliegende: der Zugangspunkt steht, aber es geht nichts raus, bis du eine erkannte Lampe freigibst. „Migration: AUTOMATIK" (migrate on) folgt danach und bekommt eine andere, deutlichere Rückfrage — der Migrations-Zugangspunkt hat ein öffentlich bekanntes Passwort (es steht in der alten Klyqa-Firmware), und im Automatikmodus wird jede alte Klyqa-Lampe in Funkreichweite ungefragt migriert, auch fremde. Die Rückfrage benennt genau das, statt nur „Wirklich?" zu fragen.

Der Taster ist nirgends Voraussetzung: fehlt gpiozero oder der Taster, protokolliert der Dienst eine Zeile und beendet sich ohne Fehler. Er fasst den SPI-Bus nicht an (zwei Prozesse auf denselben Leitungen ergeben GPIO busy), sondern schreibt seinen Bedienzustand nach /run/ninlight-button/ui.json; der Anzeigedienst liest ihn und zeichnet. Ausgeführt wird ausschließlich über das CLI.

Dienst und Unit liegen in tools/station/button/ bzw. tools/station/ninlight-button.service. setup_pi.sh installiert, aktiviert und startet den Tasterdienst wie den Anzeigedienst; deploy.sh liefert button/ bei jedem Deploy mit aus. Ein fehlgeschlagenes Aktivieren/Starten ist dabei nur eine Warnung — eine Station ohne Taster muss vollständig benutzbar bleiben.

SSID und Passwort stehen in /etc/ninlight-station.conf auf dem Pi und müssen zu den Build-Parametern NINLIGHT_RECOVERY_SSID und NINLIGHT_RECOVERY_PASSWORD aus config.local.cmake passen. Weicht eines ab, findet die Lampe die Station nicht.

Vertrauensgrenze

Der Trailer eines Images prüft Gerätetyp und SHA256. Er ist keine kryptografische Signatur, und der Download läuft über http:// ohne TLS. Die Station schützt allein ein WPA2-Passwort, dessen Default im Repo steht. Wer in Funkreichweite ist und es kennt, kann jeder Lampe beim nächsten Boot beliebige Firmware unterschieben.

Das ist gewollt: Die Signaturprüfung der alten Firmware auszuhebeln ist der Zweck dieses Projekts. Daraus folgen zwei Regeln.

Setz ein eigenes Passwort. In config.local.cmake und in /etc/ninlight-station.conf — an beiden Stellen denselben Wert.

Lass die Station nur an, solange du sie brauchst. Nicht nur wegen des Fremdzugriffs: Die Firmware löscht den Power-Cycle-Zähler, bevor sie einen Recovery-Versuch startet. Solange eine Station in Reichweite ist, funktioniert der Werksreset per fünf Stromzyklen bei keiner Lampe in Reichweite mehr.