Nachteinspeisung in homeassistant steuern

Ich nutze die Nachteinspeisung und steuere die Einspeisung über Homeassistant abhängig von Solarprognosen und einem Zielwert, wieweit der Batteriestand in % bis zu dem Zeitpunkt sinken darf, wo die PV wieder ausreichend Strom zum Laden der Batterie liefert.

Ich habe einen Fronius Symo Gen24 und BYD HVM Batterien. Ich möchte für alle diejenigen, die das nicht schaffen, hier meine Automationen und Skripte im as-is Zustand als Vorlage einstellen, damit sie sich leichter tun. Jeder kann sie verwenden und nach seinen Wünschen anpassen, ich leiste aber keinerlei Haftung für eventuelle Folgen. Die Steuerung des Fronius passiert über modbus. Das ist ein wenig knifflig. Wer das verwenden will, sollte genau die angegebene Dokumentation studieren. Natürlich kann jeder seine eigene Nicht-Fronius Anlage programmieren, ich brauche im wesentlichen für meine Automation 2 Funktionen:

  1. Zwangsentladung mit vorgegebenen nnnn Watt. und

  2. Rücksetzen auf Normalzustand.

DIe Automationen im Detail:

alias: BYD Nacheinspeisesteuerung
description: >+
  Nachteinspeisungssteuerung für Fronius Symo Gen24 + BYD HVM.

  Läuft von März bis Oktober. Berechnet um 15:00 die nächsten Start/Ende-Zeiten
  und startet basierend darauf das BYD_Nachteinspeisung script zum
  Ein/Ausschalten der Nachteinspeisung. Die Regelung und Neuberechnung der
  Einspeiseleistung erfolgt dann alle 5 Minuten durch die BYD_Nachteinspeisung
  Automatisierung.

  Benötigte Helper, die zu definieren sind:

  input_number.byd_nachteinspeisung_vorgabe: Bis zu wechem Prozentsatz die
  Batterie entladen werden darf bi PV Ladestrom liefert.

  sensor.byd_nachteinspeisung_total: Utility meter: Summe bisher eingespeist

  sensor.byd_nachteinspeisung_verbrauch: Utility meter: Summe bisheriger
  Eigenverbrauch zur Schätzung des Stundenverbrauchs bis PV liefert.

  input_datetime.byd_nachteinspeisung_start: Nächster Startzeitpunkt 

  input_datetime.byd_nachteinspeisung_end: Nächster Endzeitpunkt 

  input_datetime.byd_nachteinspeisung_last_start: Letzter Startzeitpunkt 

  input_boolean.byd_nachteinspeisung: Schalter: Nachteinspeisung läuft

  input_number.byd_discharge_limit: Aktuelle Batterieentladungsvorgabe in Watt

triggers:
  - at: "06:00:00"
    id: sicherheitsstop
    trigger: time
  - at: "15:00:00"
    id: Settime
    trigger: time
  - trigger: time
    at: input_datetime.byd_nachteinspeisung_start
    id: an
  - trigger: time
    at:
      entity_id: input_datetime.byd_nachteinspeisung_ende
      offset: "00:05:00"
    id: aus
conditions:
  - alias: Nur von März bis Oktober
    condition: or
    conditions:
      - condition: trigger
        id:
          - aus
          - sicherheitsstop
          - Settime
      - condition: and
        conditions:
          - condition: trigger
            id:
              - an
          - alias: Wenn es März bis Oktober ist
            condition: template
            value_template: "{{ 3 <= now().month <= 10 }}"
    enabled: true
actions:
  - choose:
      - conditions:
          - condition: trigger
            id:
              - sicherheitsstop
              - Settime
        sequence:
          - action: script.nachteinspeisung
            metadata: {}
            data:
              startstop: stop
          - action: input_datetime.set_datetime
            data:
              datetime: >
                {# 1. Dusk holen, 30 Min addieren und dann 1h für das
                "Aufrunden" #}

                {% set t = state_attr('sun.sun', 'next_dusk') | as_datetime |
                as_local + timedelta(hours=1) %}

                {# 2. Abrunden auf die volle Stunde #}

                {% set t = t.replace(minute=0, second=0, microsecond=0) %}

                {# 3. Maximum aus berechneter Stunde und 20 ermitteln #} 

                {% if t < today_at("20:00") %} {% set t = today_at("20:00")  %}
                {% endif %}

                {{ t }}
            target:
              entity_id: input_datetime.byd_nachteinspeisung_start
        alias: Sicherheitshalber ein 2. Stop um 6:00 Uhr
      - conditions:
          - condition: trigger
            id: an
        sequence:
          - action: script.nachteinspeisung
            metadata: {}
            data:
              startstop: start
        alias: Nachteinspeisung einschalten
      - conditions:
          - condition: trigger
            id: aus
        sequence:
          - action: script.nachteinspeisung
            metadata: {}
            data:
              startstop: stop
        alias: Nachteinspeisung abschalten
mode: parallel
  
alias: BYD Nachteinspeisung update
description: >-
  Läuft alle 5 Minuten und passt die Entladerate der Batterie aufgrund des
  gemessenen bisherigen Einspeisungsverlaufs und des gemessenen Eigenverbrauchs
  an, sodass in der geplanten Entladezeit die gewünschte Einspeisung erzielt
  wird.

  Steuerung durch Vorgabe des Grenzwertes, bis zu dem die Batterie entladen
  werden soll. Eingespeist wird nur, wenn die Prognosen erwarten lassen, dass am
  nächsten Tag die Batterie wieder zu 100% aufgeladen werden kann.

  Prognosen: Solcast und Solar Forecast ML Integrationen

  PV-Steuerung: über modbus an Fronius Symo Gen24 + BYD HVM Batterien (
  BYD_forced_discharge und BYD_reset_charging_default scripts , Doku dazu siehe
  https://www.libe.net/byd-modbus )
triggers:
  - minutes: /5
    trigger: time_pattern
conditions:
  - condition: state
    entity_id: input_boolean.byd_nachteinspeisung
    state: "on"
actions:
  - variables:
      time: "{{ now().strftime('%H:%M') }}"
      wettervorsorge: |
        {# Abzug für unerwartete Wetterverschlechterung #}
        {% set wv = 10000 %} {{ wv }}
      batteriekap: |
        {# Nettokapazität der PV Batterie gesamt in Watt #} 40000
      eigenverbr: |
        {# Geschätzter Eigenverbrauch in der Nacht #}
        {% set eigenverbr = 6000 %} {{ eigenverbr }}
      normverbrauch: |
        {# Erstwert für stündlichen Eigenverbrauch #} 300
      forecast_ml: >
        {# Solar Forecast ML Ertragsprognose heute/morgen #} {% if now().hour >=
        16 %}   {{ states('sensor.solar_forecast_ml_forecast_tomorrow') |
        float(0) }} {% else %} {{
        states('sensor.solar_forecast_ml_expected_daily_production') | float(0)
        }}  {% endif %}   
      solcast: >
        {# solcast Ertragsprognose heute/morgen #} {% if now().hour >= 16 %}  {{
        states('sensor.solcast_pv_forecast_forecast_tomorrow') | float(0) }} {%
        else %} {{ states('sensor.solcast_pv_forecast_forecast_today') |
        float(0) }} {% endif %} 
      ertragsprognose: >
        {# Minimum von 2 Vorhersagen für PV-Ertrag abzgl. wettervorsorge #}  {{ 
        ( min(solcast, forecast_ml) * 1000 - wettervorsorge ) | int(0) }}
      batterie: >
        {# aktueller Ladezustand aus Photovoltaiksystem #}

        {{ states('sensor.byd_battery_box_premium_hv_state_of_charge') |
        round(0) }}
      grenzwert: >
        {# Grenzwert, bis zu dem die Batterie entladen werden darf #}  {{
        max(50, (100 - states('input_number.byd_nachteinspeisung_vorgabe') | int
        )) | int }}
      usable: |
        {# Maximal mögliche Einspeisung in Watt, bis Grenzwert erreicht ist #}
        {{ max( 0, ( batterie - grenzwert ) * batteriekap / 100 ) | round(0) }}
      start_dt: >
        {# Startdatum und Zeit der aktuellen Nachteinspeisung #} {% set s =
        states('input_datetime.byd_nachteinspeisung_start') %} {{ as_datetime(s)
        if as_datetime(s) is not none else now() }}
      end_dt: >
        {# Endedatum und Zeit der aktuellen Nachteinspeisung #} {% set s =
        states('input_datetime.byd_nachteinspeisung_ende') %} {{ as_datetime(s)
        if as_datetime(s) is not none else now() + timedelta(hours=8) }}
      lade_dt: >
        {# Datum und Zeit, wenn wieder hinreichend PV zum Laden der Batterie
        vorhanden ist, setze 2 Stunden nach Dawn #} {% set s =
        states('sensor.sun_next_dawn') %} {{ as_datetime(s) + timedelta(hours=2)
        }}
      rest_h: >
        {# Restzeit auf end_dt in Std. (float), um entladewert zu kalkuleren #} 
        {{ max(0, (as_datetime(end_dt) | as_local - now()).total_seconds() /
        3600) | round(5) }}
      lade_h: >
        {# Restzeit, bis wieder genügend Ladung verfügbar ist #} {{ max(0,
        (as_datetime(lade_dt) | as_local - now()).total_seconds() / 3600) }}
      verbrauch: >
        {# Errechnen Eigenverbrauch pro Stunde aus Utility meter Verbrauch seit
        start_dt #} {% set s_obj = as_datetime(start_dt) %}  {% set h = (now() -
        s_obj | as_local).total_seconds() / 3600 %} {% set val =
        states('sensor.byd_nachteinspeisung_verbrauch') | float(0) %} {% if h <
        0.1 %} {{ normverbrauch }} {% else %} {{ ( val / h ) | int }} {% endif
        %}
      verbrauchsprognose: >
        {# Fortschreibung aktueller Verbrauch bis lade_dt, um nicht am Ende noch
        Verbrauch vom Netz zu erzeugen #} {{ verbrauch * lade_h | int }}
      ziel: >
        {# Restliche Einspeisung gesamt in Watt #} {{ usable -
        verbrauchsprognose | round(0) }}
      bisher: |
        {# Utility meter: bisher eingespeist in Watt seit start_dt #}
        {{ states('sensor.byd_nachteinspeisung_total') | int }}
      restmenge: "{{ max(0, ziel) | int }}"
      entladewert: >
        {# Batterieentladung in Watt: restmenge / reststunden + Eigenverbrauch
        #}

        {% set h = rest_h | float(0) %} {% if h > 0.05 and restmenge > 0 %}

        {{ ((restmenge / h) | round(0) + ( verbrauch | int ) ) | int }}

        {% else %} 0 {% endif %}
      fertig: >
        {# Bedingungen zum vorzeitigen Stop der Einspeisung: #} {# wenn
        Ladestand bis lade_dt unter Grenzwert sinken würde #} {% if batterie  -
        verbrauchsprognose * 100 / batteriekap <= grenzwert %} true  {# wenn 
        bereits der Planwert eingespeist ist #} {% elif restmenge < 0 %} true 
        {# wenn der zu setzende Entladewert negativ wird #} {% elif entladewert
        <= 0 %} true {# wenn die zeit abgelaufen ist #}  {% elif now() >=
        as_datetime(end_dt) | as_local %} true  {# wenn der prognostizierte
        Ertrag zu niedrig ist #} {% elif ertragsprognose < usable +
        verbrauchsprognose + wettervorsorge %} true  {% else %} false {%endif %}
  - if:
      - condition: template
        value_template: |
          {{ states('input_boolean.byd_nachteinspeisung') == 'on' }}
        alias: If byd nachteinspeisung is on
    then:
      - if:
          - alias: If fertig = true
            condition: template
            value_template: "{{ fertig }}"
        then:
          - action: input_boolean.turn_off
            metadata: {}
            target:
              entity_id: input_boolean.byd_nachteinspeisung
            data: {}
          - action: script.nachteinspeisung
            metadata: {}
            data:
              startstop: stop
            enabled: true
        else:
          - action: input_number.set_value
            target:
              entity_id: input_number.byd_discharge_limit
            data:
              value: |
                {{ entladewert | int }}
          - action: script.1751097291791
            metadata: {}
            data: {}
            enabled: true
    alias: Nur wenn Nachteinspeisung läuft
  - action: persistent_notification.create
    data:
      title: BYD Nachteinspeisung
      message: |
        BYD Nachteinspeisung letzte Werte: 
        Prognose forecast_ml: {{ forecast_ml }} kWh
        Prognose solcast: {{ solcast }} kWh
        Minimumprognose abzgl. Reserve: {{ ertragsprognose }} Wh
        Batterieladung aktuell: {{ batterie }}%
        Entladen bis Genzwert: {{ grenzwert }}%
        Aktueller Stundenverbrauch {{ verbrauch }} Wh
        Prognose bis Ladestart: {{ verbrauchsprognose }} Wh
        Nutzbare Bruttokapazität: {{ usable }} Wh
        Einspeisung geplant: {{ ziel }} Wh
        Offene Restmenge: {{ restmenge }} Wh
        Restzeit: {{ rest_h }} Stunden
        Bisher eingespeist: {{ bisher }} Wh
        Entladewert gesetzt: {{ entladewert }} W
        Einspeisung ist fertig: {{ fertig }}
      notification_id: eeg_data_fromto
mode: restart

Skripte:

Alles nach dem ersten script ist Fronius/BYD spezifisch !

sequence:
  - variables:
      starter: "{{startstop}}"
      wettervorsorge: |
        {# Abzug für unerwartete Wetterverschlechterung #}
        {% set wv = 5 %} {{ wv }}
      eigenverbr: |
        {# Geschätzter Eigenverbrauch in der Nacht #}
        {% set eigenverbr = 6 %} {{ eigenverbr }}
      normverbrauch: |
        {# Erstwert für stündlichen Eigenverbrauch #} 300
      ertrag: >
        {# Minimum von 2 Vorhersagen für PV- Ertrag morgen abzgl. wettervorsorge
        #} {% set ertrag =
        min(states('sensor.solcast_pv_forecast_forecast_tomorrow') | round(1), 
        states('sensor.solar_forecast_ml_forecast_tomorrow') | round(1) )  -
        wettervorsorge %} {{ ertrag }}
      batterie: >
        {# Nutzbare Batteriekapazität abzgl. 50% Reserve für Blackout #} {% set
        grenze = 50 %}  {# Entladebegenzung 50% #}  {% set bat = max(
        states('sensor.byd_battery_box_premium_hv_state_of_charge') | round(0) -
        grenze , 0 )  %}   {{ bat }}
      kwmax: >
        {# Maximal nutzbare Batteriekapazität in kw - eigenverbrauch #} {% set
        kap = 40.0 %}  {# Batterie netto 40kw * nutzbare Prozent - eigenverbr #}
        {% set kwmax = max( ( batterie * kap / 100 - eigenverbr) , 0) | float(0)
        | round(3) %} {{ kwmax }}
      usable: >
        {# Nutzbare Kapazität in kw für Einspeisung für heute nacht #} {% if
        ertrag > eigenverbr %} {% set usable = min( ertrag - eigenverbr, kwmax )
        %}  {% else %} {% set usable = 0 %} {% endif %} {{ usable }}
      verwendbar: |
        {{ usable * 1000 | round(0) }} {# in watt #}
  - if:
      - alias: If parameter = "start"
        condition: template
        value_template: "{{ starter == \"start\" }}"
    then:
      - action: input_datetime.set_datetime
        metadata: {}
        target:
          entity_id: input_datetime.byd_nachteinspeisung_last_start
        data:
          datetime: "{{ now() }}"
      - action: input_datetime.set_datetime
        data:
          datetime: |
            {{ now() }}
        target:
          entity_id: input_datetime.byd_nachteinspeisung_start
      - action: input_datetime.set_datetime
        data:
          datetime: >-
            {# 1. Dawn holen, 30 Min addieren und dann 1h für das "Aufrunden" #}
            {% set t = state_attr('sun.sun', 'next_dawn') | as_datetime |
            as_local - timedelta(minutes=30) %} {# 2. Abrunden auf die volle
            Stunde #} {% set t = t.replace(minute=0, second=0, microsecond=0) %}
            {{ t }}
        target:
          entity_id: input_datetime.byd_nachteinspeisung_ende
      - action: input_number.set_value
        metadata: {}
        target:
          entity_id: input_number.byd_discharge_limit
        data:
          value: |
            {{ 1500 }}
        enabled: true
      - action: script.1751097291791
        metadata: {}
        data: {}
        enabled: true
      - action: input_boolean.turn_on
        metadata: {}
        target:
          entity_id: input_boolean.byd_nachteinspeisung
        data: {}
        enabled: true
      - action: utility_meter.calibrate
        metadata: {}
        target:
          entity_id: sensor.byd_nachteinspeisung_total
        data:
          value: "0"
      - action: utility_meter.calibrate
        metadata: {}
        target:
          entity_id: sensor.byd_nachteinspeisung_verbrauch
        data:
          value: "0"
      - action: input_number.set_value
        metadata: {}
        target:
          entity_id: input_number.byd_nachteinspeisung_vorgabe
        data:
          value: 50
      - action: chime_tts.say
        metadata: {}
        data:
          volume_level: 1
          audio_conversion: Volume 150%
          join_players: false
          unjoin_players: false
          chime_path: /media/sounds/custom/light_tone.mp3
          message: >-
            Die Nachteinspeisung wird gestartet. Erwarteter Ertrag für morgen
            ist {{ ertrag }} Kilowatt, die Batterie ist zu {{ 
            states('sensor.byd_battery_box_premium_hv_state_of_charge') }}
            Prozent geladen.

            Verwendbar für Nachteinspeisung sind {{ usable | round(1) }}
            Kilowatt.
        target:
          entity_id: media_player.media_player_nest
    else:
      - action: script.byd_reset_charging
        metadata: {}
        data: {}
      - action: input_boolean.turn_off
        metadata: {}
        target:
          entity_id: input_boolean.byd_nachteinspeisung
        data: {}
alias: BYD Nachteinspeisung
description: ""
fields:
  startstop:
    selector:
      text: null
    name: Startstop
    required: true

alias: BYD Forced Discharge
sequence:
  - data:
      slave: 1
      address: 40348
      hub: gen24
      value: 3
    action: modbus.write_register
  - data:
      address: 40356
      slave: 1
      hub: gen24
      value: >-
        {{ 65536 - (states('input_number.byd_discharge_limit')|int(0) * 10000 /
        states('sensor.reading_battery_settings').split(',')[0]|int(1) ) | int
        }}
    action: modbus.write_register
  - data:
      address: 40355
      slave: 1
      hub: gen24
      value: 10000
    action: modbus.write_register
mode: single
icon: mdi:home-battery
description: >-
  "Set 40348 Inout mode, 40355 forced discharge %, 40356 negative forced charge
  %  from input number byd_discharge_limit"

  Doku: https://www.libe.net/byd-modbus

alias: BYD Reset charging default
sequence:
  - data:
      slave: 1
      address: 40348
      value: 0
      hub: gen24
    action: modbus.write_register
  - data:
      address: 40355
      slave: 1
      value: 10000
      hub: gen24
    action: modbus.write_register
  - data:
      slave: 1
      address: 40350
      value: 500
      hub: gen24
    action: modbus.write_register
  - data:
      address: 40356
      slave: 1
      value: 10000
      hub: gen24
    action: modbus.write_register
mode: single
icon: mdi:home-battery
description: >-
  "Set 40348 automatic Mode, 40355 100% Max charge, 40356 100% Max discharge and
  40350 5% residual battery capacity"

  Doku: https://www.libe.net/byd-modbus

configuration.yaml modbus Eintrag ( erstellt Voraussetzungen für modbus Zugriff von homeassistant aus ) Bitte unbedingt die Dokumentation lesen. Die Fronius Anlage muss konfiguriert werden !

modbus:
  - type: tcp
    # Put your Gen24 IP address here
    host: 10.0.0.111
    port: 502
    name: gen24
    sensors:
      - name: reading_battery_settings
        unique_id: BYD_reading_battery_settings
        slave: 1
        count: 24
        address: 40345
        scan_interval: 15
        data_type: custom
        structure: ">10H2h4H8h"
#       > big endian, H unsigned, h signed Halfword

Die für Modbus zu setzenden Werte im Fronius menü findet ihr in der Anleitung: Fronius & BYD Akku über Modbus steuern, Home Assistant Ich verwende die Einstellungen SunSpec Model Type: „int + SF“.

Gutes Gelingen

11 „Gefällt mir“

Habe ich vergessen zu erwähnen: in der Doku steht auch, wie die in den BYD-spezifischen Skripten verwendeten Template-Variablen zu definieren sind:

Hi, danke :slight_smile:

Für Fronius Gen24, gibt es eine HACS Integration “Fronius Modbus“ die ich auch benutze.
Mann kann damit sehr viele Daten auslesen und steuern.

Eventuell sparst du dir mit der etwas Programmieraufwand.
Habe bei mir mal Programmiert das er morgens und Abends bevorzugt einspeist wenn die Produktion mittags für die Akkuladung reicht. Leider kann man den Ohmpilot nicht beeinflussen.

Die Nachtentladung kommt bei mir auch noch :slight_smile:

SG
Wolfgang

1 „Gefällt mir“