Delta Wallbox via Modbus in HA

Hallo zusammen

Hier ein Beitrag für alle, die so ein Setup bereits haben oder wollen. Ich mache das, damit nicht alle so viel Chaos erleben wie ich. Ich hoffe sehr, dass es jemandem eine Tages hilft.

Fast alle Infos konnte ich über diesen Forum-Thread finden. Danke vielmals denen, die dazu beigetragen haben. Unter anderem habe ich die KI auf den Thread gehetzt, um die relevantesten Informationen herauszusuchen, das war eine gute Idee, hätte ich von anfang an machen sollen.

Geschichte:
Nach installierter PV-Anlage musste eine andere Wallbox her, ich hatte den Juice-Booster 2, und der kann nicht dynamisch laden. Er kann nicht ins Smarthome eingebunden werden.

Nun habe ich eine Delta AC Max Basic gekauft. Sie hat einen modbus Anschluss. Diesen habe ich dann mittels RS485 Adapter und eines ESP32 in Homeassistant eingebunden mit ESPhome und MQTT. (Wobei ich mir die MQTT hätte sparen können, da ich ja die Entitäten von ESPhome auch erhalte. Besser kann es für mich kaum sein, die Wallbox ist sehr günstig und die Verarbeitung hat mich positiv überrascht.

Ich habe einen Homeassistant Yellow. Da dieser nicht ESPHome kompilieren kann wegen mangelnder Leistung/Ram, musste ich das auf dem Laptop machen.

Strom für die Module habe ich von der Wallbox selbst nehmen wollen, aber meine Module konnten damit nur ungenügend gespiesen werden. Im Forum hat jemand gemeint, dass es für seine Module gereicht hat. Deshalb habe ich innerhalb der Wallbox eine fliegende Steckdose (Verlängerungskabel-Abschnitt) gemacht und da ein USB Netzteil eingesteckt.

Der KI (claude.ai) habe ich gesagt, was ich will und was ich habe und dann hat mir die KI die yaml Datei gemacht, die ich dann kompilieren und flashen musste.
Auf dem Desktop habe ich dafür einen Ordner gemacht für die Dateien und da die yaml und die secrets.yaml abgelegt.
Da ich keine Ahnung davon hatte, hat mir die KI alles gut erklärt. So hat es dann auch geklappt.

Wie ich secrets.yaml benutzt habe:
die secrets.yaml sieht im Aufbau so aus:

wifi_ssid: “MeinWLAN”
wifi_password: “MeinPasswort123”

mqtt_username: “homeassistant”
mqtt_password: “MeinMqttPasswort”

ha_api_key: “xxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
ota_password: “MeinOtaPasswort”

wifi_ap_password: “FallbackPasswort”

In der yaml des ESP32 muss man das dann so machen:

wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password

ESPHome ersetzt !secret wifi_ssid beim Kompilieren automatisch durch den Wert aus secrets.yaml.

Probleme:
Hatte ich viele.

  • Ungenügende Speisung für die Module in der Wallbox
  • Nicht übereinstimmende Begriffe in secrets.yaml und der wallbox.yaml
  • Falsche Register Abfragen für die Wallbox, keine Daten kamen an.
  • Verdrehte Datenleitungen (Data+ und Data-)
  • App-Einrichtung und Firmware Update der Wallbox katatrophal. Ist aber im Prinzip auch nicht notwendig. Anleitung: App und Firmware update Delta
  • Und einiges mehr.

Als Anhänge habe ich euch die Wallbox yaml und die Automation, die ich verwende, um die Ladung am Auto zu steuern.
Die Wallbox ist mit 1 Phase angeschlossen und mit 16A abgesichert.
In Homeassistant habe ich einen “input select” Helfer gemacht, wo ich steuern kann, wie ich das Auto laden möchte.
(Ein anderer Weg wäre evcc zu benutzen, ein HACS repository. Die Wallbox kann die KI als “Benutzerdefiniert” erstellen, dann braucht man keinen Token kaufen. Damit kann man ziemlich einfach alles regeln, was nötig ist in Zusammenhang mit PV, Wallbox und Auto.)
Steuern tu ich in 100W Schritten, aber die Sprünge werden automatisch zu 1A-Schritten. Also ca. alle 230W geht etwas mehr. Ich weiss aber nicht, ob das am Auto liegt, an irgendwelchen protokollen oder sonst was.

Lade-Varianten des “input select” Helfers:

  • Aus
  • Ein (Auto wird geladen, koste es was es wolle)
  • PV-Überschuss (Auto wird geladen, sobald genügend Überschuss vorhanden ist)
  • Nur NT (Niedriger Stromtarif, Auto wird nur “Günstig” geladen.

Hier die Automation die ich in HA verwende:
Lade Automation Auto-s42.txt (6,0 KB)

Und noch das yaml des ESP32, der mittels RS485 Adapter die Wallbox mit HA verbindet:
ESP32_delta_acmax_basic-s42.yaml (6,6 KB)

Hier noch eine yaml für evcc für die Delta AC Max Basic. (Die gibt es in den Vorlagen, aber dann muss man den Token kaufen. Monatlich 4.- oder einmalig 150.-) Mit dieser yaml kann man einfach eine benutzerdefinierte Wallbox anlegen und so die Vorlage und den Token umgehen:
Delta AC MAx Basic yaml für evcc.txt (1,4 KB)

Und noch Unterlagen von Delta aus dem Forum und aus dem Netz:

Hier wollte ich die pdf posten, da das nich geht, poste ich halt die Links dazu:
EVCS Modbus Register Delta Wallbox
Modbus Register Table Delta

Und noch 2 Bilder:

Moin,
Vielen Dank für deine Anleitung, hat mir persönlich sehr geholfen. Allerdings hätte ich noch ein Problem, dass ich bis dato nicht gelöst bekommen habe.
Wie startest / beendest / pausierst du den Ladevorgang? Ich finde dafür kein Register. Wenn ich das Auto anschließe springt der Status auf “Verbunden - wartet auf Freigabe”, aber da kann ich Modbus-Seitig nichts machen…
Aktuell sehe ich da nur zwei Möglichkeiten:
A) Bluetooth App weiter benutzen um den Ladevorgang zu starten,
B) DIP-Schalter 2 der WB auf “OFF”, dann sollte ja theoretisch das Laden per Schlüssel aktiv sein und dann einfach den Schlüssel dauerhaft auf ON lassen. Würde aber bedeuten, dass dann theoretisch jeder einfach bei mir Zuhause laden könnte (ohne Autorisierung)…

