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 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 19:53:53 +02:00
co-authored by Claude Opus 5
parent 4a1cd00e6e
commit acb443e27a
3 changed files with 117 additions and 3 deletions
+13
View File
@@ -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:
```
+10 -3
View File
@@ -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 &
+94
View File
@@ -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)