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.