Ich hoffe du hast eine Idee, danke und Gruß

Hoi Timo

Ich nutze die Freigabe nicht, da eigene geschlossene Garage, der Schlüsselschalter ist stets auf ein.

Ich habe die KI gefragt, ob man den Schlüsselschalter auf 2 Kontakte des ESP32 legen kann. Das geht aber nur über weitere Hilfsmittel wie Optokoppler oder so (Da kenne ich mich nicht aus).

Was man machen könnte, ein Shelly mini im WLAN, das mit der Shelly integration einfügen in HA (Kein Shelly Konto oder cloud nötig) und dann mittels dieses Relais die Freigabe machen. Also die beiden Drähte vom Schlüsselschalter abklemmen und an das Relais (Potentialfrei) anschliessen. Strom für den Shelly auch von den 230 V abgreifen, die an der Wallbox angeschlossen ist. So wie ich es gemacht habe für das ESP32 Netzteil in meinem Setup.
Als Relais kannst du nehmen: Shelly 1Mini.
L/N ist klar, Stromversorgung.
I und SW ist dann der Schlüsselschalter. Dann kannst du das in der Automation einfügen und erst wenn der Shelly durch deine Eingabe den kontakt schliesst, ist Freigabe.
Und eben: Shelly ist einfach ein Beispiel. Kannst auch was anderes nehmen. Ich beschreibe halt gerne, was ich kenne und nutze.

Hier noch die Antwort der KI: (Nicht geprüft und nicht getestet!)
Ja, das geht sehr gut mit ESPHome! Du kannst einfach einen binary_sensor für den Schlüsselschalter-Eingang und einen switch (mit GPIO-Ausgang) für die potentialfreie Freigabe hinzufügen.

Hier die ergänzenden Blöcke, die du in deine YAML vom esp32 einfügen kannst:

yaml

# ============================================================
# Schlüsselschalter Eingang (z.B. GPIO18)
# ============================================================
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO18
      mode:
        input: true
        pullup: true   # interner Pullup, Schalter gegen GND
      inverted: true   # LOW = aktiv (Schalter geschlossen)
    name: "Schlüsselschalter"
    id: key_switch
    icon: mdi:key-variant
    on_press:
      then:
        - switch.turn_on: freigabe_relay
    on_release:
      then:
        - switch.turn_off: freigabe_relay

# ============================================================
# Potentialfreier Ausgang (z.B. GPIO19) – z.B. via Relais/Optokoppler
# ============================================================
switch:
  - platform: gpio
    pin: GPIO19
    name: "Freigabe Ausgang"
    id: freigabe_relay
    icon: mdi:electric-switch
    restore_mode: ALWAYS_OFF

