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:
@@ -6,6 +6,9 @@
|
||||
<PREFIX>/set/hysterese 150
|
||||
<PREFIX>/set/mount_host 192.168.1.115 Adresse der Montierung; leer =
|
||||
Vorgabe aus config.MOUNT_HOST
|
||||
<PREFIX>/cmd/ota http://192.168.1.50:8000 loest ota.update() aus; leere
|
||||
Nachricht = Vorgabe aus
|
||||
config.OTA_URL (siehe ota.py)
|
||||
|
||||
<PREFIX>/status/ra 18h36m56s ausgehend
|
||||
<PREFIX>/status/dec +38°47'01"
|
||||
@@ -58,7 +61,7 @@ class MqttBridge:
|
||||
|
||||
def __init__(self, broker=None, port=1883, user="", password="",
|
||||
prefix="grossanzeige", client_id="grossanzeige",
|
||||
client=None, log=None, on_change=None):
|
||||
client=None, log=None, on_change=None, on_ota=None):
|
||||
self._broker = broker
|
||||
self._port = port
|
||||
self._user = user
|
||||
@@ -68,6 +71,7 @@ class MqttBridge:
|
||||
self._client = client
|
||||
self._log = log or (lambda *a: None)
|
||||
self._on_change = on_change # wird nach jeder Aenderung gerufen
|
||||
self._on_ota = on_ota # wird bei cmd/ota gerufen (Payload = URL)
|
||||
|
||||
self.connected = False
|
||||
self._retry = RETRY_START
|
||||
@@ -78,6 +82,9 @@ class MqttBridge:
|
||||
def _set_topic(self, name=None):
|
||||
return "%s/set/%s" % (self._prefix, "+" if name is None else name)
|
||||
|
||||
def _cmd_topic(self, name=None):
|
||||
return "%s/cmd/%s" % (self._prefix, "+" if name is None else name)
|
||||
|
||||
def _status_topic(self, name):
|
||||
return "%s/status/%s" % (self._prefix, name)
|
||||
|
||||
@@ -106,6 +113,7 @@ class MqttBridge:
|
||||
retain=True)
|
||||
self._client.connect()
|
||||
self._client.subscribe(self._set_topic())
|
||||
self._client.subscribe(self._cmd_topic())
|
||||
self._client.publish(self._status_topic("online"), b"1", retain=True)
|
||||
self.connected = True
|
||||
self._retry = RETRY_START
|
||||
@@ -143,12 +151,17 @@ class MqttBridge:
|
||||
def _on_message(self, topic, payload):
|
||||
"""Callback von umqtt. Faengt alles ab -- hier darf nichts durchschlagen."""
|
||||
try:
|
||||
name = topic.decode().rsplit("/", 1)[-1]
|
||||
teile = topic.decode().split("/")
|
||||
gruppe, name = teile[-2], teile[-1]
|
||||
roh = payload.decode().strip()
|
||||
except Exception:
|
||||
self._log("MQTT: unlesbare Nachricht verworfen")
|
||||
return
|
||||
|
||||
if gruppe == "cmd":
|
||||
self._on_command(name, roh)
|
||||
return
|
||||
|
||||
if name not in SETZBAR:
|
||||
self._log("MQTT: unbekannte Einstellung %r verworfen" % name)
|
||||
return
|
||||
@@ -179,6 +192,23 @@ class MqttBridge:
|
||||
except Exception as e:
|
||||
self._log("MQTT: on_change fehlgeschlagen (%s)" % e)
|
||||
|
||||
def _on_command(self, name, roh):
|
||||
"""cmd/<name> auswerten. Bislang nur "ota" -- Payload ist die URL."""
|
||||
if name != "ota":
|
||||
self._log("MQTT: unbekanntes Kommando %r verworfen" % name)
|
||||
return
|
||||
if self._on_ota is None:
|
||||
self._log("MQTT: OTA angefordert, aber kein Handler eingerichtet")
|
||||
return
|
||||
self._log("MQTT: OTA angefordert%s" % (" (%s)" % roh if roh else ""))
|
||||
try:
|
||||
self._on_ota(roh)
|
||||
except Exception as e:
|
||||
# OTA scheitert oft erst mitten im Download (Netz, Server nicht
|
||||
# erreichbar) -- das darf die Poll-Schleife nicht mitreissen,
|
||||
# dieselbe Regel wie bei on_change.
|
||||
self._log("MQTT: OTA fehlgeschlagen (%s)" % e)
|
||||
|
||||
def check(self):
|
||||
"""Anstehende Nachrichten verarbeiten. Blockiert nicht."""
|
||||
if not self.ensure():
|
||||
@@ -235,7 +265,7 @@ class MqttBridge:
|
||||
self._client = None
|
||||
|
||||
|
||||
def connect_from_config(log=None, on_change=None):
|
||||
def connect_from_config(log=None, on_change=None, on_ota=None):
|
||||
"""Bruecke aus mqtt_config.py bauen und verbinden.
|
||||
|
||||
Liefert None, wenn keine Konfiguration da ist -- dann laeuft die Anzeige
|
||||
@@ -257,6 +287,7 @@ def connect_from_config(log=None, on_change=None):
|
||||
client_id=getattr(mqtt_config, "CLIENT_ID", "grossanzeige"),
|
||||
log=log,
|
||||
on_change=on_change,
|
||||
on_ota=on_ota,
|
||||
)
|
||||
bridge.connect() # scheitert es, versucht check() es spaeter erneut
|
||||
return bridge
|
||||
|
||||
Reference in New Issue
Block a user