Eine Heimspeicher-Überwachung zeigt Ihnen, wie viel Energie gespeichert ist, wie stark der Akku arbeitet und ob eine Zelle aus der Reihe tanzt, lange bevor daraus ein Fehler wird. In diesem Tutorial veröffentlichen Sie Daten des Batteriemanagementsystems (BMS) wie Ladezustand, Packspannung, Strom, Zellspannungen und Temperatur an einen MQTT-Broker, am Beispiel eines Victron-Systems mit Venus OS. Außerdem ergänzen Sie Warnungen bei niedrigem Ladestand und Zellungleichgewicht, die Ihr Smartphone nicht mit Meldungen überfluten.
Was Sie an einem Heimspeicher überwachen sollten
Ein BMS stellt Dutzende Werte bereit. Diese sind für den täglichen Betrieb und die frühe Fehlererkennung entscheidend:
| Wert | Einheit | Warum er wichtig ist | Typische Warnregel |
|---|---|---|---|
| Ladezustand (SoC) | % | Verfügbare Energie für Abend und Nacht | Niedrig unter 20 %, aufheben über 25 % |
| Packspannung | V | Gegenprobe zum SoC, erkennt Sensorfehler | Außerhalb des normalen Bereichs der Zellchemie |
| Strom | A | Positiv beim Laden, negativ beim Entladen | Dauerhafter Strom nahe am BMS-Limit |
| Leistung | W | Spannung mal Strom; leicht zusammen mit PV und Netz darzustellen | Informativ |
| Minimale / maximale Zellspannung | V | Schwächste und stärkste Zelle | Differenz über etwa 50 mV im Ruhezustand |
| Temperatur | °C | Lithium-Akkus dürfen unter dem Gefrierpunkt nicht geladen werden | Unter 5 °C oder über 45 °C |
| Alarme und Zustand | Flags | Schutzereignisse des BMS | Jeder aktive Alarm |
Bei Lithium-Eisenphosphat-Packs (LiFePO4) ist die Zellspannungsdifferenz langfristig oft das aussagekräftigste Signal. Der SoC wird vom BMS geschätzt und kann driften; Zellspannungen dagegen werden gemessen. Eine Differenz, die von Monat zu Monat wächst, deutet auf ein Zell- oder Balancing-Problem hin.
Woher die Daten kommen
Wie Sie an die BMS-Daten kommen, hängt vom System ab:
- Victron-Systeme mit GX-Gerät (Venus OS). Das GX-Gerät betreibt einen lokalen MQTT-Broker, der jeden Wert des internen D-Bus bereitstellt. Aktivieren Sie ihn unter Settings > Services (bei neuerer Firmware Integrations) mit der Option „MQTT on LAN“.
- Hybrid-Wechselrichter stellen SoC, Spannung und Strom des Akkus oft über Modbus-Register bereit, genau wie PV-Daten; zum Modbus-Ansatz siehe Monitoring des Solar-Wechselrichters.
- DIY-Packs mit JK-, JBD- oder Daly-BMS-Platinen bieten Bluetooth- oder UART-Schnittstellen. ESP32-Firmware-Projekte (einschließlich ESPHome-Komponenten) lesen sie aus und veröffentlichen per MQTT.
- Server-Rack-Batterien mit CAN- oder RS485-Anschlüssen melden in der Regel an den Wechselrichter, der dann Ihre Datenquelle ist.
Der Rest dieser Anleitung verwendet Venus OS, weil dessen MQTT-Schnittstelle gut dokumentiert ist, aber die Veröffentlichungs- und Warnlogik funktioniert mit jeder Quelle.
So funktioniert MQTT in Venus OS
Das GX-Gerät veröffentlicht Werte auf Topics der Form N/<portal-id>/<service>/<instance>/<path> mit einem JSON-Payload wie {"value": 87.5}. Akkuwerte liegen unter dem Service battery:
N/<portal-id>/battery/512/Soc
N/<portal-id>/battery/512/Dc/0/Voltage
N/<portal-id>/battery/512/Dc/0/Current
N/<portal-id>/battery/512/Dc/0/Power
N/<portal-id>/battery/512/Dc/0/Temperature
N/<portal-id>/battery/512/System/MinCellVoltage
N/<portal-id>/battery/512/System/MaxCellVoltage
Die Instanznummer (hier 512) unterscheidet sich je nach Installation, und die Pfade für Zellspannungen gibt es nur, wenn das BMS sie meldet. Zwei Details sorgen oft für Verwirrung. Erstens veröffentlicht das GX-Gerät nur so lange, wie ein Client regelmäßig eine Keepalive-Anfrage an R/<portal-id>/keepalive sendet; ohne sie enden die Updates nach etwa einer Minute. Zweitens steht die Portal-ID im Topic von N/<portal-id>/system/0/Serial, worüber ein Skript sie ermitteln kann.
Akkudaten an Ihren Broker weiterleiten
Das folgende Skript verbindet sich im LAN mit dem GX-Gerät, sendet Keepalives, sammelt Akkuwerte und veröffentlicht alle 10 Sekunden eine kompakte JSON-Zusammenfassung an Ihren eigenen Broker. Getestet wird gegen den öffentlichen MQTT-Broker unter broker.connectmq.com, der kein Konto erfordert, aber für alle lesbar und nur für Tests und Prototypen gedacht ist; deshalb verwendet das Skript ein zufälliges Präfix.
pip install "paho-mqtt>=2.0"
import json
import threading
import time
import uuid
import paho.mqtt.client as mqtt
GX_HOST = "192.168.1.70" # Venus-OS-GX-Gerät
PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:8]}/battery/house"
PUBLISH_EVERY = 10
PATHS = {
"Soc": "soc_pct",
"Dc/0/Voltage": "voltage_v",
"Dc/0/Current": "current_a",
"Dc/0/Power": "power_w",
"Dc/0/Temperature": "temp_c",
"System/MinCellVoltage": "cell_min_v",
"System/MaxCellVoltage": "cell_max_v",
}
values = {}
portal = {"id": None}
dest = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"batt-pub-{uuid.uuid4().hex[:6]}")
dest.will_set(f"{PREFIX}/status", "offline", qos=1, retain=True)
dest.connect("broker.connectmq.com", 1883, keepalive=60)
dest.loop_start()
dest.publish(f"{PREFIX}/status", "online", qos=1, retain=True)
def gx_connect(client, userdata, flags, reason_code, properties):
print("Connected to GX:", reason_code)
client.subscribe("N/+/system/0/Serial")
client.subscribe("N/+/battery/+/#")
def gx_message(client, userdata, msg):
parts = msg.topic.split("/")
if parts[2] == "system" and parts[-1] == "Serial" and portal["id"] is None:
portal["id"] = parts[1]
print("Portal ID:", portal["id"])
client.publish(f"R/{portal['id']}/keepalive", "")
return
if parts[2] != "battery":
return
path = "/".join(parts[4:])
if path in PATHS:
try:
values[PATHS[path]] = json.loads(msg.payload).get("value")
except (ValueError, AttributeError):
pass
def keepalive_loop(client):
while True:
if portal["id"]:
client.publish(f"R/{portal['id']}/keepalive", "")
time.sleep(30)
gx = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"batt-gx-{uuid.uuid4().hex[:6]}")
gx.on_connect = gx_connect
gx.on_message = gx_message
gx.connect(GX_HOST, 1883, keepalive=60)
gx.loop_start()
threading.Thread(target=keepalive_loop, args=(gx,), daemon=True).start()
print("Publishing to", PREFIX)
while True:
time.sleep(PUBLISH_EVERY)
if not values:
continue
out = dict(values)
if out.get("cell_min_v") is not None and out.get("cell_max_v") is not None:
out["cell_spread_mv"] = round((out["cell_max_v"] - out["cell_min_v"]) * 1000)
out["ts"] = int(time.time())
dest.publish(f"{PREFIX}/telemetry", json.dumps(out), qos=1, retain=True)
print(out)
Das Ergebnis beobachten:
mosquitto_sub -h broker.connectmq.com -p 1883 -i batt-view-3318 -t "connectmq/demo/+/battery/#" -v
{"soc_pct": 63.4, "voltage_v": 52.71, "current_a": -18.2, "power_w": -959,
"temp_c": 21.0, "cell_min_v": 3.291, "cell_max_v": 3.304, "cell_spread_mv": 13, "ts": 1760611200}
Negativer Strom und negative Leistung bedeuten, dass der Akku entladen wird. Halten Sie diese Vorzeichenkonvention über alle Quellen hinweg einheitlich, damit Dashboards und Automatisierungen keine Sonderfälle brauchen.
Heimspeicher-Warnungen ohne Meldungsflut
Eine Warnung bei niedrigem Ladestand, die alle zehn Sekunden auslöst, während der SoC um den Schwellwert pendelt, gewöhnt alle daran, sie zu ignorieren. Verwenden Sie Hysterese (unterschiedliche Schwellwerte zum Auslösen und Aufheben) und veröffentlichen Sie nur Zustandswechsel der Warnung, nicht jeden Messwert:
import json
import paho.mqtt.client as mqtt
TELEMETRY = "connectmq/demo/<your-id>/battery/house/telemetry"
ALERTS = "connectmq/demo/<your-id>/battery/house/alerts"
RULES = {
# Name: (Feld, auslösen_wenn, aufheben_wenn)
"low_soc": ("soc_pct", lambda v: v < 20, lambda v: v > 25),
"cell_imbalance": ("cell_spread_mv", lambda v: v > 50, lambda v: v < 30),
"cold_battery": ("temp_c", lambda v: v < 5, lambda v: v > 8),
"hot_battery": ("temp_c", lambda v: v > 45, lambda v: v < 40),
}
active = set()
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe(TELEMETRY, qos=1)
def on_message(client, userdata, msg):
data = json.loads(msg.payload)
for name, (field, raise_if, clear_if) in RULES.items():
v = data.get(field)
if v is None:
continue
if name not in active and raise_if(v):
active.add(name)
client.publish(ALERTS, json.dumps({"alert": name, "state": "raised", field: v}), qos=1)
elif name in active and clear_if(v):
active.discard(name)
client.publish(ALERTS, json.dumps({"alert": name, "state": "cleared", field: v}), qos=1)
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="batt-alerts-9902")
c.on_connect = on_connect
c.on_message = on_message
c.connect("broker.connectmq.com", 1883, keepalive=60)
c.loop_forever()
Alles, was Benachrichtigungen versenden kann, etwa Node-RED oder Home Assistant, kann das Alerts-Topic abonnieren und an Ihr Smartphone weiterleiten. Für einfache Schwellwerte auf einem einzelnen Wert bietet das ConnectMQ-Portal außerdem Schwellwert-Alarmregeln mit einem Alarmprotokoll, die „SoC unter 20“ abdecken, ohne dass Sie ein eigenes Skript betreiben; die obige Hysterese-Logik ergänzen Sie, wenn Sie sie brauchen.
Messen Sie die Zelldifferenz im Ruhezustand oder bei geringer Last. Bei starkem Laden oder Entladen und nahe dem Vollladezustand laufen LiFePO4-Zellen von Natur aus stärker auseinander; eine Ungleichgewichtswarnung in diesen Phasen ist daher nicht unbedingt ein Fehler.
Akkuverhalten über die Zeit darstellen
Live-Werte beantworten die Frage „Wie voll ist der Akku gerade?“, die Historie die Frage „Ist der Akku noch gesund?“. Da der Broker nur die letzte retained Nachricht vorhält, speichern Sie die Telemetrie mit einem Subscriber, etwa Telegraf mit InfluxDB, dem Recorder von Home Assistant oder einem kleinen Skript, das in SQLite schreibt. Drei Diagramme lohnen sich schnell:
- SoC zusammen mit PV- und Netzleistung auf derselben Zeitachse, das zeigt, ob der Akku für Ihren Abendverbrauch richtig dimensioniert ist.
- Täglicher minimaler SoC, der saisonale Engpässe sichtbar macht und zeigt, ob eine Reserveeinstellung zu hoch oder zu niedrig ist.
- Zelldifferenz im Ruhezustand über Monate, der langfristige Gesundheitsindikator für LiFePO4-Packs. Ein langsamer Aufwärtstrend ist Ihr Signal, die Balancing-Einstellungen zu prüfen oder den Lieferanten zu kontaktieren.
Checkliste zur Fehlersuche
- Keine Nachrichten vom GX-Gerät? Prüfen Sie, ob MQTT on LAN aktiviert ist und ob Sie nach dem Verbinden abonniert haben.
- Werte stoppen nach einer Minute? Das Keepalive erreicht
R/<portal-id>/keepalivenicht; prüfen Sie die ermittelte Portal-ID. - Zellspannungen fehlen? Ihr BMS meldet sie möglicherweise nicht an Venus OS; prüfen Sie die Geräteseite des Akkus auf dem GX.
- SoC springt nach einer Vollladung? Das BMS hat seine Schätzung neu synchronisiert; das ist nach Phasen ohne Vollladung normal.
- Werte wirken im Dashboard veraltet? Prüfen Sie das retained Status-Topic; steht dort
offline, ist die Bridge gestoppt.
Umstieg auf einen privaten Broker
Akkudaten verraten, wann Sie zu Hause sind und wie Ihr System konfiguriert ist, und der öffentliche MQTT-Broker wird gemeinsam genutzt; verwenden Sie für den Dauerbetrieb daher einen privaten Broker. Mit einem verwalteten MQTT-Broker wie ConnectMQ baut die Bridge auf Ihrem Raspberry Pi eine einzige ausgehende TLS-Verbindung auf, ohne dass Sie Ports am Router öffnen müssen. Legen Sie im ConnectMQ-Portal einen Broker an und ändern Sie die Zielverbindung:
dest = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID")
dest.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
dest.tls_set()
dest.connect("broker.connectmq.com", 8883, keepalive=60)
Von dort aus können Akkudaten zusammen mit Ihrem Energiemonitor für Zuhause und Ihrer Wallbox Entscheidungen steuern, etwa das Auto erst zu laden, wenn der Akku einen festgelegten SoC überschritten hat. Hosting-Optionen für den Broker finden Sie im Leitfaden zum Cloud-MQTT-Broker, das größere Bild im IoT-Automatisierungsleitfaden. Dasselbe Muster trägt auch im Mittelstand: Ein Gewerbespeicher am Werk lässt sich als weiterer Knoten in den Unified Namespace (UNS) einhängen, etwa unter acme/werk-ulm/energie/speicher-1/telemetry, und fließt so direkt in das Energiemonitoring neben den Maschinendaten ein.
Überwachen Sie Ihren Akku mit ConnectMQ
ConnectMQ bietet einen TLS-gesicherten MQTT-Broker mit generierten Zugangsdaten, einen Live-Topic-Explorer und Schwellwert-Alarmregeln für Werte wie den Ladezustand. Erstellen Sie einen kostenlosen Serverless-Broker unter app.connectmq.com, ganz ohne Kreditkarte, und verbinden Sie Ihre Akku-Bridge in wenigen Minuten.
Häufig gestellte Fragen
Welcher Schwellwert für niedrigen Akkustand ist bei Heimspeichern sinnvoll?
Viele LiFePO4-Nutzer lösen eine Warnung bei etwa 15 bis 20 Prozent SoC aus und heben sie einige Prozent höher wieder auf. Halten Sie sich an die Empfehlung Ihres Akkuherstellers zum minimalen SoC im Alltagsbetrieb.
Warum Zellspannungen überwachen statt nur den Ladezustand?
Der SoC ist eine Schätzung, die driften kann, während Zellspannungen direkte Messwerte sind. Eine wachsende Differenz zwischen höchster und niedrigster Zelle ist ein frühes Anzeichen für Balancing-Probleme oder eine schwache Zelle.
Braucht Venus OS für MQTT eine Internetverbindung?
Nein. MQTT on LAN funktioniert vollständig lokal. Die Bridge in dieser Anleitung liest lokal und baut nur eine ausgehende Verbindung zu dem von Ihnen gewählten Broker auf.
Kann ich einen DIY-Akku ohne Victron-Hardware überwachen?
Ja. JK-, JBD- und Daly-BMS-Platinen lassen sich über Bluetooth oder UART mit ESP32-Firmware wie ESPHome-Komponenten auslesen, die direkt per MQTT veröffentlichen und dasselbe Topic- und Warnungsdesign nutzen.