Ein paar Hinweise:

  • GPIO18 ist der Eingang vom Schlüsselschalter – Schalter zwischen GPIO18 und GND, interner Pullup aktiviert

  • GPIO19 ist der Ausgang – da schliesst du ein Relais oder Optokoppler an, dessen Kontakt dann potentialfrei ist

  • Den ESP32 direkt als potentialfreien Kontakt nutzen geht nicht – du brauchst zwingend ein Relais-Modul oder Optokoppler dazwischen

  • Freie GPIOs beim ESP32 DevKit: z.B. GPIO18, GPIO19, GPIO21, GPIO22, GPIO23 – meide GPIO0, GPIO2, GPIO12, GPIO15 (Bootpins)


Noch eine Ergänzung!
Du kannst auch auf die Relais für Freigabe verzichten. Schlüssel immer auf ein.

Und dann programmierst du einen Helfer “Freigabe”
Und erst wenn dieser Helfer auf “Ein” steht, dann darf die Laderegelung arbeiten.

Quasi eine Condition ganz am Anfang der Automation.

So müsste es gehen ohne weitere Hilfsmittel.

Hast du meine Automation kopiert?
Sie hat noch einen Bug.

Hier ist die aktuellste Version:
Bei der müsstest du aber eben noch den Freigabe Helfer ändern. Ich habe eine Pause Switch als condition, den kannst du genau gleich als Freigabe nutzen.

yaml:

alias: Auto laden Laderegelung Delta (30s)
description: >
Regelt die Ladeleistung der Delta Wallbox anhand PV-Überschuss. PV-Überschuss:
dynamisch 1400–3450W mit Hysterese beim Stopp. Ein/Nur NT: konfigurierbar.
triggers:
minutes: “*”
seconds: /30
trigger: time_pattern
entity_id: input_select.auto_lademodus
trigger: state
entity_id: input_boolean.auto_laden_pause
trigger: state
entity_id: input_number.wallbox_ladeleistung_fur_ein_nt
trigger: state
entity_id: schedule.hochtarif
to: “on”
trigger: state
conditions:
condition: template
value_template: “{{ wb_angeschlossen }}”
actions:
if:
condition: state
entity_id: input_boolean.auto_laden_pause #Den kannst du als Freigabe nutzen. Solange der auf "on" steht lädt es nicht.
state: “on”
then:
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: 0
action: number.set_value
target:
entity_id: input_number.wallbox_hysterese_start
data:
value: 0
action: input_number.set_value
stop: Pause aktiv
if:
condition: template
value_template: “{{ wb_charge_state == 0 }}”
then:
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: 0
action: number.set_value
stop: Kein Fahrzeug – Limit auf 0 gesetzt
if:
condition: template
value_template: “{{ wb_charge_state == 5 }}”
then:
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: 0
action: number.set_value
target:
entity_id: input_number.wallbox_hysterese_start
data:
value: 0
action: input_number.set_value
stop: Laden abgeschlossen – Limit auf 0 gesetzt
if:
condition: template
value_template: |
{{ trigger.entity_id == ‘schedule.hochtarif’
and states(‘input_select.auto_lademodus’) == ‘Nur NT’ }}
then:
target:
entity_id: input_select.auto_lademodus
data:
option: PV-Überschuss
action: input_select.select_option
stop: Nur NT → HT begonnen, Modus auf PV-Überschuss gewechselt
if:
condition: template
value_template: |
{{ (bezug <= ausschalten_netz_w or pv > reserve)
and netzspitze_start > 0 }}
then:
target:
entity_id: input_number.wallbox_hysterese_start
data:
value: 0
action: input_number.set_value
choose:
conditions:
condition: template
value_template: “{{ modus == ‘Ein’ }}”
sequence:
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: “{{ fix_limit if wb_angeschlossen else 0 }}”
action: number.set_value
target:
entity_id: input_number.wallbox_hysterese_start
data:
value: 0
action: input_number.set_value
conditions:
condition: template
value_template: “{{ modus == ‘Nur NT’ }}”
sequence:
if:
condition: state
entity_id: schedule.hochtarif
state: “off”
then:
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: “{{ fix_limit if wb_angeschlossen else 0 }}”
action: number.set_value
else:
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: 0
action: number.set_value
target:
entity_id: input_number.wallbox_hysterese_start
data:
value: 0
action: input_number.set_value
conditions:
condition: template
value_template: “{{ modus == ‘PV-Überschuss’ }}”
sequence:
choose:
conditions:
condition: template
value_template: “{{ wb_aktiv }}”
sequence:
variables:
netto: “{{ pv - reserve - bezug }}”
new_limit: >
{% set raw = wb_limit + netto %} {% set clamped = [[raw,
max_limit] | min, min_limit] | max %} {{ ((clamped //
100) * 100) | int }}
if:
condition: template
value_template: >
{{ wb_limit <= min_limit and bezug >
ausschalten_netz_w
and netzspitze_start == 0 }}
then:
target:
entity_id: input_number.wallbox_hysterese_start
data:
value: “{{ now().timestamp() | int }}”
action: input_number.set_value
if:
condition: template
value_template: >
{{ netzspitze_start > 0 and netzspitze_seconds >=
off_delay
and bezug > ausschalten_netz_w and wb_limit <= min_limit }}
then:
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: 0
action: number.set_value
target:
entity_id: input_number.wallbox_hysterese_start
data:
value: 0
action: input_number.set_value
stop: Hysterese abgelaufen – Wallbox gestoppt
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: “{{ new_limit }}”
action: number.set_value
conditions:
condition: template
value_template: >-
{{ not wb_aktiv and wb_angeschlossen and pv >= start_bei
and bezug <= 0 }}
sequence:
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: “{{ min_limit }}”
action: number.set_value
target:
entity_id: input_number.wallbox_hysterese_start
data:
value: 0
action: input_number.set_value
conditions:
condition: template
value_template: “{{ modus == ‘Aus’ }}”
sequence:
target:
entity_id: number.delta_ac_max_basic_evse1_ladeleistung_limit
data:
value: 0
action: number.set_value
target:
entity_id: input_number.wallbox_hysterese_start
data:
value: 0
action: input_number.set_value
variables:
modus: “{{ states(‘input_select.auto_lademodus’) }}”
pv: “{{ states(‘sensor.pv_uberschuss’) | float(0) }}”
bezug: “{{ states(‘sensor.leistung_bezug_korrigiert’) | float(0) }}”
wb_limit: >-
{{ states(‘number.delta_ac_max_basic_evse1_ladeleistung_limit’) | float(0)
}}
wb_charge_state: “{{ states(‘sensor.delta_ac_max_basic_evse1_charge_state’) | int(0) }}”
wb_angeschlossen: “{{ wb_charge_state >= 1 }}”
wb_aktiv: “{{ wb_charge_state == 3 and wb_limit > 0 }}”
reserve: 50
min_limit: 1400
max_limit: 3450
fix_limit: “{{ states(‘input_number.wallbox_ladeleistung_fur_ein_nt’) | int(1400) }}”
ausschalten_netz_w: 300
off_delay: 120
netzspitze_start: “{{ states(‘input_number.wallbox_hysterese_start’) | int(0) }}”
netzspitze_seconds: “{{ (now().timestamp() - netzspitze_start) if netzspitze_start > 0 else 0 }}”
start_bei: 1200
mode: restart

