Files
ninlight-w600/tools/station
Michael Sauer cc398ef57a feat(station): Anzeige ausliefern, Migrationsprofil, display-Befehle
Schritt 8 des Plans: die fertige E-Paper-Anzeige wird endlich ausgeliefert
und verdrahtet, dazu zwei liegengebliebene Dinge.

- deploy.sh/setup_pi.sh uebertragen display/ (mit Panel-Treibern und
  HERKUNFT.md) und ninlight-display.service; setup_pi.sh installiert und
  aktiviert die Unit und zieht python3-pil nach - ohne Pillow beendet sich
  der Anzeigedienst still mit 0, das faellt sonst nirgends auf.
- setup_pi.sh legt auch das Profil fuer den Migrations-Zugangspunkt an
  (qconnex-firmware, von der alten Klyqa-Firmware fest vorgegeben, gleiche
  Adresse wie das Rettungsprofil). Ohne das scheiterte "migrate on" auf
  einem frisch eingerichteten Pi an need_profile. Bestehende Profile
  bleiben unangetastet.
- "ninlight-station display test|clear|off"; der Hilfetext erklaert die
  Revisionsbestimmung, denn EPD_REVISION laesst sich nur am Testbild
  bestimmen.
- "off" nimmt die Anzeige mit: erst Dienst stoppen, dann Panel leeren
  (sonst schreibt der Daemon binnen 5 s sein altes Bild zurueck) und beides
  vor ap_switch, das bei haengendem NetworkManager abbricht. Ein
  stehengebliebenes "MIGRATION" wuerde einen Betriebszustand behaupten, den
  es nicht mehr gibt.
- test_host.sh sammelt tools/mkimage als Ganzes ein: die 19 Tests in
  test_nl_mkimage.py liefen in keiner Suite mehr mit, darunter die Wache
  fuer die Python-3.8-Randbedingung des Build-Containers. Ein neuer Test
  haelt die Regel fest, dass keine Testdatei mehr herausfallen kann.
- Nebenbei: die Temp-Datei mit dem WLAN-Passwort wird wieder zuverlaessig
  aufgeraeumt, und leere Konfigurationswerte legen kein kaputtes Profil an.
2026-09-13 23:19:14 +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 off         ausschalten

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.