Solar power dashboards with sonnenBatterie 10

We recently installed solar power generation with a sonnenBatterie 10 as central component, three different roof areas and two SunGrow inverters. The sonnenBatterie measures the flow to and from the grid and the flow from the two inverters towards grid, house or battery. As it contains the battery, it also knows about charge resp. discharge power. All of that is available through a REST API, with no authentication.

Below I am going to describe how I collect the relevant data and how I configured the energy dashboard and the Tesla-style solar power card.

The first step was to collect the data. There is an integration for it but I found it simpler and sufficient to configure rest sensors. That gave me some flexibility to store data as needed:

# Derived from https://www.matusz.ch/blog/2022/07/10/sonnenbatterie-in-homeassistant/
rest:
  - resource: http://sonnenbatterie/api/v2/status
    method: GET
    headers:
      User-Agent: Home Assistant
      Content-Type: application/json
    scan_interval: 10
    timeout: 15
    # It remained unclear whether unique_id is needed. It's not documented
    # as being supported, but I had weird effects when trying to remove it later.
    sensor:
      - name: Solar Power
        unique_id: solar_power
        value_template: '{{ value_json.Production_W | int }}'
        unit_of_measurement: W
        device_class: power
        state_class: measurement
      - name: Battery USOC
        unique_id: battery_usoc
        value_template: '{{ value_json.USOC | float }}'
        unit_of_measurement: '%'
        device_class: battery
        state_class: measurement
      - name: Battery RSOC
        unique_id: battery_rsoc
        value_template: '{{ value_json.RSOC | float }}'
        unit_of_measurement: '%'
        device_class: battery
        state_class: measurement
      - name: Battery Charging Power
        unique_id: battery_charging_power
        # AC Power greater than ZERO is discharging Inverter AC Power less than ZERO is charging
        value_template: '{{ [ value_json.Pac_total_W | int, 0 ] | min | abs }}'
        unit_of_measurement: W
        device_class: power
        state_class: measurement
      - name: Battery Discharging Power
        unique_id: battery_discharging_power
        # AC Power greater than ZERO is discharging Inverter AC Power less than ZERO is charging
        value_template: '{{ [ value_json.Pac_total_W | int, 0 ] | max }}'
        unit_of_measurement: W
        device_class: power
        state_class: measurement
      - name: House Consumption
        unique_id: house_consumption
        value_template: '{{ value_json.Consumption_W | int }}'
        unit_of_measurement: W
        device_class: power
        state_class: measurement
      - name: Battery SoC Energy
        unique_id: battery_soc_energy
        value_template: '{{ value_json.RemainingCapacity_Wh | int }}'
        unit_of_measurement: Wh
        device_class: energy
        state_class: total
      - name: Power From Grid
        unique_id: power_from_grid
        # Grid Feed in negative is consumption and positive is feed in
        value_template: '{{ [ value_json.GridFeedIn_W | int, 0 ] | min | abs }}'
        unit_of_measurement: W
        device_class: power
        state_class: measurement
      - name: Power To Grid
        unique_id: power_to_grid
        # Grid Feed in negative is consumption and positive is feed in
        value_template: '{{ [ value_json.GridFeedIn_W | int, 0 ] | max }}'
        unit_of_measurement: W
        device_class: power
        state_class: measurement

The energy dashboard wants energy (Wh) , not power (W), as provided by these sensors. Therefore I added integration sensors for each power sensor, for example battery_charging_energy. I did this through the UI, so it’s not in my config. I added the forecast.solar integration twice: once for the roof facing East, once for the parts facing West. With that I had enough input for the energy dashboard.

I’m not a fan of the flow diagram in that energy dashboard because I found it confusing that it visualizes the total energy in each direction as if it is flowing right now. This is where the Tesla-style dashboard comes in. It needed yet another set of sensors:

template:
  - sensor:
    # For https://github.com/reptilex/tesla-style-solar-power-card#complete-example-with-all-details
    - name: "Flow Solar to House"
      device_class: power
      state_class: measurement
      unit_of_measurement: "W"
      # Assumption: all produced power is used first for the house.
      state: >
        {{ min( int(states('sensor.house_consumption'), 0), int(states('sensor.solar_power'), 0) ) }}
    - name: "Flow Solar to Battery"
      device_class: power
      state_class: measurement
      unit_of_measurement: "W"
      # Assumption: all produced power is used first for the house, so what remains can be used for charging (but might not be used for it).
      state: >
        {{ max(0, min(int(states('sensor.battery_charging_power'), 0), int(states('sensor.solar_power'), 0) - int(states('sensor.house_consumption'), 0))) }}
    - name: "Flow Solar to Grid"
      device_class: power
      state_class: measurement
      unit_of_measurement: "W"
      # Assumption: all produced power is used first for the house, then the battery. What remains is feed to the grid.
      state: >
        {{ max(0, int(states('sensor.solar_power'), 0) - int(states('sensor.house_consumption'), 0) - int(states('sensor.battery_charging_power'), 0)) }}
    - name: "Flow Grid to Battery"
      device_class: power
      state_class: measurement
      unit_of_measurement: "W"
      # Assumption: The missing enery for charging the battery must come from the grid.
      state: >
        {{ max(0, int(states('sensor.battery_charging_power'), 0) - int(states('sensor.flow_solar_to_battery'), 0)) }}
    - name: "Flow Grid to House"
      device_class: power
      state_class: measurement
      unit_of_measurement: "W"
      # Assumption: The missing enery for the house must come first from the battery.
      state: >
        {{ max(0, int(states('sensor.house_consumption'), 0) - int(states('sensor.solar_power'), 0) - int(states('sensor.battery_discharging_power'), 0)) }}
    - name: "Flow Battery to House"
      device_class: power
      state_class: measurement
      unit_of_measurement: "W"
      # Assumption: The remaining missing enery for the house must come from the grid.
      state: >
        {{ max(0, int(states('sensor.house_consumption'), 0) - int(states('sensor.solar_power'), 0) - int(states('sensor.flow_grid_to_house'), 0)) }}
    - name: "Flow Battery to Grid"
      device_class: power
      state_class: measurement
      unit_of_measurement: "W"
      # Assumption: any unused battery power must go to the grid.
      state: >
        {{ max(0, int(states('sensor.battery_discharging_power'), 0) - int(states('sensor.flow_battery_to_house'), 0)) }}

In the UI, I added a energy_production_today_remaining sensor which is a sum of the individual forecasts. In the config, I added another template sensor:

    - name: "Netz"
      device_class: power
      state_class: measurement
      unit_of_measurement: "W"
      state: >
        {{ int(states('sensor.power_to_grid'), 0) - int(states('sensor.power_from_grid'), 0) }}
      icon: >
        {% if int(states('sensor.power_to_grid'), 0) > int(states('sensor.power_from_grid'), 0) %}
           mdi:transmission-tower-import
        {% else %}
           mdi:transmission-tower-export
        {% endif %}

Choosing the icon dynamically works when viewing it in HomeAssistant, but (unfortunately) not in the following dashboard.

Then I could add a new dashboard through the UI in raw editor mode:

views:
  - title: Home
    type: custom:tesla-style-solar-power-card
    grid_to_house_entity: sensor.flow_grid_to_house
    grid_to_battery_entity: sensor.flow_grid_to_battery
    grid_entity: sensor.netz
    generation_to_grid_entity: sensor.flow_solar_to_grid
    generation_to_battery_entity: sensor.flow_solar_to_battery
    generation_to_house_entity: sensor.flow_solar_to_house
    generation_entity: sensor.solar_power
    battery_to_house_entity: sensor.flow_battery_to_house
    battery_to_grid_entity: sensor.flow_battery_to_grid
    battery_extra_entity: sensor.battery_usoc
    battery_entity: sensor.battery_usoc
    # Can be left out: it tells me whether the house is completely locked.
    house_extra_entity: binary_sensor.gesichert
    house_entity: sensor.house_consumption
    generation_extra_entity: sensor.energy_production_today_remaining
    # Configuring appliances is optional.
    appliance1_consumption_entity: sensor.keller_plug_power
    appliance1_extra_entity: switch.keller_plug
    appliance1_icon: mdi:water-boiler
    show_gap: true
    hide_inactive_lines: 1
    # card_mod must be installed for this, can be left out.
    card_mod:
      style: |
        ha-card {
          zoom: 1.5 !important;
        }
title: Power flows

I have one water heater that is connected to a ZigBee plug ( switch.keller_plug). I am using some custom rules for turning that on only when there is sufficient solar power. I can write about that in a separate topic, if there’s interest.

Same with the inverters: I am also collecting data about each string via SunGrow, but that is not needed for these dashboards.

1 Like

Very neat an whell described! I would love to see the outcome! (https://www.screentogif.com/)

Currently is not a good time for solar power here… short days and heavy rain. Daily production is not enough for fully charging the battery and normal consumption, so the battery was empty already late last evening:

At least right now it is enough to charge the battery:

flow