Sonnen does not allow access to the sonnenCharger without a login and password, which it does not make public. However, access via Modbus (port 502) is possible. Here I describe how I have implemented this in Home Assistant (tested with version 2024.5).
Reading and writing values in the wallbox is done via register addresses. A list of the registers and their meaning can be found at ETREL:
[https://landisgyr-evsolutions.atlassian.net/wiki/spaces/Home/pages/2236121092/Modbus+Communication+with+Inch+products]
I have created the following file modbus.yaml and called it via “modbus: !include modbus.yaml” in config.yaml.
My modbus.yaml file:
- name: sonnenCharger
type: tcp
host: <IP of your wallbox>
port: 502
sensors:
- name: charge_status_int
address: 0
input_type: input
data_type: int16
- name: no_of_phases
address: 1
input_type: input
data_type: int16
- name: active_power
address: 26
input_type: input
data_type: float32
device_class: power
state_class: measurement
unit_of_measurement: kW
precision: 2
- name: session_energy
address: 30
input_type: input
scan_interval: 10
data_type: float32
device_class: energy
state_class: total_increasing
unit_of_measurement: kWh
- name: session_duration
address: 32
input_type: input
data_type: int64
unit_of_measurement: s
- name: departure_time_unix
address: 36
input_type: input
data_type: int64
unit_of_measurement: s
- name: serial_number
address: 990
input_type: input
data_type: string
count: 10
- name: model
address: 1000
input_type: input
data_type: string
count: 10
- name: HW_version
address: 1010
input_type: input
data_type: string
count: 5
- name: SW_version
address: 1015
input_type: input
data_type: string
count: 5
The values are then available as sensors in Home Assistant. Here some examples in my file sensors.yaml:
- platform: template
sensors:
wb_active_power:
unique_id: "wb_active_power"
value_template: >-
{% if (states('sensor.active_power') | float) > 0 %}
{{(states('sensor.active_power') | float)}}
{% else %}
{{ 0.0 }}
{% endif %}
- platform: integration
source: sensor.wb_active_power
name: i_wallbox_total_energy
method: right
round: 2
- platform: template
sensors:
wallbox_total_energy:
unique_id: "wallbox_total_energy"
friendly_name: "Wallbox gesamt geladenen Energie"
value_template: >-
{% set number = (states('sensor.i_wallbox_total_energy') | float) %}
{{number}}
device_class: energy
wallbox_session_duration:
unique_id: "wallbox_session_duration"
friendly_name: "Dauer"
value_template: >-
{% set uptime = states("sensor.session_duration") | int %}
{% set hours = (uptime % 86400) // 3600 %}
{% set minutes = (uptime % 3600) // 60 %}
{% set seconds = (uptime % 60) %}
{{ '{:02} Std {:02} Min'.format(hours, minutes) }}
wallbox_departure_time:
unique_id: "wallbox_departure_time"
friendly_name: "Abfahrtszeit in der Wallbox"
value_template: >-
{% set departure = as_datetime(as_datetime(states('sensor.departure_time_unix')) | as_local).strftime("%a. den %d.%m.%Y um %H:%M") %}
{{departure}}
For the integration it is important to use the method “right”, because the value in active_power of the last charge is still in the register (on the left, so to speak).
The sensors can now be displayed as cards on the dashboard. Here is an excerpt from my vertical-stack where two cards are only shown when they make sense:
- type: markdown
title: Wallbox
content: >-
<h3> {% if states('sensor.charge_status_int') == '1' %} <ha-alert
alert-type="info">Wallbox bereit</ha-alert> {% elif
states('sensor.charge_status_int') == '2' %} <ha-alert
alert-type="info">Warten auf Verbindung zum Auto</ha-alert> {% elif
states('sensor.charge_status_int') == '3' %} <ha-alert
alert-type="info">Warten, dass Laden startet</ha-alert> {% elif
states('sensor.charge_status_int') == '4' %} <ha-alert
alert-type="success">Auto lädt seit:
{{states('sensor.wallbox_session_duration')}}</ha-alert> {% elif
states('sensor.charge_status_int') == '5' %} <ha-alert
alert-type="info">Auto pausiert Laden</ha-alert> {% elif
states('sensor.charge_status_int') == '6' %} <ha-alert
alert-type="info">Wallbox pausiert Laden</ha-alert> {% elif
states('sensor.charge_status_int') == '7' %} <ha-alert
alert-type="info">Laden beendet</ha-alert> {% elif
states('sensor.charge_status_int') == '8' %} <ha-alert
alert-type="alert">Systemfehler</ha-alert> {% elif
states('sensor.charge_status_int') == '9' %} <ha-alert
alert-type="success">Laden wird fortgesetzt</ha-alert> {% elif
states('sensor.charge_status_int') == '10' %} <ha-alert
alert-type="alert">Nicht verfügbar</ha-alert> {% else %} <ha-alert
alert-type="alert">Ststus unbekannt</ha-alert> {% endif %} </h3>
<small>Software-Version {{states('sensor.sw_version')}}, Hardware-Version
{{states('sensor.hw_version')}}</small>
- type: conditional
conditions:
- condition: numeric_state
entity: sensor.charge_status_int
above: 3
below: 7
card:
type: vertical-stack
cards:
- type: sensor
name: Leistung
entity: sensor.active_power
graph: line
detail: 2
min: 0
max: 11.1
- type: entity
name: aktuell geladenen Energie
icon: mdi:ev-station
entity: sensor.session_energy
- type: entity
entity: sensor.wallbox_total_energy
name: gesamte geladenen Energie
icon: mdi:ev-station
unit: kWh
You can also write values to the wallbox. This is particularly interesting if you want to charge the car with the PV system over several days. The departure time is saved as a UTC Unix timestamp in the box. Here is my automation, which reads the set time from helper input_datetime.departure_time and writes it to the box when triggered by the button input_boolean.wallbox_set_time. The timestamp must be divided into four 16-bit integer values. The calculation in the automation reaches up to the year 2106.
In my automations.yaml:
- id: '1716879434742'
alias: set departure time in wallbox
description: setting the expected departure time of the car
trigger:
- platform: state
entity_id:
- input_boolean.wallbox_set_time
condition: []
action:
- service: modbus.write_register
data:
hub: sonnenCharger
address: 4
slave: 0
value: >-
{% set dt = as_timestamp(states('input_datetime.departure_time', 0)) | round(0)%}
{% set reg1 = (dt | float / 65536) | round(0, "floor") | int%}
{% set reg2 = (dt - (reg1 * 65536)) | int%}
[0, 0, {{reg1}}, {{reg2}}]
mode: single
Setting the time is only possible when the car is connected to the wallbox and only makes sense when “Smart mode” is selected. Smart and Power mode are not saved in the wallbox. They are transmitted to the company Sonnen, which then controls charging depending on the available energy in PV system and sonnenBatterie.
Here you can see what my dashboard looks like when the car is loading: