EV Charger control with Modbus TCP

Hi,

I just wanted to share my successful learning experience with Modbus TCP, Home Assistant, and electric car charger.

I hope this helps others who are new to Modbus or are thinking about electric car charger control.

Difficult part was to understand that coil and register are just different datatypes of Modbus. mbpoll was usefull in early testing. It’s a Linux command line tool for sending and reading Modbus TCP. No passwords or any other means of security, so depending on your case this might be problem or benefit :).

I bought an electric car and a home charger (wallbox) for it about a month ago. The charger was the cheapest possible with Ethernet connection I could find (at least when considering my other requirements). Manufacturer did not provide any info on Ethernet, but I took the risk. I had found some pictures from other models of the same manufacturer, and they did contain a module from Phoenix Contact. After getting the charger it proved out to contain the charge controller form Phoenix Contact module (they sell modules only to OEMs).
Phoenix contact had datasheet for the module available, so soon after electrical installation I started to play around with it.

This is the working config:

modbus:
  - name: wallbe
    type: tcp
    host: 192.168.0.8
    port: 502

Additionally one needs some sensors (in my sensor.yaml):

- platform: modbus
  scan_interval: 2
  registers:
    - name: ChargeTime
      hub: wallbe
      unit_of_measurement: s
      slave: 255
      register: 102
      register_type: input
      data_type: int
    - name: ChargeCurrent
      hub: wallbe
      slave: 255
      register: 528
      register_type: holding
      scale: 0.1
      data_type: int
      unit_of_measurement: A
    - name: EVStateDec
      hub: wallbe
      slave: 255
      register: 100
      register_type: input

(For understanding EVStateDec charging standard needs to be read, 1 is state A)

And control via scripts.yaml (only the “-service” with address 528 is really needed for current control, 413 is enable (you could leave that always enabled), and about over current more later):

charge_0a:
  sequence:
    - service: switch.turn_on
      entity_id: switch.ChargerOvercurrentDisable
    - service: modbus.write_register
      data_template:
        hub: wallbe
        unit: 255
        address: 528
        value: 0
    - service: modbus.write_register
      data_template:
        hub: wallbe
        unit: 255
        address: 413
        value: 0
    - service: switch.turn_on
      entity_id: switch.ChargerOvercurrentDisable
charge_6a:
  sequence:
    - service: switch.turn_off
      entity_id: switch.ChargerOvercurrentDisable
    - service: modbus.write_register
      data_template:
        hub: wallbe
        unit: 255
        address: 528
        value: 60
    - service: modbus.write_register
      data_template:
        hub: wallbe
        unit: 255
        address: 413
        value: 1
charge_16a:
  sequence:
    - service: switch.turn_off
      entity_id: switch.ChargerOvercurrentDisable
    - service: modbus.write_register
      data_template:
        hub: wallbe
        unit: 255
        address: 528
        value: 160
    - service: modbus.write_register
      data_template:
        hub: wallbe
        unit: 255
        address: 413
        value: 1

0A charge setting did not work, thus I implemented switch.ChargerOvercurrentDisable. It commands the charger to think that the car is taking more current that is allowed -> it goes to error state. Recovery is simple disable over current setting and set correct current. One problem I had to solve with automation is that if you connect car to charger that is in over current state, the charger state machine goes crazy (running through states constantly). My automation just calls the charge_0a when this happens.

Here is the missing switch.yaml:

- platform: modbus
  scan_interval: 2
  coils:
    - name: ChargerOvercurrentDisable
      hub: wallbe
      slave: 255
      coil: 409

.yaml -files above are included from configuration.yaml, with normal syntax, e.g.:

switch: !include switch.yaml
2 Likes

nice job. I bought I guess the same charger are you.
Do you know the password from the internal webserver from wallbe?
I tried all the known regular passwords, but none did work.

Thanks
Sebi

Hi @prese,

Here is the link to charging controller: https://www.phoenixcontact.com/online/portal/gb/?uri=pxc-oc-itemdetail:pid=1018701.

According to datasheet the Modbus interface contains all the same features as webpage, so the password is really not needed.
When I asked for support from Walbe, they said:
The LAN interface of this version is only intended for maintenance or programming works.
With the access you can easily change settings that could damage the charging station and you also lose your warranty.
Please note that an incorrect setting of the charge controller will result in immediate loss of warranty.
Unfortunately, we cannot offer support for integration or Modbus questions to private end customers.

My translation about the warning would be: You should make it absolutely sure that you do not configure the charger for higher currents: cabling in the device is rated only for 16A. I think the dip switches are used for this setting, but better safe than sorry!

Any other settings are probably reversible with the reset command from Modbus, firmware upgrade excluded of course :slight_smile:

Great job Jarkko!!!
I order my first electric car last month and I bought the same yours wallbox this week!
In your post you said you created an automation to recovery the error state.
Can you share that automation?
ThankYou

K.

Hi @kender,
charger reset is not used in automation, as there is no need for it :slight_smile:. I have a switch for it instead:

- platform: modbus
  scan_interval: 10
  coils:
    - name: ChargerOvercurrentDisable
      hub: wallbe
      slave: 255
      coil: 409
    - name: ChargerEnable
      hub: wallbe
      slave: 255
      coil: 400
    - name: ChargerReset
      hub: wallbe
      slave: 255
      coil: 413

ChargerEnable is a later addition. I changed the charger dip switches so that separate enable command is always required; either from Modbus TCP or separate input. I added a switch to input too, so I have a backup in case HA fails :slight_smile:

My current setup is quite complex, but it works.

  • Normally charger is enabled and set for 10A
  • When I connect charging cable charging starts and EVStateDec changes from A (decimal 65)
  • State change triggers telegram automation to ask for user selection and starts a 10 min timer. Additionally entrance lights are turned on if the sun is below horizon.
  • User (me) can select charging speed or no charge, all selections cancel the timer. So the choice is charge now or do not charge
  • If nothing is selected the timer reaches zero, this triggers another telegram message and stops charging. Reasoning for this 10 min is battery lifetime optimization. Lithium batteries do not like high nor low voltages, so short charging after driving is always good. In reality this should have near zero effect, but it’s there because it’s the most optimal solution I could think of :slight_smile:.
  • I get the car battery SOC with Mercedes Me component made by @ReneNulschDE (:+1:). SOC is used to start charging at night so that charging is ready at 6:30 (input_datetime). This optimises the charging losses for cabin heating and minimizes the time battery is at full SOC, also electricity is cheaper at night time.
  • Last automation is based on whole house current consumption. Main fuses are 25A, and if the current goes over 30A for a minute (they last quite long time small over current) charging is stopped and telegram message is sent out.

Furthermore I have other automations, all in same file in quite messy order. So it’s not presentation quality :slightly_frowning_face:. I can share any pieces you’d be interested in, or send more via pm, but putting it all here would require too much cleaning work…

Just this week I had one issue. HA reported in the morning that battery is at 34%. I got nervous, if something is broken. Rebooted everything, charger too and charging did not start… Finally I checked the current consumption graphs and saw that charging had happened. The issue was in Mercedes cloud service, which reports the SOC. Cloud was down all night and battery was already full, but it was difficult to believe (going out and starting the car is too much) :).

Good to know there is a possibility to control Wallbe using HA. Nice work!
I am still not sure what to get: Go-eCharger Home+ or Wallbe. Where Go-e has an official API and 22kW but Wallbe looks better, is cheaper and would be sufficient, since I would put all the logic anyway to HA automations.

Can you set the current to whatever you want (except 0) or are there standards / levels to be aware of?
(I saw you’re using Reg 528 to set the current. Are the possible values there e.g. 10,20,30,40…?)

I have a 20.5kWp PV installation and want to charge the car mainly using solar-energy. So, with some hysteresis, HA could set the charging current always a bit lower than the current unused solar-energy current is.

I found also this project to control wallbe: https://github.com/andig/evcc/

1 Like

Hi @andreas.w ,

The charging cable communication defines the maximum current the car can take. Minimum value there is 6A. It really is Amps, so 11kW with three phases is the same as single phase 3.6kw (both being 16A@230V).

Wallbe supports any discrete values up from 6A.

That evcc is a great finding!

Hi all,