:crayon:by HarryP: Zusammenführung Doppelpost (bei Änderungen oder hinzufügen von Inhalten bitte die „Bearbeitungsfunktion“ anstatt „Antworten“ zu nutzen)

Hi ich bin neu hier. Hab mir jetzt auch die delta Wallbox gekauft und bin gerade dabei das ganze so umzusetzen wie hier beschrieben. Wollte jetzt nur nochmal sicher gehen wo genau GND ist? So wie ich das sehe in der Anleitung, aus einem anderen post, sieht man nur wo D+ und D- ist. Stimmt das so wenn ich von vorne auf die wallbox schaue:

ganz rechts D-

links daneben D+

Und links daneben GND

Danke schonmal für eure hilfe:)

Hallo bottniko

Schön, dass du dich meldest.

Das mit dem Ground ist so eine Sache…
Ich hatte massive Probleme, das zum Laufen zu bringen, irgendwann habe ich es mit dem GND versucht, das hat aber nichts gebracht. Der GND ist eigentlich ein Überbleibsel vom troubleshooting und verzweifeltem Lösung suchen.

Als es dann endlich lief, habe ich den nicht zurückgebaut, um zu prüfen, ob es ihn noch benötigt.
Höchstwahrscheinlich läuft es auch ohne den GND.

Probier mal ohne.

Ich wünsche dir viel Erfolg!

Das mit der Baudrate ging bei mir nicht, ich fahre mit 19200.
Das war glaube ich default. Wenn das alles so läuft, brauchst du auch die App Einrichtung nicht machen, damit habe ich am meisten Zeit vertan, da das nicht so “User-Friendly” gemacht ist.

1 „Gefällt mir“

Vielen Dank für die info​:+1:. Dann braucht man also auch kein Update zu machen wenn man die app nicht nutzt oder?

Probiers mal ohne. Kannst dann immer noch, wenn nichts geht.