Batteriespeicher mit Home Assistant steuern

Schema: Home Assistant regelt zwei Batteriespeicher nach der Netzmessung; darunter ein Verlauf, in dem ein gleitender Mittelwert den Ladestand 79 Minuten lang bei 40,9 Prozent einfriert

Verfasst von

in

In einem früheren Artikel habe ich beschrieben, wie meine Server an den Notstrom-Ausgängen von zwei Hybrid-Wechselrichtern hängen und welche Fehler ich in der Batteriesteuerung gefunden habe. Hier geht es um die Steuerung selbst. Sie hat zwei Ziele, die sich widersprechen: möglichst viel eigenen Solarstrom nutzen und trotzdem immer genug Reserve für einen Stromausfall halten.

Schema: Home Assistant regelt zwei Batteriespeicher nach der Netzmessung; darunter ein Verlauf, in dem ein gleitender Mittelwert den Ladestand 79 Minuten lang bei 40,9 Prozent einfriert

So rechnet der Regelkreis

Am Netzanschluss misst ein Shelly Pro 3EM die Leistung, positiv heißt Bezug aus dem Netz. Template-Sensoren rechnen daraus eine Zielleistung je Wechselrichter. Dazu gehören eine Totzone von 30 W, damit kleine Schwankungen nichts auslösen, eine Dämpfung mit dem Faktor 0,85 und ein Balance-Faktor, der die Leistung auf beide Batterien verteilt. Je Batterie sind höchstens 1200 W erlaubt. Eine Automation schreibt die Zielleistung über eine lokale Integration in den Wechselrichter: negativ heißt laden, positiv heißt entladen.

Regelkreis der Batteriesteuerung: Der Netzzähler misst den Bezug, Template-Sensoren rechnen die Zielleistung, eine Automation schreibt sie über die Integration in den Wechselrichter, die Batterie ändert den Netzbezug.

Seit dem Umbau sehen die wichtigsten Stellschrauben so aus:

Stellschraubevorherheute
Auslöser der Steuerungalle 5 Sekunden und bei jeder Änderung von Shelly oder Ladestand, Läufe in einer Warteschlangenur alle 10 Sekunden, ein Lauf zurzeit
Neuer Befehl ab Abweichung50 W80 W, mindestens 15 Sekunden Abstand
Abfrage der Integrationalle 3 Sekundenalle 5 Sekunden
NetzladungStart unter 40 %, Stopp bei 40 %Start unter 43 %, Stopp ab 48 %
Fehlende MesswerteErsatzzahlenSensor gilt als nicht verfügbar, Sollwert 0

Die Netzladung braucht einen Merker, damit sie zwischen 43 und 48 Prozent weiß, ob sie gerade lädt. Sinngemäß sieht das so aus (Entitätsnamen vereinfacht):

template:
  - binary_sensor:
      - name: "Netzladung Batterie 2 aktiv"
        state: >
          {% set soc = states('sensor.batterie2_ladestand_sicher') | float(none) %}
          {% if soc is none %}{{ this.state == 'on' }}
          {% elif soc < 43 %}true
          {% elif soc >= 48 %}false
          {% else %}{{ this.state == 'on' }}{% endif %}

Drei Fehler in der Rechnung

Beim genauen Durchlesen der Konfiguration fielen mir drei Fehler auf, die im Betrieb nicht sofort sichtbar sind.

Die Zielleistung las ihren eigenen alten Wert, um zu glätten. Home Assistant meldete deshalb immer wieder „Template loop detected“. Schlimmer: Die Glättung hing nicht an der Zeit, sondern wurde bei jeder Änderung irgendeines Eingangs neu gerechnet, zwischen 22.500 und 37.700 Mal am Tag je Wechselrichter. Heute rechnet der Sensor ohne Selbstbezug, und die Glättung sitzt in der Automation mit festem Takt.

Fehlende Messwerte wurden an verschiedenen Stellen unterschiedlich ersetzt, mal durch 0, mal durch 50, mal durch 100. Fiel ein Ladestand aus, halbierte sich der Durchschnitt, und der Status zeigte „Netzladung (Kritisch)“, während die eigentliche Steuerung gar nicht lud. Jetzt haben alle Berechnungen eine availability-Bedingung. Fehlt ein Eingang, ist das Ergebnis nicht verfügbar, und die Steuerung setzt den Sollwert auf 0.

Der Balance-Faktor gab der Batterie mit dem niedrigeren Ladestand 60 Prozent des Anteils. Beim Laden ist das richtig, beim Entladen hat dadurch die leerere Batterie mehr abgegeben, und der Abstand wuchs. Der Schalter „SOC-Balance An“ wurde außerdem von keiner Automation gelesen. Beides ist korrigiert: Beim Entladen gibt die vollere Batterie mehr ab, und der Schalter wirkt.

Warum der Filter den Ladestand einfror

Die Folge habe ich im früheren Artikel geschildert: Der gefilterte Ladestand blieb 79 Minuten bei 40,9 Prozent stehen, die Netzladung startete nicht, und eine Batterie sank auf 10 Prozent. Hier der Grund. Ich hatte diesen Filter gebaut:

sensor:
  - platform: filter
    name: "Batterie 2 Ladestand gefiltert"
    entity_id: sensor.batterie2_ladestand
    filters:
      - filter: time_simple_moving_average
        window_size: "00:02"
        precision: 1

Der gleitende Mittelwert über zwei Minuten rechnet nur, wenn ein neuer Wert ankommt. Springt der Ladestand und bleibt danach gleich, kommt kein neuer Zustand mehr, und der Filter bleibt beim Mittelwert stehen, der gerade im Fenster lag. Bei mir sprang der Wert von 42 auf 30 Prozent. Danach stand der gefilterte Wert knapp über der damaligen Ladegrenze von 40 Prozent, und das blieb so, bis der Messwert sich wieder bewegte.

Ein Ausreißerfilter wäre noch schlechter gewesen. Er ersetzt jeden Wert, der mehr als einen festen Abstand vom Median der letzten Werte entfernt ist, durch diesen Median. Springt der Ladestand dauerhaft, etwa nach einer Kalibrierung der Batterie, hält er den alten Wert für immer fest. Die Netzladung käme nie. Den hatte ich deshalb schon vorher verworfen.

Ersetzt habe ich den Filter durch einen Template-Sensor „Ladestand sicher“, der den Messwert durchreicht und nur dann nicht verfügbar ist, wenn keine Zahl kommt. Kurze Sprünge fängt nicht mehr ein Filter ab, sondern eine Wartezeit an der einzigen Stelle, wo sie stören: Ein Ladestand unter 10 Prozent führt erst nach zehn Minuten zu einer Meldung. Sinngemäß:

template:
  - sensor:
      - name: "Batterie 2 Ladestand sicher"
        unit_of_measurement: "%"
        state: "{{ states('sensor.batterie2_ladestand') | float(0) }}"
        availability: "{{ is_number(states('sensor.batterie2_ladestand')) }}"

Ein zweites Einfrieren kam nicht vom Filter, sondern von der Integration. Die Abfragen an einen Wechselrichter liefen zeitweise ins Leere, in den schlimmsten Fenstern rund 95 Fehler in zehn Minuten. Der Wert galt dabei nicht als nicht verfügbar, er stand einfach still. Deshalb gibt es jetzt einen eigenen Sensor, der anschlägt, wenn der Ladestand länger als zehn Minuten nicht gemeldet wurde.

Kalibrierung und Entladen nach Sonnenprognose

Die Integration meldet für jede Batterie, ob eine Kalibrierung nötig ist. Laut der App des Herstellers soll die Batterie dann auf 100 Prozent geladen werden. Das macht die Steuerung jetzt selbst: Steht die Meldung an und liegt der Ladestand unter 100 Prozent, lädt sie mit bis zu 1200 W aus dem Netz, sofern die Netzladung eingeschaltet ist. Direkt nach dem Einspielen standen beide Meldungen an. Beide Batterien luden gleichzeitig, der Netzbezug lag bei 2,6 kW. Ob die Meldung nach 100 Prozent von selbst erlischt, habe ich noch nicht bestätigt.

Die zweite Neuerung betrifft das Entladen. Abends soll die Batterie nur so weit leer werden, dass der Solarüberschuss des nächsten Tages noch hineinpasst. So rechnet die Steuerung:

Überschuss   = Prognose × 0,6 − 5,5 kWh        (nie unter 0)
Untergrenze  = 100 % − Überschuss / 9,6 kWh
               mindestens 44 %, höchstens 60 %, ohne Prognose 60 %

Der Faktor 0,6 ist der Mittelwert aus gemessener Leistung und Prognose an elf Tagen, mit einzelnen Tagen zwischen 0,45 und 0,9. Die 5,5 kWh sind mein mittlerer Verbrauch zwischen 8 und 17 Uhr. Die 9,6 kWh sind beide Batterien zusammen. Die Mindestgrenze von 44 Prozent liegt bewusst über dem Start der Netzladung bei 43 Prozent. Sonst würde die Steuerung abends entladen und gleich danach wieder aus dem Netz laden.

Prognose nächster TagUntergrenze
9,3 kWh60 % (Höchstgrenze)
15 kWh60 % (Höchstgrenze)
17,6 kWh47 %
21 kWh44 % (Mindestgrenze)

Eine Schwäche kenne ich schon: Der Faktor wird nicht nachgeführt. Die Prognose überschätzt, und die gemessene Leistung ist teils gedrückt, weil die Batterien voll sind oder die Einspeisung begrenzt ist. Nach einigen Wochen schaue ich mir das wieder an.

Was bewusst ausgeschaltet bleibt

Nicht jede Schutzfunktion macht das System sicherer. Einige lasse ich mit Absicht weg.

Der alte Sicherheits-Stopp bleibt aus. Er schaltete bei einem Ladestandssprung alle Automationen ab. Der neue Stopp reagiert nur auf die Batterietemperatur über 45 °C, setzt die Sollwerte auf 0 und gibt nach fünf Minuten unter 40 °C selbst wieder frei.

Auch bei niedrigem Ladestand pausiert die Steuerung nicht. Unter 10 Prozent gibt es nur eine Meldung. Würde die Steuerung pausieren, käme auch die Netzladung nicht, also genau das, was die Batterie dann braucht.

Einen Stopp für die Gerätetemperatur gibt es nicht. Im Verlauf sah ich Werte über 45 °C und erschrak. Das war aber die Temperatur des Wechselrichters, nicht der Batterie: höchstens 46,1 °C während der Kalibrierungsladung mit 1,2 kW. Das Gerät kühlt ohne Lüfter, das Datenblatt nennt eine Umgebung bis 65 °C. Die Batterietemperatur lag in zehn Tagen bei höchstens 30 °C. Welchen Temperatursensor eine Automation liest, sollte man genau prüfen.

Der Wartungsmodus schaltet sich nicht automatisch ein. Home Assistant kennt die Firmware-Version der Wechselrichter nicht und kann ein Update daher nicht erkennen. Ich schalte den Wartungsmodus von Hand ein. Automatisch greift nur die Überwachung: Liefern Shelly oder ein Wechselrichter keine Werte, gehen die Sollwerte auf 0.

Fallen beim Einspielen

Die Konfiguration liegt in einem Git-Repository, jede Änderung läuft als Merge Request. Eingespielt wird immer gleich:

# Vorher sichern
ha backups new --name vor-aenderung

# Dateien ablegen, dann prüfen und neu starten
ha core check
ha core restart

Trotzdem lief nicht alles nach Plan:

  • Der Schalter, der die Datenbank aus dem Backup ausnehmen sollte, wurde nicht übernommen. Das Backup enthielt die 3,3 GB große Datenbank und war 1,5 GB groß. Gültig war es trotzdem.
  • Vor dem Neustart für die Filterkorrektur war der Wartungsmodus nicht eingeschaltet, weil mein Verwaltungs-Container keinen API-Zugang zu Home Assistant hatte. Die Sollwerte standen zufällig bei −2 und −75 W, es ging gut.
  • In derselben Nacht startete Home Assistant wegen einer Zertifikatsarbeit viermal neu, ebenfalls ohne Wartungsmodus. Seitdem kontrolliere ich nach jedem Neustart die Sollwerte.
  • Geplant war eine Stufe pro Woche. Die Stufen 2 bis 5 habe ich dann doch in einem Zug eingespielt. Welche Änderung welche Wirkung hat, lässt sich jetzt schlechter trennen.
  • Die Zwischensensoren habe ich aus der Aufzeichnung genommen. Ältere Dashboards zeigen für die Zielleistung deshalb keinen Verlauf mehr, nur den aktuellen Wert.

Ob sich der Umbau lohnt, ist noch offen. Vorher gingen rund 2.150 und 2.600 Befehle am Tag an die beiden Wechselrichter, Ziel sind unter 1.000. Die Tagestiefstwerte sollen nicht mehr unter 40 Prozent fallen. Die Beobachtung läuft noch, Zahlen liefere ich nach.

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht, deine IP-Adresse wird nicht gespeichert. Kommentare erscheinen erst nach Freigabe. Was mit deinen Angaben passiert, steht in der Datenschutzerklärung. Pflichtfelder sind mit * markiert.