wanted to quickly mention that I’ve developed https://github.com/andig/evcc as a comprehensive EV charge controller software. I’d like to add hassio integration (https://github.com/andig/evcc/issues/235) but could use some community help. Please join us on Github if interested.

Kind regards,
Andi

2 Likes

Hi @jruoho,

thanks for your work!
I have set up a pv ev charging algorithm (similar to evcc) in homeassistant with automations with the help of your documentation! (I am still testing and plan to show it later…)
But I don’t like the idea of forcing my wallbe into an error state to disable charging. Is there another way of switching the charging off maybe via the “ChargerEnable” address?

Thanks
Sebastian

Hi Sebastian (@S3b4st1an),

Check the link from @andig - there are instructions what dip to change to require separate enable. I am using it also nowadays, with the addition of physical enable button. Separate enable helps with wife acceptance factor, when there is an easy work around for the case when computers fail :slight_smile:

I can add now that evcc meanwhile also has an api, both rest and mqtt that should ease integration with hassio and others.

Cheers,
Andi

1 Like

I have seen the mentioned dip switch (10).
So if I understand correctly a script with:

- service: modbus.write_register
      data_template:
        hub: wallbe
        unit: 255
        address: 413
        value: 1

will start charging and:

- service: modbus.write_register
      data_template:
        hub: wallbe
        unit: 255
        address: 413
        value: 0

will stop charging if the dip switch ist set to “on”?

Other question: Can you tell me more about the physical switch you are using?

Hi @S3b4st1an,

If you have changed the dip, then the address 400 should be enough. “on” (1) to enable charging and “off” (0). Additionally you only need to set the address 528 to correct value (range 60…160).

The reset (413) I use only if nothing works :slight_smile:

1 Like

Hi @miki_lbc,

Thanks for sharing :slight_smile:
I guess it’s good to have links in both direction: https://community.home-assistant.io/t/phoenix-contact-ev-charger-with-modbus-tcp-2902802

Next step would be a proper integration :slight_smile:

1 Like

Hi, bringing up this topic again. Today I also got my wallbe ECO 2.0 installed. It’s fully operational and also the web interface is available on http://192.168.0.8 (incl. access with the “secret” password, but I’m not going to make use of that). I thought I could easily add the basic sensors as a first step, so I added the config from the first post of this thread:

modbus:
  - name: wallbe
    type: tcp
    host: 192.168.0.8
    port: 502

together with

sensor: !include sensor.yaml

and the sull sensor.yaml, also from the first post. Unfortunately, no entities or sensors are shows, but config is accepted. Did the syntax change in the meantime or is anything else missing for a simple start without switches - just sensors? Even if the wallbox is not accessible or parameters are wrong, I had guessed that I get the sensors (with wrong data or errors), but I just get nothing.

Thanks,
Tobias

Hi Tobse,
the syntax has indeed changed at some point.

Here is a piece of my current, working, config:

- name: wallbe
  type: tcp
  host: 192.168.0.8
  port: 502
  switches:
    - name: ChargerOvercurrentDisable
      slave: 255
      write_type: coil
      address: 409
    - name: ChargerEnable
      slave: 255
      write_type: coil
      address: 400
    - name: ChargerReset
      slave: 255
      write_type: coil
      address: 413
  sensors:
    - name: ChargeCurrent
      slave: 255
      address: 528
      input_type: holding
      scale: 0.1
      data_type: int16
      unit_of_measurement: A
    - name: EVState_raw
      slave: 255
      address: 100
      input_type: input
      data_type: string
      count: 1
    - name: EVErrorCodeHex
      slave: 255
      address: 107
      input_type: input
      data_type: int16

Thanks, after a lot of playing around last night, I also got it running - at least the sensors:

# wallbox
modbus:
  - name: wallbe
    type: tcp
    host: 192.168.0.8
    port: 502
    sensors:
    - name: Lade-Zeit
      unit_of_measurement: h
      slave: 255
      address: 102
      precision: 1
      scale: 0.000277777777
    - name: Lade-Strom
      slave: 255
      address: 528
      scale: 0.1
      unit_of_measurement: A
      device_class: current
    - name: Lade-Status
      slave: 255
      address: 100
      device_class: battery

