From acb443e27aa8fa6d7ae30013f3223512067e2059 Mon Sep 17 00:00:00 2001 From: "m0@nas" Date: Thu, 3 Sep 2026 19:53:53 +0200 Subject: [PATCH] Wattpilot-Bruecke verwirft keine Messwerte mehr Die Wallbox schickt 34 Statusfelder, die die API-Beschreibung von wattpilot 0.2 nicht kennt. Die Bibliothek schlug jedes Feld ungeprueft nach und lief in einen KeyError, der die restliche Schleife mitriss - alle Werte hinter dem unbekannten Feld derselben Nachricht kamen nie beim MQTT-Broker an. Im Dauerbetrieb traf es alle 15 Sekunden fhz, lps und tpcm, nach einem Verbindungsaufbau deutlich mehr; sichtbar war es nur als Fehlerpaar 'clea' im Log, rund ein MB am Tag. wattpilot_bruecke.py ersetzt die betroffene Funktion zur Laufzeit und ueberspringt unbekannte Felder, jedes einmal mit einer Warnung. Die Reparatur steht hier und nicht in site-packages, weil eine Neuinstallation sie dort spurlos zurueckdrehen wuerde und wattpilot 0.2 seit Mai 2022 die letzte Veroeffentlichung ist. Co-Authored-By: Claude Opus 5 --- autoActions/README.md | 13 ++++++ startWattpilotMQTT.sh | 13 ++++-- wattpilot_bruecke.py | 94 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 3 deletions(-) create mode 100755 wattpilot_bruecke.py diff --git a/autoActions/README.md b/autoActions/README.md index 8c680c1..e47f6fe 100644 --- a/autoActions/README.md +++ b/autoActions/README.md @@ -264,6 +264,19 @@ arbeitet die Rotation mit `copytruncate` — deshalb leiten die Startskripte mit `>>` um und nicht mehr mit `&>`. Wer das zurückdreht, bekommt nach der nächsten Rotation eine Logdatei, die vorn aus Nullbytes besteht. +Die lauteste dieser Dateien war `wattpilotshell.log`, rund ein MB am Tag. Die +Wallbox schickt in ihren Statusnachrichten 34 Felder, die die +API-Beschreibung der Bibliothek nicht kennt (`clea`, `cle`, `opad`, die ganze +`ocpp*`-Familie) — wattpilot 0.2 ist seit Mai 2022 die letzte +Veröffentlichung, ein Update behebt das also nicht. Die Bibliothek schlug +jedes Feld ungeprüft nach und lief in einen `KeyError`, der die restliche +Schleife mitriss: alles, was in derselben Nachricht dahinter stand, wurde nie +veröffentlicht — im Dauerbetrieb alle 15 Sekunden `fhz`, `lps` und `tpcm`, +nach einem Verbindungsaufbau deutlich mehr. `wattpilot_bruecke.py` ersetzt +die betroffene Funktion zur Laufzeit und überspringt unbekannte Felder, jedes +einmal mit einer Warnung im Log. `startWattpilotMQTT.sh` startet seither die +Brücke statt der `wattpilotshell` direkt. + `fetch_calendar.py` gehört einmal jährlich in den Cron: ``` diff --git a/startWattpilotMQTT.sh b/startWattpilotMQTT.sh index a7f73fa..c0b2514 100755 --- a/startWattpilotMQTT.sh +++ b/startWattpilotMQTT.sh @@ -27,11 +27,13 @@ fi echo "Starting..." # Change the name of the script here -SCRIPT_NAME="wattpilotshell" +# Deckt auch den alten Aufruf ab, damit beim Umstieg keine zweite +# Instanz stehen bleibt. +SCRIPT_NAME="wattpilot_bruecke.py|wattpilotshell" LOG_FILE="wattpilotshell.log" # Find the process ID of any running instance of the script -PID=$(ps aux | grep "$SCRIPT_NAME" | grep -v grep | awk '{print $2}') +PID=$(ps aux | grep -E "$SCRIPT_NAME" | grep -v grep | awk '{print $2}') # If a running instance was found, kill it if [[ -n "$PID" ]]; then @@ -48,4 +50,9 @@ cd "$BASIS" # Loch aus Nullbytes in der Groesse des bisherigen Inhalts. Bei dieser Datei # faellt das besonders ins Gewicht - die wattpilotshell meldet einen # Verbindungsfehler im Sekundentakt und hatte es so auf 329 MB gebracht. -/var/services/homes/wagner/.local/bin/wattpilotshell server >> "$LOG_FILE" 2>&1 & +# Nicht mehr die wattpilotshell direkt: wattpilot_bruecke.py startet sie +# ueber eine reparierte MQTT-Bruecke. Die Bibliothek stolpert sonst ueber +# Statusfelder, die ihre API-Beschreibung von 2022 nicht kennt, und +# verwirft dabei alle Werte, die in derselben Nachricht dahinter stehen. +# Begruendung im Kopf von wattpilot_bruecke.py. +/usr/local/bin/python3.10 "$BASIS/wattpilot_bruecke.py" server >> "$LOG_FILE" 2>&1 & diff --git a/wattpilot_bruecke.py b/wattpilot_bruecke.py new file mode 100755 index 0000000..04f7a93 --- /dev/null +++ b/wattpilot_bruecke.py @@ -0,0 +1,94 @@ +#!/usr/local/bin/python3.10 +"""Startet die wattpilotshell, aber mit einer Reparatur an der MQTT-Bruecke. + +Das Problem +----------- +Die Wallbox schickt in ihren Statusnachrichten Felder, die die +API-Beschreibung der Bibliothek (wattpilot 0.2, Stand 2022) nicht kennt - +gemessen 34 Stueck, darunter 'clea', 'cle', 'opad' und die ganze +'ocpp*'-Familie. Die Bibliothek schlaegt jedes Feld ungeprueft in ihrem +Verzeichnis nach: + + for prop_name, value in msg_dict["status"].items(): + pd = wpdef["properties"][prop_name] # KeyError bei 'clea' + mqtt_publish_property(wp, mqtt_client, pd, value) + +Der KeyError reisst die restliche Schleife mit. Alles, was in derselben +Nachricht *hinter* dem unbekannten Feld steht, wird nie veroeffentlicht - +beim Verbindungsaufbau trifft das unter anderem 'amp', 'car', 'ust', 'err', +'cbl', 'pha' und 'wh'. Sichtbar wurde das nur als Fehlerpaar im Log, etwa +alle 16 Sekunden: + + ERROR:wattpilot:Error received from WebSocketApp: 'clea' + ERROR:websocket:error from callback ... Wattpilot.__on_message ...: 'clea' + +Die Reparatur +------------- +Unbekannte Felder werden uebersprungen statt zu werfen, jedes einmal mit +einer Warnung im Log. Alle bekannten Felder derselben Nachricht kommen +dadurch durch. + +Warum hier und nicht in der Bibliothek +-------------------------------------- +Die Bibliothek liegt unter ~/.local/lib/python3.10/site-packages und damit +ausserhalb dieses Repositorys; eine Neuinstallation wuerde eine Aenderung +dort spurlos zurueckdrehen. wattpilot 0.2 ist seit Mai 2022 die letzte +Veroeffentlichung, ein Update behebt es also nicht. Deshalb steht die +Reparatur hier, unter Versionskontrolle, und ersetzt die Funktion zur +Laufzeit. mqtt_setup() schlaegt den Namen erst beim Registrieren nach, so +dass unsere Fassung greift. +""" + +import json +import logging +import sys + +from wattpilot import wattpilotshell as shell + +_LOG = logging.getLogger("wattpilot.bruecke") + +# Jedes unbekannte Feld soll genau einmal auffallen, nicht bei jeder Nachricht. +_gemeldet = set() + + +def mqtt_publish_message(event, message): + """Ersatz fuer wattpilotshell.mqtt_publish_message - siehe Modulkopf.""" + wp = event["wp"] + if shell.mqtt_client is None: + return + + nachricht = json.loads(message) + typ = nachricht["type"] + + if shell.MQTT_PUBLISH_MESSAGES == "true" and ( + shell.MQTT_MESSAGES in ([], [""]) or typ in shell.MQTT_MESSAGES): + thema = shell.mqtt_subst_topic(shell.MQTT_TOPIC_MESSAGES, { + "baseTopic": shell.MQTT_TOPIC_BASE, + "serialNumber": wp.serial, + "messageType": typ, + }) + shell.mqtt_client.publish(thema, message) + + if shell.MQTT_PUBLISH_PROPERTIES != "true" or typ not in ("fullStatus", "deltaStatus"): + return + + eigenschaften = shell.wpdef["properties"] + for name, wert in nachricht["status"].items(): + beschreibung = eigenschaften.get(name) + if beschreibung is None: + if name not in _gemeldet: + _gemeldet.add(name) + _LOG.warning( + "Feld '%s' steht nicht in der API-Beschreibung der " + "Bibliothek - wird uebersprungen (Wert: %.80s)", name, repr(wert)) + continue + shell.mqtt_publish_property(wp, shell.mqtt_client, beschreibung, wert) + + +shell.mqtt_publish_message = mqtt_publish_message + +if __name__ == "__main__": + try: + sys.exit(shell.main()) + except KeyboardInterrupt: + sys.exit(0)