OTA-Update per MQTT

Neues Kommando <PREFIX>/cmd/ota loest ota.update() aus: laedt die
Projektdateien per HTTP, erst als temporaere .ota-Dateien, und benennt
sie nur bei vollem Erfolg um. Schlaegt ein Download fehl, bleiben die
bisherigen Dateien unveraendert -- die Anzeige laeuft mit der alten
Version weiter (Grundsatz wie beim Rest von MQTT: eine fehlgeschlagene
OTA darf das Geraet nicht unbrauchbar machen).

Am Gerät bestätigt, inkl. echtem Reboot: leere/ungueltige Payload,
unbekanntes Kommando und nicht erreichbarer Server werden abgefangen,
die Poll-Schleife laeuft unbeeinflusst weiter. Ein echtes Update mit
allen Projektdateien kam sauber ueber main.py-Autostart wieder hoch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zTSXLK4w32PoCmFgSzp68
This commit is contained in:
2026-09-04 17:34:58 +02:00
parent 72da766af0
commit 0e4bb025ef
9 changed files with 534 additions and 9 deletions
+46 -2
View File
@@ -66,6 +66,7 @@ beiden Startprogrammen.
| `lx200.py` | LX200-Kommandorahmen. | ✓ |
| `wifi.py` | WLAN-Anbindung des ESP32 (verbinden, Verbindung halten). | ✓ |
| `mqtt.py` | MQTT: Einstellungen empfangen, Zustand veröffentlichen. | ✓ |
| `ota.py` | OTA-Update: Dateien per HTTP laden, umbenennen, neu starten. | ✓ |
| `run_esp32.py` | Startprogramm auf dem ESP32: WLAN, Anzeige, Schleife. | ✓ |
| `main.py` | Autostart nach jedem Reset, mit Watchdog und Abbruchfenster. | ✓ |
| `wifi_config.py` | WLAN-Zugangsdaten, **nicht im Git** (Vorlage `wifi_config_example.py`). | ✓ |
@@ -548,9 +549,10 @@ Empfangen (`<PREFIX>/set/<name>`):
| `grossanzeige/set/schwelle` | `1800` | Umschaltpunkt (LDR-Wert) |
| `grossanzeige/set/hysterese` | `150` | Breite um den Umschaltpunkt |
| `grossanzeige/set/mount_host` | `192.168.1.115` | Adresse der Montierung (leer = Vorgabe aus `config.py`) |
| `grossanzeige/cmd/ota` | `http://192.168.178.50:8000` | löst ein OTA-Update aus (leer = Vorgabe aus `config.OTA_URL`, siehe [OTA-Update per MQTT](#ota-update-per-mqtt)) |
Alle Nutzlasten außer `mount_host` sind ganze Zahlen; `mount_host` ist Text
(IP-Adresse oder Hostname).
Alle Nutzlasten außer `mount_host` und `cmd/ota` sind ganze Zahlen; `mount_host`
und `cmd/ota` sind Text (Adresse bzw. URL).
Gesendet (`<PREFIX>/status/<name>`, alle *retained*):
@@ -618,6 +620,48 @@ Der Wert geht in `socket.getaddrinfo` und kommt von außen, deshalb prüft
`settings.py` ihn eng: nur Buchstaben, Ziffern, Punkt und Bindestrich, höchstens
63 Zeichen. Alles andere wird verworfen, `settings.json` bleibt unberührt.
### OTA-Update per MQTT
Ein Update lässt sich anstoßen, ohne das Gerät anzustecken:
```bash
cd /pfad/zum/projekt
python3 -m http.server 8000 # einfacher Dateiserver, hier laufen lassen
mosquitto_pub -h <broker> -t grossanzeige/cmd/ota -m http://192.168.178.50:8000
```
Die Nachricht auf `<PREFIX>/cmd/ota` ist die Basis-URL des Dateiservers; eine
leere Nachricht verwendet stattdessen `config.OTA_URL` (dieselbe Regel wie bei
`set/mount_host` mit leerer Nachricht):
```bash
mosquitto_pub -h <broker> -t grossanzeige/cmd/ota -m '' # config.OTA_URL
```
`ota.py` lädt dieselben Dateien, die auch `deploy.sh` überträgt, jede zunächst
unter einem temporären Namen (`<datei>.ota`). **Erst wenn alle Downloads
gelingen**, werden sie auf die endgültigen Namen umbenannt und das Gerät
startet neu (`machine.reset()`) — genau wie ein normaler Reset läuft danach
`main.py` mit Abbruchfenster und Watchdog an. Schlägt ein einzelner Download
fehl (Netz weg, Server nicht erreichbar, Datei fehlt), bleiben die bisherigen
Dateien unverändert liegen, die temporären Reste werden aufgeräumt, und die
Anzeige läuft mit der alten Version unbeeinflusst weiter — dieselbe
Fehlerphilosophie wie beim Rest von MQTT.
Der Watchdog wird während des Updates weiter gefüttert (`run_esp32.make_on_ota`
reicht den `feed` aus `main.py` durch), damit ein Update über viele Dateien
nicht selbst einen Neustart auslöst.
`settings.json`, `wifi_config.py` und `mqtt_config.py` werden **nicht**
angefasst — Laufzeitzustand bzw. Zugangsdaten, dieselbe Ausnahme wie in
`deploy.sh`.
**Sicherheitshinweis:** Der Dateiserver liefert unverändert aus, was unter der
angegebenen URL liegt — wer die MQTT-Nachricht schicken kann, bestimmt damit,
welcher Code auf dem Gerät läuft. Das ist im Rahmen des bestehenden
Vertrauensmodells (MQTT-Zugangsdaten in `mqtt_config.py`) beabsichtigt, aber
kein Ersatz für einen abgesicherten Broker.
### Was dabei schiefgehen kann, und warum es nichts ausmacht
**Grundsatz: MQTT darf die Anzeige nie aufhalten.** Die Anzeige ist der Zweck des