but the switches from your syntax are something I might take over, as well as the additional error code sensor ;-).

In addition to the basic sensors, I created one for the status, assigning texts and icons to the states (info taken from the Phoenix documentation), so I have a more beautiful display on Lovelace. Unfortunately it’s in German, but might also give others an idea how do to such “mappings”:

template:
  - sensor:
      - name: "Wallbox Status"
        state: >
          {% if is_state('sensor.lade_status', '65') %}
            kein Fahrzeug
          {% elif is_state('sensor.lade_status', '66') %}
            Fahrzeug lädt nicht
          {% elif is_state('sensor.lade_status', '67') %}
            Fahrzeug lädt
          {% elif is_state('sensor.lade_status', '68') %}
            Fahrzeug lädt
          {% elif is_state('sensor.lade_status', '69') %}
            Fehler, nicht bereit
          {% elif is_state('sensor.lade_status', '70') %}
            Laden nicht verfügbar
          {% else %}
            Unbekannt
          {% endif %}
        icon: >
          {% if is_state('sensor.lade_status', '65') %}
            mdi:power-plug-off
          {% elif is_state('sensor.lade_status', '66') %}
            mdi:car-outline
          {% elif is_state('sensor.lade_status', '67') %}
            mdi:battery-charging
          {% elif is_state('sensor.lade_status', '68') %}
            mdi:battery-charging
          {% elif is_state('sensor.lade_status', '69') %}
            mdi:battery-alert
          {% elif is_state('sensor.lade_status', '70') %}
            mdi:battery-alert
          {% else %}
            mdi:battery-unknown
          {% endif %}

Note that I read the register as int16 (default), so I have to switch by ASCII codes, not the actual string representation A…F. That allows displaying something like the following:

image

Hi Tobse,
I will also use Wallbe Eco 2.0s in my Home assist. I have add you code, but I only get Lade-Strom and not the other things. Have you got an idea?

Hm, not really :-(. But in the meantime, my configuration slightly changed. Maybe the one I posted earlier had some issues - don’t remember. This is my current sensor configuration for the wallbe:

# wallbox
modbus:
  - name: wallbe
    type: tcp
    host: 192.168.0.8
    port: 502
    sensors:
    - name: wallbe Lade-Zeit S
      unique_id: wallbe_lade_zeit_s
      unit_of_measurement: s
      slave: 255
      address: 102
      input_type: input
    - name: wallbe eingestellter Lade-Strom # read
      unique_id: wallbe_eingestellter_lade_strom
      slave: 255
      address: 300
      input_type: holding
      scale: 0.1
      unit_of_measurement: A
      device_class: current
    - name: wallbe Vorgabe Lade-Strom # read/write
      unique_id: wallbe_vorgabe_lade_strom
      slave: 255
      address: 528
      input_type: holding
      scale: 0.1
      unit_of_measurement: A
      device_class: current
    - name: wallbe Status Raw
      unique_id: wallbe_status_raw
      slave: 255
      address: 100
      input_type: input
      device_class: battery
    - name: wallbe Lade-FehlerCode Hex
      unique_id: wallbe_lade_fehlercode_hex
      slave: 255
      address: 107
      input_type: input
      data_type: int16

And BTW, in addition to and based on this configuration, I was also finally able to implement some buttons on my Dashboard:

image

Here’s the yaml:

type: horizontal-stack
title: Lade-Leistung setzen
cards:
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: call-service
      service: modbus.write_register
      data:
        address: 528
        slave: 255
        value: 0
        hub: wallbe
      target: {}
    icon: mdi:gauge-empty
    name: Aus
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: call-service
      service: modbus.write_register
      data:
        address: 528
        slave: 255
        value: 60
        hub: wallbe
      target: {}
    name: 4kW
    icon: mdi:gauge-low
    show_state: false
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: call-service
      service: modbus.write_register
      data:
        address: 528
        slave: 255
        value: 120
        hub: wallbe
      target: {}
    name: 8kW
    icon: mdi:gauge
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: call-service
      service: modbus.write_register
      data:
        address: 528
        slave: 255
        value: 160
        hub: wallbe
      target: {}
    name: 11kW
    icon: mdi:gauge-full