docs: OTA und Recovery dokumentieren

This commit is contained in:
Michael Sauer
2026-09-12 02:45:27 +02:00
parent 247d610fe8
commit 682235f3ab
3 changed files with 79 additions and 1 deletions
+60
View File
@@ -71,6 +71,66 @@ Verfügbare Befehle in der Konsole: `help`.
- Bruno: `bruno/ninlight.yml` importieren, Environment „EVK (mDNS)" bzw. „Onboarding-AP" wählen.
- Konsole: `net` zeigt Modus, SSID, IP, RSSI und den letzten Onboarding-Fehler.
## Firmware-Update
Der Build erzeugt pro Gerät zwei Images:
- **`_gz.img`** — komprimiertes App-Image für das serielle Flashen mit `tools/flash.sh` (siehe oben).
- **`_ota.img`** — dasselbe `_gz.img`, um einen 512-Byte-Trailer ergänzt (`tools/mkimage/nl_mkimage.py`,
automatisch bei jedem Build via `cmake/run_mkimage.cmake`). Der Trailer enthält Gerätetyp, Firmware-Version
und den SHA256 über das komplette `_gz.img` — das ist genau der Hash, den die Firmware beim Schreiben ins
Flash prüft.
Netz-Update über die REST-API:
curl -X PUT http://ninlight-681f.local:3333/api/v1/system/command \
-H 'Authorization: aabbccddeeff0011223344' \
-d '{"command":{"type":"fw_update","url":"http://<host-ip>:8000/pfad/zur/ninlight_evk_ota.img"}}'
Antwort `202 {"status":"updating"}` startet den Download im Hintergrund; ein per HTTP-Server bereitgestelltes
`_ota.img` reicht (z.B. `python3 -m http.server 8000`). Läuft der Trailer- bzw. Hash-Check durch, resettet die
Lampe und bootet mit der neuen Version. Wird das Image abgelehnt, gibt es **keinen** Reset — die Lampe läuft
mit der alten Firmware weiter und trägt den Grund in `last_ota_error` (`GET system/info`) ein. Ein
Verbindungsabbruch mitten im Download löst dagegen einen Wiederaufnahmeversuch per HTTP-Range aus (begrenzte
Anzahl Runden); erst wenn auch das ausgeht, landet der Versuch bei `last_ota_error = download`.
Werte von `last_ota_error` (`null`, solange nichts fehlgeschlagen ist):
| Wert | Bedeutung |
|---|---|
| `download` | Verbindung/Transfer gescheitert (auch nach ausgeschöpftem Wiederaufnahmeversuch) |
| `crc` | Prüfsumme des SDK-eigenen Update-Mechanismus stimmt nicht |
| `trailer` | Trailer fehlt, ist zu kurz oder hat eine falsche Magic/Version |
| `device_mismatch` | Trailer nennt einen anderen Gerätetyp |
| `hash` | SHA256 im Trailer stimmt nicht mit dem übertragenen Image überein |
| `busy` | es läuft bereits ein Update, oder die übergebene URL war ungültig |
Ein erneuter `fw_update`-Aufruf mit einem gültigen Image funktioniert nach einer Ablehnung sofort, ohne
manuellen Reboot.
## Recovery
Findet die Firmware beim Booten keinen Weg, sich selbst zu aktualisieren (z.B. weil das reguläre WLAN nicht
erreichbar ist), sucht sie kurz nach einem Rettungs-Zugangspunkt: SSID/Passwort sind Build-Parameter
(`NINLIGHT_RECOVERY_SSID`/`NINLIGHT_RECOVERY_PASSWORD` in `config.local.cmake`, Default für beide
`ninlight-recovery`). Wird die Station gefunden, verbindet sich die Lampe und lädt
`http://192.168.8.1/ninlight_<device>_ota.img` (z.B. `ninlight_evk_ota.img`) — der Dateiname enthält den
Gerätetyp, `<device>` ist der Wert von `NINLIGHT_DEVICE` aus dem Build.
Bei jedem Boot scannt die Firmware dafür bis zu ~3 Sekunden nach der Station und loggt das Ergebnis
(gefunden, nichts gefunden, oder Scan fehlgeschlagen). Ist keine Station in Reichweite, verlängert sich der
Boot nur um diese Scan-Zeit; danach startet der normale WLAN-Aufbau wie gewohnt. Über dem Download selbst
liegt eine harte Zeitobergrenze — läuft sie ab, wird der Watchdog nicht mehr bedient und der Chip startet neu,
statt unbeobachtet hängen zu bleiben; der nächste Boot versucht Recovery erneut.
**Vertrauensgrenze:** Der Trailer prüft Gerätetyp und SHA256 — das ist kein kryptografisches Signaturverfahren.
Der Download läuft über `http://` ohne TLS, und der Recovery-Kanal ist ausschließlich durch das oben genannte
WLAN-Passwort geschützt, das mit einem öffentlichen Default im Repo steht. Wer im selben WLAN ist und das
API-Token kennt (bzw. beim Recovery in Funkreichweite ist und das Passwort kennt), kann der Lampe beliebige
Firmware unterschieben. Das ist eine bewusste Entscheidung dieses Projekts: Ziel ist, die Signaturprüfung der
alten, abgekündigten Original-Firmware zu umgehen, damit die Lampen überhaupt weiter nutzbar bleiben — nicht,
ein neues, gehärtetes Sicherheitsmodell zu bauen.
## Werksreset
Gerät 5× hintereinander einschalten, jeweils kürzer als 5 Sekunden.