Fronius netzladung

Seit Jahren versuche ich eine sinnvolle Implementierung einer über HA gesteuerten Netzladung meines PV Akkus umzusetzen. Mit der Unterstützung von Claude endlich geschafft. Hier die Details:

  • Fronius Symo Gen24 10.0 Wechselrichter
    (wichtig: dieser hat die Modbus Schnittstelle natürlich aktiv und den “SunSpec Model Type” auf “float” gesetzt.
  • BVD Akku

Hier mal vorweg die Ansicht im Dashboard:

Hier die Modbus Definition für die z.B. configuration.yaml

modbus:
  - name: gen24
    type: tcp
    host: X.X.X.X
    port: 502

    sensors:
      - name: "GEN24 AC Power"
        slave: 1
        address: 40083
        input_type: holding
        data_type: float32
        precision: 0
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement

      - name: "GEN24 AC Energy Total"
        slave: 1
        address: 40093
        input_type: holding
        data_type: float32
        precision: 0
        unit_of_measurement: "Wh"
        device_class: energy
        state_class: total_increasing

      - name: "GEN24 DC Power"
        slave: 1
        address: 40101
        input_type: holding
        data_type: float32
        precision: 0
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement

      - name: "Battery StorCtl Mod"
        slave: 1
        address: 40358
        input_type: holding
        data_type: uint16

      - name: "Battery MinRsvPct"
        slave: 1
        address: 40360
        input_type: holding
        data_type: uint16
        scale: 0.01
        precision: 1
        unit_of_measurement: "%"

      - name: "Battery ChaSt"
        slave: 1
        address: 40364
        input_type: holding
        data_type: uint16

      - name: "Battery OutWRte"
        slave: 1
        address: 40365
        input_type: holding
        data_type: int16
        scale: 0.01
        precision: 1
        unit_of_measurement: "%"

      - name: "Battery InWRte"
        slave: 1
        address: 40366
        input_type: holding
        data_type: int16
        scale: 0.01
        precision: 1
        unit_of_measurement: "%"

      - name: "Battery ChaGriSet"
        slave: 1
        address: 40370
        input_type: holding
        data_type: uint16

Automations, Scripts, etc. habe ich in einem eigenen fronius.yaml. Code wie folgt:

# packages/fronius.yaml
# Fronius Symo GEN24 — battery grid charge control
#
# Confirmed register addresses (firmware 1.39.5-1, float model):
#   StorCtl_Mod  → address 40358 (register 40359)  bitfield16: bit0=charge, bit1=discharge
#   MinRsvPct    → address 40360 (register 40361)  uint16, scale -2 (10000=100%, 2000=20%)
#   OutWRte      → address 40365 (register 40366)  int16,  scale -2 (10000=100%, -10000=-100%)
#   InWRte       → address 40366 (register 40367)  int16,  scale -2 (10000=100%)
#   ChaGriSet    → address 40370 (register 40371)  enum16: 0=PV only, 1=grid allowed
#
# Prerequisites (requires Technician password in GEN24 web UI):
#   Communication → Modbus → "Inverter control via Modbus" → ON
#   Device config → Components → Battery → "Battery charging from DNO grid" → ON

input_boolean:
  grid_charging_active:
    name: "Grid charging active"
    icon: mdi:battery-charging

input_number:
  grid_charge_target_soc:
    name: "Grid charge target SOC"
    min: 20
    max: 100
    step: 5
    unit_of_measurement: "%"
    icon: mdi:battery-charging-80

  grid_charge_power:
    name: "Grid charge power"
    min: 10
    max: 100
    step: 5
    unit_of_measurement: "%"
    icon: mdi:lightning-bolt

  grid_charge_normal_reserve:
    name: "Normal battery reserve"
    min: 0
    max: 50
    step: 5
    initial: 20
    unit_of_measurement: "%"
    icon: mdi:battery-low

script:
  fronius_start_grid_charge:
    alias: "Fronius: Start grid charge"
    description: "Force BYD battery to charge from grid up to target SOC"
    icon: mdi:battery-charging
    sequence:
      # 1) Allow grid charging (ChaGriSet = 1)
      - service: modbus.write_register
        data:
          hub: gen24
          slave: 1
          address: 40370
          value: [1]

      # 2) Set MinRsvPct to target SOC — forces inverter to charge up to this level
      #    Scale -2: value = target_soc × 100
      - service: modbus.write_register
        data:
          hub: gen24
          slave: 1
          address: 40360
          value:
            - "{{ (states('input_number.grid_charge_target_soc') | int * 100) | int }}"

      # 3) Set InWRte to charge power % (max charge rate)
      #    Scale -2: value = pct × 100
      - service: modbus.write_register
        data:
          hub: gen24
          slave: 1
          address: 40366
          value:
            - "{{ (states('input_number.grid_charge_power') | int * 100) | int }}"

      # 4) Set OutWRte to negative charge power % — forces full charging window
      #    Negative OutWRte shifts the power window into charging territory
      #    This is what triggers "Forced Recharge" mode at full power
      - service: modbus.write_register
        data:
          hub: gen24
          slave: 1
          address: 40365
          value:
            - "{{ (65536 - (states('input_number.grid_charge_power') | int * 100)) | int }}"

      # 5) Activate both charge and discharge limits (StorCtl_Mod = 3, bits 11)
      - service: modbus.write_register
        data:
          hub: gen24
          slave: 1
          address: 40358
          value: [3]

      # 6) Set active flag
      - service: input_boolean.turn_on
        target:
          entity_id: input_boolean.grid_charging_active

  fronius_stop_grid_charge:
    alias: "Fronius: Stop grid charge"
    description: "Return battery to normal automatic mode"
    icon: mdi:battery-auto
    sequence:
      # 1) Return StorCtl_Mod to auto (0)
      - service: modbus.write_register
        data:
          hub: gen24
          slave: 1
          address: 40358
          value: [0]

      # 2) Reset MinRsvPct to normal reserve
      #    Scale -2: value = reserve × 100
      - service: modbus.write_register
        data:
          hub: gen24
          slave: 1
          address: 40360
          value:
            - "{{ (states('input_number.grid_charge_normal_reserve') | int * 100) | int }}"

      # 3) Reset OutWRte to +100%
      - service: modbus.write_register
        data:
          hub: gen24
          slave: 1
          address: 40365
          value: [10000]

      # 4) Reset InWRte to 100%
      - service: modbus.write_register
        data:
          hub: gen24
          slave: 1
          address: 40366
          value: [10000]

      # 5) Clear active flag
      - service: input_boolean.turn_off
        target:
          entity_id: input_boolean.grid_charging_active

automation:
  - id: fronius_auto_stop_at_target_soc
    alias: "Fronius: Auto-stop grid charge at target SOC"
    description: "Stop charging from grid once battery reaches target SOC"
    trigger:
      - platform: numeric_state
        entity_id: sensor.byd_battery_box_premium_hv_ladezustand
        above: input_number.grid_charge_target_soc
    condition:
      - condition: state
        entity_id: input_boolean.grid_charging_active
        state: "on"
    action:
      - service: script.fronius_stop_grid_charge
      - service: persistent_notification.create
        data:
          title: "Grid charge complete"
          message: >
            Battery reached {{ states('sensor.byd_battery_box_premium_hv_ladezustand') | round(0) }}% —
            grid charging stopped automatically.
    mode: single

  - id: fronius_grid_charge_safety_timeout
    alias: "Fronius: Grid charge safety timeout"
    description: "Failsafe — stop grid charging after 4 hours regardless of SOC"
    trigger:
      - platform: state
        entity_id: input_boolean.grid_charging_active
        to: "on"
        for:
          hours: 4
    action:
      - service: script.fronius_stop_grid_charge
      - service: persistent_notification.create
        data:
          title: "Grid charge timeout"
          message: "Grid charging stopped after 4-hour safety limit."
    mode: single

Und zum Schluss den Code fürs Dashboard. Kann natürlich jeder machen wie er will :wink:

title: Fronius Battery
views:
  - title: Battery
    path: battery
    icon: mdi:battery-charging
    cards:
      - type: vertical-stack
        cards:
          - type: custom:mushroom-template-card
            primary: Akkuladung aus dem Netz
            secondary: |
              {% if is_state('input_boolean.grid_charging_active', 'on') %}
                Charging from grid · {{ states('sensor.byd_battery_box_premium_hv_ladezustand') | round(0) }}%
              {% else %}
                {% set st = states('sensor.battery_chast') | int(0) %}
                {% if st == 2 %}Entladen
                {% elif st == 3 %}Laden von PV
                {% elif st == 4 %}Voll geladen
                {% elif st == 5 %}Halten
                {% elif st == 6 %}Leerlauf
                {% else %}Auto mode
                {% endif %} · {{ states('sensor.byd_battery_box_premium_hv_ladezustand') | round(0) }}%
              {% endif %}
            icon: |
              {% if is_state('input_boolean.grid_charging_active', 'on') %}
                mdi:transmission-tower
              {% else %}
                mdi:battery-auto
              {% endif %}
            badge_icon: |
              {% if is_state('input_boolean.grid_charging_active', 'on') %}
                mdi:lightning-bolt
              {% endif %}
            badge_color: amber
            tap_action:
              action: none
            color: |
              {% if is_state('input_boolean.grid_charging_active', 'on') %}
                amber
              {% else %}
                green
              {% endif %}
            features_position: bottom
          - type: custom:gauge-card-pro
            entity: sensor.byd_battery_box_premium_hv_ladezustand
            segments:
              - pos: 0
                color: red
              - pos: 25
                color: '#FFA500'
              - pos: 50
                color: rgb(255, 255, 0)
              - pos: 100
                color: var(--green-color)
            needle: true
            gradient: true
            titles:
              primary: BYD Batterie Ladezustand (SOC)
            gradient_resolution: auto
            min_indicator:
              type: number
              value: 20
              color: red
              opacity: 0
          - type: entities
            title: Einstellungen
            entities:
              - entity: input_number.grid_charge_target_soc
                icon: mdi:battery-charging-80
                name: Ziel SOC
              - entity: input_number.grid_charge_power
                icon: mdi:lightning-bolt
                name: Max. Ladeleistung
              - entity: input_number.grid_charge_normal_reserve
                icon: mdi:battery-low
                name: Standard Reserve SOC
          - type: horizontal-stack
            cards:
              - type: custom:mushroom-template-card
                primary: Start
                secondary: Netzladung
                icon: mdi:play-circle-outline
                tap_action:
                  action: call-service
                  service: script.fronius_start_grid_charge
                hold_action:
                  action: none
                color: amber
                features_position: bottom
              - type: custom:mushroom-template-card
                primary: Stop
                secondary: Automatikmodus
                icon: mdi:stop-circle-outline
                tap_action:
                  action: call-service
                  service: script.fronius_stop_grid_charge
                hold_action:
                  action: none
                color: green
                features_position: bottom
          - type: entities
            title: Modbus Stati
            show_header_toggle: false
            entities:
              - entity: sensor.battery_storctl_mod
                name: StorCtl_Mod
                icon: mdi:cog
              - entity: sensor.battery_inwrte
                name: Charge rate (InWRte)
                icon: mdi:battery-charging
              - entity: sensor.battery_chagriset
                name: Grid charge allowed (ChaGriSet)
                icon: mdi:transmission-tower
              - entity: input_boolean.grid_charging_active
                name: Grid charging active flag
                icon: mdi:flag

Finally: Ich bin noch am Optimieren. Es ist auch noch eine Teil in EN und ein Teil in DE. Muss ich auch noch bereinigen. Aber: Es hat heute bereits tadellos funktioniert.

Grüße
C