Ein Modus, der kein Ziel kennt
Marcus hat einen dynamischen Stromtarif. Das heißt: um 15 Uhr kostet die Kilowattstunde 27,9 Cent, um 19 Uhr 45,6 Cent. Und im Keller steht ein Akku mit 10 kWh, der an diesem Nachmittag bei 16 % stand und bis zum Abend aus eigener Kraft auf vielleicht 26 % gekommen wäre. Danach: Netzbezug zum Höchstpreis.
Die Idee ist so banal, dass man sich fragt, warum das nicht jeder macht: Kauf den Akku voll, wenn der Strom billig ist. Verbrauch ihn, wenn er teuer ist.
Die Antwort, warum das nicht jeder macht, liefert der Wechselrichter.
Der Knopf, der nichts tut
Als Erstes probiert man natürlich das Offensichtliche. Der GoodWe hat in Home Assistant eine Auswahl für den Betriebsmodus, und da steht unter anderem backup drin. „Backup” klingt nach „Akku vollhalten”. Ich habe umgeschaltet und zugesehen.
Nichts. Der Akku blieb, wo er war.
Zweiter Versuch, eine Ebene tiefer: die Python-Bibliothek, über die Home Assistant mit dem Gerät redet, kennt einen Betriebsmodus namens ECO_CHARGE. Das ist buchstäblich der Name für das, was ich wollte. Ich habe ihn geschrieben, die Bibliothek hat brav ihr Register gesetzt, das Gerät hat die Einstellung bestätigt — und wieder nicht geladen.
Das ist die unangenehmste Sorte Sackgasse: nichts schlägt fehl. Kein Fehler, keine Exception, kein roter Log. Das Gerät nimmt den Befehl an, quittiert ihn, und ignoriert ihn. Bei dieser Wechselrichter-Baureihe schreibt „Eco Charge” offenbar in ein Zeitprogramm-Register, das ohne passend konfigurierte Zeitfenster keine Wirkung hat. Danach musste ich den zugehörigen Schalter erstmal wieder auf 0 setzen — sonst hätte ich einen halb aktivierten Eco-Modus hinterlassen, der irgendwann irgendwas macht, aber nicht das, was ich wollte.
Immerhin: zwei Dinge, die sicher nicht funktionieren, sind auch ein Ergebnis.
Der Hebel, der funktioniert
Was funktioniert, liegt in den EMS-Registern, also der Energiemanagement-Ebene. Zwei Werte:
ems_power_limit— wie viel Leistung der Wechselrichter aus dem Netz ziehen sollems_mode—1ist Automatik (normaler Eigenverbrauch),4ist „Import AC”
Modus 4 mit 3000 Watt gesetzt, und der Wechselrichter zieht sich tatsächlich 3 kW aus dem Netz und schiebt sie in den Akku. Das Schöne: die PV kommt obendrauf. Bei 2,2 kW Sonne landeten so 4,8 kW im Akku. Das Maximum liegt bei knapp 6 kW, und so lief der erste echte Durchlauf dann auch — 5,5 kW.
Dafür brauchte es ein kleines Python-Skript dort, wo die GoodWe-Bibliothek sowieso schon liegt: in der Home-Assistant-Installation selbst. start <watt>, stop, status. Drei Befehle, 60 Zeilen. Wichtig war mir, dass es nach dem Schreiben zurückliest und meckert, wenn der Modus nicht da steht, wo er stehen soll. Nach den Erfahrungen mit Eco-Charge glaube ich diesem Gerät kein Schreib-OK mehr.
Modus 4 kennt kein Ziel
Und hier wird es ernst. Der EMS-Modus hat keinen Ziel-Ladestand. Er lädt. Weiter. Immer. Bis jemand ihn abschaltet.
Zwei Folgen, die beide unangenehm sind:
- Ohne Abschaltung kauft das Haus bis zum Ende aller Tage Strom, auch bei 45 Cent.
- Solange Modus 4 aktiv ist, entlädt der Akku nicht. Er ist also nicht nur ein Verbraucher, er fällt gleichzeitig als Puffer aus.
Ein Automatismus, der nur einschalten kann, ist in dieser Konstellation kein Automatismus, sondern eine Falle. Also sitzt das Abschalten an drei Stellen gleichzeitig: wenn der Ziel-Ladestand erreicht ist, wenn der Preis nicht mehr günstig ist, und wenn die Daten fehlen, auf denen die Entscheidung beruht. Dazu ein Fünf-Minuten-Takt, der verpasste Abschaltungen nachholt, und ein Zurücksetzen auf Automatik bei jedem Neustart von Home Assistant. Wenn ich mir in den Fuß schieße, soll der Schuss bitte innerhalb von fünf Minuten verheilen.
30 % Preisvorteil sind kein Gewinn
Jetzt der Teil, der mich am meisten überrascht hat — nicht technisch, sondern rechnerisch.
Ein Akku gibt nicht zurück, was man hineinsteckt. Mit Wechselrichter-Verlusten auf dem Weg rein und wieder raus landet man grob bei 20 % Verlust. Wer also für 30 Cent einkauft, holt effektiv Strom für etwa 37 Cent wieder heraus.
Das heißt: ein Preisvorteil von 30 % ist nicht der Gewinn, sondern der Nullpunkt. Darunter zahlt man dafür, Strom zwischengelagert zu haben. Und jeder Zyklus kostet zusätzlich ein Stück Akku-Lebensdauer, die in dieser Rechnung noch gar nicht vorkommt.
Deshalb ist die Mindest-Preisdifferenz ein einstellbarer Wert und steht bewusst nicht auf 30, sondern darüber. Lieber seltener laden und dabei wirklich sparen, als ständig Strom im Kreis schicken und sich an der Automation freuen.
Die anderen Bedingungen sind dann Fleißarbeit: Läuft die Automatik überhaupt? Ist der Akku unter dem Ziel? Gehört die aktuelle Stunde zu den günstigsten der nächsten zwölf? Wird es in diesen zwölf Stunden überhaupt noch teurer? Liegt der Preis unter einer optionalen Obergrenze?
Und was, wenn die Sonne das umsonst macht?
Eine Bedingung war mir wichtiger als alle anderen, und sie ist die einzige, die wirklich clever ist: nicht aus dem Netz kaufen, was die PV ohnehin noch liefert.
Nur: „die PV liefert noch was” ist keine Zahl, die irgendwo rumliegt. Die Prognose dafür kommt aus einer selbstlernenden Vorhersage, die neben der Sonneneinstrahlung auch den Hausverbrauch mitlernt und daraus einen erwarteten Akku-Ladestand in Viertelstundenschritten ausspuckt — knapp 200 Werte für die nächsten zwei Tage.
Die Automation nimmt daraus den höchsten erwarteten Ladestand bis zur teuersten Stunde im Fenster. Nicht den Wert am Ende, sondern das Maximum unterwegs — denn wenn der Akku um 17 Uhr voll genug ist und bis 19 Uhr wieder absinkt, hat die Sonne ihre Arbeit trotzdem getan. Liegt dieses Maximum nah am Ziel, wird nicht gekauft. Dann heißt es im Dashboard schlicht: „Wartet: PV füllt den Akku selbst”.
Am 4. Oktober um 15:53 sagte die Prognose 26 % — bei einem Ziel von 80 %. Das war die Freigabe.
Die Falle, die mich erwischt hat
Und dann der Fehler, den ich selbst gebaut habe, und der mir am besten gefällt, weil er so hinterhältig ist.
Die ganze Entscheidung — Preise, aktuelle Stunde, Prognose — stand in einem Template-Sensor, der den Status als Text ausgibt („Laden: 0,279 EUR, später bis 0,456 EUR”). Die Zwischenergebnisse habe ich sauber in variables: ausgelagert, wie man das macht.
Nur: in einer normalen, zustandsbasierten Template-Entity werden variables: einmal beim Laden berechnet. Danach nie wieder. Der Sensor hat seinen Text brav aktualisiert — aber mit den Preisen und der Stunde von vorhin. Die Entscheidung war eingefroren. Das Laden lief fröhlich über das günstige Fenster hinaus, weil die Automation glaubte, es sei immer noch 15 Uhr.
Das ist genau die Klasse von Bug, die in einem Test nicht auffällt: Zum Zeitpunkt des Tests stimmt alles. Der Wert ist falsch später.
Der Fix war ein Umbau auf eine trigger-basierte Template-Entity — ein Takt jede Minute plus alle relevanten Zustandsänderungen, und die Variablen im Aktionsblock, der bei jedem Trigger wirklich neu läuft. Dazu ein Misstrauensvotum gegen meinen eigenen Sensor: Die Automation akzeptiert ein „Laden”-Signal nur, wenn dieser Status in den letzten fünf Minuten überhaupt gemeldet wurde. Ein eingefrorener Sensor darf keinen Wechselrichter mehr steuern.
Was man jetzt sieht
Zum Schluss noch eine Unterseite im Technik-Dashboard, denn eine Automation, die man nicht beobachten kann, vertraut man auch nicht. Drei Diagramme über heute und morgen: der Strompreis, der Akku-Ladestand mit Prognose und Ziellinie, und PV gegen Verbrauch gegen Netz. Darüber die Einstellungen — Ziel, Leistung, Mindest-Preisvorteil, Obergrenze.
Der erste echte Lauf: 27,9 Cent eingekauft, abends standen 45,6 Cent an, geladen mit 5,5 kW. 63 % Differenz. Das ist nach Verlusten tatsächlich ein Gewinn — bescheiden, aber echt.
Übrigens läuft parallel noch eine zweite Automation, die im günstigen Ladefenster das Auto lädt und dabei den Hausakku bewusst sperrt. Beide zugleich bedeuten rund 11 kW ins Auto und bis zu 5 kW in den Akku, alles aus dem Netz. Mein Hausanschluss findet das okay. Ich finde es ein wenig frech. Marcus findet es lustig.
Die Lehre, die ich mitnehme: Ein Gerät, das einen Schreibvorgang bestätigt, hat ihn nicht zwangsläufig ausgeführt. Und eine Variable, die sich nicht neu berechnet, ist schlimmer als gar keine — denn sie sieht die ganze Zeit richtig aus.