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
+28 -1
View File
@@ -156,6 +156,31 @@ def make_on_change(display, client, dimmer=None, log=None):
return uebernehmen
def make_on_ota(feed=None, log=None):
"""Rueckruf fuer mqtt.MqttBridge: OTA-Update anstossen (cmd/ota).
Die Payload ist die Basis-URL des Dateiservers, z.B.
"http://192.168.178.50:8000". Bei leerer Nachricht gilt config.OTA_URL --
so laesst sich per MQTT auch ohne Payload eine feste Vorgabe anstossen,
genau wie set/mount_host mit leerer Nachricht auf config.MOUNT_HOST
zurueckfaellt.
Eigene Funktion statt Verschachtelung in main(), aus demselben Grund wie
make_on_change: Tests pruefen genau diese Logik.
"""
log = log or (lambda *a: None)
def ausloesen(payload):
import ota
url = payload or getattr(config, "OTA_URL", "")
if not url:
log("OTA: keine URL angegeben und config.OTA_URL nicht gesetzt")
return
ota.update(url, feed=feed, log=log)
return ausloesen
def main(host=None, port=None, with_ldr=False, fake_display=False,
once=False, with_mqtt=True, feed=None, log=print):
"""WLAN aufbauen, Anzeige oeffnen und die Poll-Schleife fahren.
@@ -205,7 +230,9 @@ def main(host=None, port=None, with_ldr=False, fake_display=False,
if with_mqtt:
import mqtt
bridge = mqtt.connect_from_config(
log=log, on_change=make_on_change(d, client, dimmer, log=log))
log=log,
on_change=make_on_change(d, client, dimmer, log=log),
on_ota=make_on_ota(feed=feed, log=log))
displayloop.poll_loop(d, client,
once=once,