Akku an einem Fronius-Wechselrichter per Modbus steuern
Wieso man den Haus-Akku gescriptet ausschalten können will
Meiner Lösung für das Laden eines E-Autos mit PV-Überschuss go-e-pvsd kann man mittlerweile zur Laufzeit mitteilen, dass man eine andere Ladeschwelle als die eigentliche haben will. Das nutze ich dafür, dass ich das Auto auch dann lade, wenn der Überschuss nicht allein dafür ausreicht. Z. B. kann man die Schwelle auf 1 W einstellen. Dann wird geladen, sobald es überhaupt irgendwelchen Überschuss gibt, und zwar mit dem minimalen Ladestrom. Was fehlt, kommt vom Netz, aber sollte der Überschuss reichen, dann wird der Ladestrom, genau wie beim „normalen“ Überschussladen, so angepasst, dass alles für das Laden benutzt wird, was da ist.
Wenn man aber nur teilweise mit eigenem Strom laden kann, dann ist es wenig sinnvoll, dass man den fehlenden Anteil aus dem Haus-Akku holt. Weil dann lädt man einen Akku mit einem anderen. Da ist der Strom aus dem Haus-Akku später bei den Verbrauchern im Haus deutlich besser aufgehoben. Und abgesehen davon wäre der Akku auch schnell leer, weil der Auto-Akku i. d. R. ja eine vielfach höhere Kapazität hat.
Also wäre es sinnvoll, das Entladen des Akkus automatisiert zu verhindern, wenn das Auto geladen wird – oder das zumindest so einfach wie möglich zu gestalten. Das geht ohne weitere Maßnamhen über ein zeitgesteuertes Energieprofil, was man im Webinterface des Wechselrichters anlegen kann. Das muss dann von Montag bis Sonntag von 0.00 bis 23.59 Uhr gelten und die maximale Entladung auf 0 W festlegen. Wenn man das dann aktiviert, dann wird aller zusätzlich benötigter Strom aus dem Netz geholt. Dazu muss man aber im lokalen Netzwerk sein, sich am Webinterface des Wechselrichters anmelden, und dann via „Energiemanagement“ → „Batteriemanagement“ das jeweilige Profil aktivieren. Nervt.
Akku steuern via Modbus
Tatsächlich kann man den Akku auch mittels Modbus „ausschalten“, also die Entladung verhindern. Dazu gibt es von Fronius allerlei Dokumentation (wenn man sich mit seiner E-Mail-Adresse registriert, dann kann man die Dokumente einfach herunterladen). Das ist aber alles auf den ersten Blick ziemlich kryptisch, insbesondere dann, wenn man (wie ich) noch nie mit Modbus zu tun hatte.
Alles, was man findet, wenn man nach „Fronius Akku per Modbus steuern“ oder auch „Fronius control battery using modbus“ sucht, ist Stand heute ziemlich dürftig. Ein paar Forums-Posts, ein paar Youtube-Videos. Scheinbar wissen auch manche nicht so recht, was sie da eigentlich machen … und alle benutzen „Home Assistant“, „Node Red“ oder sonstwas.
Das muss doch auch einfacher gehen.
Geht es auch, und zwar mit pymodbus, einer vollständigen Implementierung des Modbus-Protokolls für Python. Damit kann man das mit einer Handvoll Zeilen Code bewerkstelligen.
Steuerung mit einem Python-Script und pymodbus
Modbus TCP am Wechselrichter aktivieren
Was man zuerst machen muss: Dem Wechselrichter mitteilen, dass er als Modbus-Server (in der Modbus-Welt „Slave“ genannt) agieren soll. Das geht folgendermaßen:
Zunächst muss man sich als „Technician“ anmelden [Update 08.11.2024: Mit der aktuellen Firmware geht das jetzt auch als „Customer“]:
Dann über das Menü zu den Modbus-Einstellungen navigieren:
Und schließlich den Modbus-Server aktivieren:
Die Einstellungen waren hier schon alle so vorausgewählt. Ich habe auch „SunSpec Model Type“ auf „int + SF“ (also Integer-Werte mit einem Skalierungsfaktor) gelassen. Für die andere Option „float“ müsste man dann andere Adressen und Werte benutzen.
Benötigte Register
Zum Steuern der maximalen Ladung bzw. Entladung braucht man nur zwei Register. Für „int + SF“ als „SunSpec Model Type“ sind diese (vgl. die Fronius-Dokumentation):
StorCtl_Mod
(Register 40349)-
Hier kann festgelegt werden, ob die maximale Ladung, Entladung oder beide Werte festgelegt werden sollen. Der Wert besteht aus zwei Bits. Das erste Bit steht für Ladung, das zweite für Entladung. Wir können also entweder
0x01
(≙ 1),0x10
(≙ 2) oder0x11
(≙ 3) setzen, was dann entsprechend für die maximale Ladung, Entladung oder für beide Werte steht. OutWRte
(Register 40356)- Dieser Wert legt die prozentuale maximale Ladung bzw. Entladung fest. Er kann zwischen 0 und 10 000 liegen und hat einen Skalierungsfaktor von -2. Dieser steht für eine Zehnerpotenz, mit der der Wert multipliziert werden muss, in diesem Fall also 10-2. Folgerichtig steht 0 für 0 % und 10 000 für 100 %.
Ansteuerung mit Python und pymodbus
Ich habe pymodbus 3.6.9 benutzt. Das gibt es oder gibt es nicht „einfach so“, je nach Distribution. Bei Gentoo gibt ein Ebuild in verschiedenen Overlays, auf Artix kann man sich ein Paket mittels dem AUR bauen, und Devuan hat es von Haus aus dabei (wobei ich für Stable einen Backport benutzen musste). Egal wie: Man bekommt das Paket installiert.
Wir brauchen nur die Klasse ModbusTcpClient
, die wir aus pymodbus.client
importieren:
from pymodbus.client import ModbusTcpClient
Dann instanziieren wir einen Client und verbinden uns mit dem Server. Der Host muss der Hostnname bzw. die IP-Adresse des Wechselrichters sein. Der Port ist standardmäßig auf 502 eingestellt, sicherheitshalber habe ich ihn aber explizit angegeben:
client = ModbusTcpClient(host = "192.168.1.3", port = 502) # Adjust as needed client.connect()
Und schon kann es losgehen. Wir brauchen nur die Funktion write_register
. Version 3.6.9 von pymodbus legt als Standardwert für slave
0 fest. Die „unit id“ des Wechselrichters ist fix 0x01
, weswegen wir den Parameter explizit angeben müssen. Laut Dokumentation sind „die ausgesendete[n] Registeradresse[n] […] immer um 1 geringer als die eigentliche Registernummer“ – also benutzen wir für StorCtl_Mod
Register 40348 und für OutWRte
Register 40355.
Dann stellen wir sicher, dass wir den maximalen Entladewert setzen:
client.write_register(40348, 2, slave = 1)
Und hinterher setzen wir den Wert (0 für „ausschalten“, 10000 für „einschalten“):
client.write_register(40355, 0, slave = 1) # off #client.write_register(40355, 10000, slave = 1) # on
Und das war’s auch schon. Zum Schluss schließen wir noch die Verbindung und sind fertig!
client.close()
Der Effekt ist nach ein paar Sekunden im Wechselrichter-Webinterface oder Solarweb zu sehen.
Sinnvollerweise setzt man natürlich die Host-Adresse und ggf. den Port in einer Konfigurationsdatei, macht ein bisschen Fehlerbehandlung (konnte die Verbindung hergestellt werden? Waren die Abfragen erfolgreich?), aber im Prinzip sind es erfreulicherweise nur die paar Zeilen Python-Code, die man braucht, um den Akku zu steuern.
Ich hoffe, ich kann damit vielleicht dem Einen oder Anderen ein bisschen Kopfzerbrechen und Dokumentation wälzen ersparen!
Viel Spaß damit :-)