Read Wallbox data (Vestel EVC04) via Modbus

Hi folks,

trying to read data from my Wallbox (Vestel EVC04, firmware 2.65.0) via the TCP modbus.

Unfortunately, I am getting an error when trying to connect via modbus platform: “Connection to (192.xxx.xxx.xxx, 502) failed: [Errno 111] Connection refused”

Has someone managed by chance to connect to the Vestel wallbox or has some further ideas how to get it working.

My config.yaml entry looks as follows:

# vestel charging station
modbus:
  - name: Ladestation
    close_comm_on_error: true
    delay: 5
    timeout: 5
    type: tcp
    host: 192.xxx.xxx.xxx
    port: 502

The modbus TCP manifest from vestel wallbox states the following:
Vestel EVC04 charging station acts as a slave device in the Modbus TCP/IP communication. Charging station should be in the same network with the master device or a proper routing should be applied to provide communication between slave and the master devices in different sub networks. Each charging station should have different IP address. Modbus TCP communication port number is 502 and Modbus Unit ID is 255 for Vestel EVC04 charging stations. There can be only one active Modbus master connection at any time.

Appreciate any thought on this.

Cheers!

Hello,

have you ever been able to establish the connection?

I have the same error and would love to know your solution.

Thank you in advance.

Greetings
Marcus

Hello,
Does anyone have a working configuration with all sensors?

i’ve tried a few things, unfortunately i don’t have an electric car at the moment to start a charging process, i only get 0 everywhere. i have no idea if that’s true or if it works not

I have a wallbox type Websta Unite. It is a rebranded Vestel EVC04 using the same modbus TCP register map (actualy most values just return zero unforntunatly).
I have created a working modbus config though (see below). Ofcourse you need to change the IP adress to your situation: This configuration does not contain the ‘keep alive’ logic. So the connection will close and reopen every 20 seconds or so. Let me know if you need the keep alive logic (no experience in exporting automations yet).

# modbus:
#
# General remarks on options used
# Connection to Webasto Unite using TQ.DM100 register definitions. This defines portnumber (502) and slave address (255).
# IP address (dependent on your network configuration)
# define: &Webasto_IP_Address 192.168.178.61
#
# At each sensor 
# 'name' and 'unique_id' must be identical. The explicit setting of unique_id makes it possible to remove the sensor (of so desired).
# use 'device_class' to customize the representation of the sensor.
# 'unit_of_measurement' should only be used if no applicable 'device_class' could be selected.
# 'slave_count' should not be used. It will make the names of the sensors ugly.
#
  - name: "Webasto Unite"
    type: tcp
    host: 192.168.178.61
    port: 502
    message_wait_milliseconds: 1
    sensors:
      - name: Webasto_ChargePointState_number
        # This is a number that represents a state. The state(s) will be exposed 
        # by another sesnsor derived from this sensor, using a template. Therfore 
        # this sensor has a suffix '_number'. Both in name and unique_id
        unique_id: Webasto_ChargePointState_number
        slave: 255
        input_type: holding
        address: 1000
        data_type: uint16
        # Template 'Webasto.ChargePointState' will be used to display the states.

      - name: Webasto_ChargeState_number
        # This is a number that represents a state. The state(s) will be exposed 
        # by another sensor derived from this sensor, using a template. Therfore 
        # this sensor has a suffix '_number'. Both in name and unique_id
        unique_id: Webasto_ChargeState_number
        slave: 255
        input_type: holding
        address: 1001
        data_type: uint16
        # Template 'Webasto.ChargeState' will be used to display the states.

      - name: Webasto_EVSEState_number
        # This is a number that represents a state. The state(s) will be exposed 
        # by another sensor derived from this sensor, using a template. Therfore 
        # this sensor has a suffix '_number'. Both in name and unique_id
        unique_id: Webasto_EVSEState_number
        slave: 255
        input_type: holding
        address: 1002
        data_type: uint16
        # Template 'Webasto.EVSEState' will be used to display the states.

      - name: Webasto_CableState_number
        # This is a number that represents a state. The state(s) will be exposed 
        # by another sensor derived from this sensor, using a template. Therfore 
        # this sensor has a suffix '_number'. Both in name and unique_id
        unique_id: Webasto_CableState_number
        slave: 255
        input_type: holding
        address: 1004
        data_type: uint16
        # Template 'Webasto.CableState' will be used to display the states.

      - name: Webasto_EVSEErrorCode_number
        # This is a number that represents a state. The state(s) will be exposed 
        # by another sennsor derived from this sensor, using a template. Therfore 
        # this sensor has a suffix '_number'. Both in name and unique_id
        unique_id: Webasto_EVSEErrorCode_number
        slave: 255
        input_type: holding
        address: 1006
        data_type: uint16
        # Template 'Webasto.EVSEErrorCode' will be used to display the states.

      - name: Charging Current L1
        unique_id: Webasto_ChargingCurrentL1
        slave: 255
        input_type: holding
        address: 1008
        data_type: uint16
        device_class: current
        # scaling: output [A] = 0.001*value [mA] + 0, precision [mA]
        offset: 0
        scale: 0.001
        precision: 3
        state_class: measurement
        unit_of_measurement: A

      - name: Charging Current L2
        unique_id: Webasto_ChargingCurrentL2
        slave: 255
        input_type: holding
        address: 1010
        data_type: uint16
        device_class: current
        # scaling: output [A] = 0.001*value [mA] + 0, precision [mA]
        offset: 0
        scale: 0.001
        precision: 3
        state_class: measurement
        unit_of_measurement: A

      - name: Charging Current L3
        unique_id: Webasto_ChargingCurrentL3
        slave: 255
        input_type: holding
        address: 1012
        data_type: uint16
        device_class: current
        # scaling: output [A] = 0.001*value [mA] + 0, precision [mA]
        offset: 0
        scale: 0.001
        precision: 3
        state_class: measurement
        unit_of_measurement: A

      - name: Active Power
        unique_id: Webasto_ActivePower
        slave: 255
        input_type: holding
        address: 1020
        data_type: uint32
        device_class: power
        state_class: measurement
#        swap: <none / byte / word / word_byte> (not used for uint16/uint32)
        unit_of_measurement: W

      - name: Energy meter
        unique_id: Webasto_Energymeter
        slave: 255
        input_type: holding
        address: 1036
        data_type: uint32
        device_class: energy
        state_class: total_increasing
#        swap: <none / byte / word / word_byte> (not used for uint16/uint32)
        # scaling: output [kWh] = 0.001*value [Wh] + 0, precision [Wh]
        offset: 0
        scale: 0.001
        precision: 3
        unit_of_measurement: kWh

      - name: Max current possible
        unique_id: Webasto_Maxcurrent
        slave: 255
        input_type: holding
        address: 1100
        data_type: uint16
        device_class: current
        state_class: measurement
        unit_of_measurement: A

      - name: Min current possible
        unique_id: Webasto_Minimumcurrentlimit
        slave: 255
        input_type: holding
        address: 1102
        data_type: uint16
        device_class: current
        state_class: measurement
        unit_of_measurement: A

      - name: Max current EVSE
        unique_id: Webasto_MaxCurrentfromEVSE
        slave: 255
        input_type: holding
        address: 1104
        data_type: uint16
        device_class: current
        state_class: measurement
        unit_of_measurement: A

      - name: Max current cable
        unique_id: Webasto_MaxCurrentfromCable
        slave: 255
        input_type: holding
        address: 1106
        data_type: uint16
        device_class: current
        state_class: measurement
        unit_of_measurement: A

      - name: Max current EV
        unique_id: Webasto_MaxCurrentfromEV
        slave: 255
        input_type: holding
        address: 1108
        data_type: uint16
        device_class: current
        state_class: measurement
        unit_of_measurement: A

      - name: User priority
        unique_id: Webasto_Userpriority
        slave: 255
        input_type: holding
        address: 1200
        data_type: uint16
#        device_class: enum
        state_class: measurement

      - name: EV SoC actual
        unique_id: Webasto_EVBatteryState
        slave: 255
        input_type: holding
        address: 1300
        data_type: uint16
        device_class: battery
        min_value: 0
        max_value: 100
        state_class: measurement
        unit_of_measurement: "%"

      - name: EV Energy actual
        unique_id: Webasto_EVBatteryEnergy
        slave: 255
        input_type: holding
        address: 1302
        data_type: uint32
        device_class: energy_storage
        # scaling: output [kWh] = 0.001*value [Wh] + 0
        offset: 0
        scale: 0.001
        precision: 3
        state_class: measurement
#        swap: <none / byte / word / word_byte> (not used for uint16/uint32)
        unit_of_measurement: kWh

      - name: Webasto_ScheduleType_number
        # This is a number that represents a state. The state(s) will be exposed 
        # by another sennsor derived from this sensor, using a template. Therfore 
        # this sensor has a suffix '_number'. Both in name and unique_id
        unique_id: Webasto_ScheduleType_number
        slave: 255
        input_type: holding
        address: 1400
        data_type: uint16
        # Template 'Webasto.ScheduleType' will be used to display the states.

      - name: EV Energy target
        unique_id: Webasto_EVRequiredEnergy
        slave: 255
        input_type: holding
        address: 1402
        data_type: uint32
        device_class: energy_storage
        # scaling: output [kWh] = 0.001*value [Wh] + 0
        offset: 0
        scale: 0.001
        precision: 3
        state_class: measurement
#        swap: <none / byte / word / word_byte> (not used for uint16/uint32)
        unit_of_measurement: kWh

      - name: EV SoC target
        unique_id: Webasto_RequiredBatteryState
        slave: 255
        input_type: holding
        address: 1406
        data_type: uint16
        device_class: battery
        min_value: 0
        max_value: 100
        state_class: measurement
        unit_of_measurement: "%"

# Scheduled time & date registries will be read into two sensors.
# Using a template they will be combined into one entity 'Webasto Scheduled end'
      - name: Webasto_ScheduledTime_number
        unique_id: Webasto_ScheduledTime_number
        slave: 255
        input_type: holding
        address: 1408
        data_type: uint32
        # device_class: None specified
        state_class: measurement
        unit_of_measurement: hhmmss

      - name: Webasto ScheduledDate_number
        unique_id: Webasto_ScheduledDate_number
        slave: 255
        input_type: holding
        address: 1412
        data_type: uint32
        # device_class: None - because it is numerical
        state_class: measurement
        unit_of_measurement: yymmdd

      - name: Charged Energy
        unique_id: Webasto_ChargedEnergy
        slave: 255
        input_type: holding
        address: 1502
        data_type: uint16
        device_class: energy
        state_class: total
        # scaling: output [kWh] = 0.001*value [Wh] + 0, precision [Wh]
        offset: 0
        scale: 0.001
        precision: 3
        unit_of_measurement: kWh

      - name: Webasto_StartTime_number
        unique_id: Webasto_StartTime_number
        slave: 255
        input_type: holding
        address: 1504
        data_type: uint32
        # device_class: None specified
        state_class: measurement
        unit_of_measurement: hhmmss

      - name: Charging duration
        unique_id: Webasto_ChargingTime
        slave: 255
        input_type: holding
        address: 1508
        data_type: uint32
        device_class: duration
        state_class: measurement
        unit_of_measurement: s

      - name: Webasto_EndTime_number
        unique_id: Webasto_EndTime_number
        slave: 255
        input_type: holding
        address: 1512
        data_type: uint32
        # device_class: None specified
        state_class: measurement
        unit_of_measurement: hhmmss

      - name: User ID
        unique_id: Webasto_UserID
        slave: 255
        input_type: holding
        address: 1600
        # User ID is sent in 10 registers LSB first.
        data_type: custom
        count: 5
        structure: ">Qxx"  # ignores last two bytes
        # device_class: None specified
        state_class: measurement

      - name: Plug and Connect
        unique_id: Webasto_15118SmartVehicleDetected
        slave: 255
        input_type: holding
        address: 1620
        data_type: uint32
#        device_class: enum
        state_class: measurement

# The Communication timeout defines a maximum period for the switch.Webast_Keepalive_switch to set a value of '1'.
# Otherwise the TCP connection is closed by the Webasto. The default value is 20 seconds.
# The Communication timeout can be changed by the combination of:
# - input_number.Webasto_ComTimeout_set
# - automation.webasto_update_communication_timeout
      - name: Communication timeout
        unique_id: Webasto_ComTimeout
        slave: 255
        input_type: holding
        address: 2002
        data_type: uint16
        device_class: duration
        state_class: measurement
        unit_of_measurement: s

# List of all fields that can be defined for a 'sensor' entity.
#
# sensors - config template (with correct indentation)
#      - name: Field Name
#        unique_id: <Webasto_FieldNameID>
#        slave: 255
#        input_type: <holding / input> (type of Modbus register)
#        address: 1000
#        data_type: <uint16 / uint32 / custom>
#        device_class: <none / enum / apparent_power / battery / current / date / duration / energy / energy_storage / timestamp / power (see: https://www.home-assistant.io/integrations/sensor/)
#        min_value: <float>
#        max_value: <float>
#        nan_value: <0x000 hex representing NaN>
#        zero_suppress: <float absolute(+) bandwidth>
# scaling: output = scale*value + offset
#        offset: <float>
#        scale: <float>
#        precision: <integer number of decimals>
#        slave_count: <allowing multiples sensors to be read with one modbus-message. Names are sacrificed>
#        state_class: <measurement / total / total_increasing>
#        structure: <formatting string for data_type=custom>
#        swap: <none / byte / word / word_byte> (not used for uint16/uint32)
#        unit_of_measurement: <string> (label for units)
#

    switches:
# The Webasto Unite wallbox needs a keep alive trigger periodically by writing 
# a 1 in the keep alive register. If you do not do this, the TCP connection
# will be closed by de Webasto Unite. The current timeout period is in sensor 
# Webasto_ComTimeout. The default is a 20 second interval.
# Although it is not certain, the register will be read after writing, using 
# the verify option of the switch entity. This seems to function correctly.
# The automation 'Webasto Keepalive @20secs' is used to periodically set this switch On
      - name: Keepalive
        unique_id: Webasto_Keepalive_switch
        slave: 255
        write_type: holding
        address: 6000
        command_on: 1
        command_off: 0
        verify:
          delay: 5

# List of all fields that can be defines for a 'switch' entity.
#
# switches
#      - name: Field Name
#        unique_id: <Webasto_FieldNameID>
#        slave: <modbus slave ID>
#        write_type: <holding / holdings / coil / coils>
#        address: <address of write register>
#        command_on: <int>
#        command_off: <int>
#        verify:
#          input_type: <coil / discrete / holding / input>
#          address: <address of verify register, defaul identical as ???>
#          delay: <ms?>
#          state_on: <int, default identical command_on>
#          state_off: <int, default identical command_off>

Hi, I have also a Webasto Unite and will give your Modbus sensor template a try asap. I believe if you have activated modbus in the Unite Web Gui and the keep alive register is not triggered every X seconds, the max. Charge Power will be limited to 6A/4,2kW for grid safety/overload protection reasons. This in conjunction that the Wallbox Modbus connection is used (enabled) either for Loadmangement purposes, e.g. by external EMS/HEMS Systems in case several Wallboxes are combined to one bigger charging station cluster, or for PV-Surcharge charging. In case the EMS fails, charging power will be limited automatically due to the missing keep alive trigger, normally/frequently send by the EMS.

Hi, I have inserted your code into the configuration.yaml and restarted the Home Assistant but my Vestel EVC04, which is connected via a network cable, is not recognized as a device although I have activated Modbus TCP on the Vestel EVC04. Do I have to do anything else besides inserting your code into the configuration.yaml?

Hi, i install in HA Open Charge Point Protocol (OCPP). Then open ip of charge (admin/admin) and activate OCPP with Charge ID and central system ws://ip_HA:9000/
Now I have data from charge Vestel EVC04. Charge is connected via WIFI.
https://home-assistant-ocpp.readthedocs.io/en/latest/

Hi jhares, thank you very much. Now it’s working.

@BrainDra1n Done and working…:

@lemuba You have it working with the Webasto Unite? Is so, do you read any values (other than zero)?

In my situation I have an automation that handles the keep alive (and functions correctly, proven by no diconnect logs). But all values read zero.
Maybe the configurations matters/ My Webasto Unite uses:

  • firmware version v2.99.11-1.0.109.0.
  • OCPP enabled
  • Local Load Management: Modbus TCP
  • DLM with Garo GNM3T (over Modus serial)
    Do you have a different configuration?

Maybe we should move this discussion to @lemuba 's topic specific for the Webasto Unite: Webasto (now Ampure) Unite Wallbox Modbus Integration

Hi,

I´m wondering how you can have both at the same time :wink:

There are two different options which are either, or:

a)

This is the Unite Web UI setting to control the Unite from an external device like a HEMS (e.g. Clemap, Solarmanager CH, evcc, etc.) or Home Assistant via Modbus TCP

or, b)

This is the setting for the integrated DLM or SLM up to 32 Unite wallboxes with one of the Unite validated external RTU-Meters meters:

So, you have to set up option a) in the Unite Web UI to get a connection to- and control from HA!

Further, when I tried first your code, my readings were also Zero…
If you compare to my code:

Your setting: input_type: holding
My Code: input_type: input

That was mainly my only fix to get all readings.

I´m on firmware “v3.128.1”, but it does not have any additional benfit for your purposes.
Your firmware is fine!

v3.128.1 is not offered “online” or via an OTA update, only in some cases via your installer (not retailer) who is connected direcly to the Ampure (former Webasto) B2B-Support Team.

BR

@lemuba Thanx for the reply. I will try your holding vs input setting.

You state that the newer firmware that you use, is not important for me. Though, my version does not have the option to set a ‘Failsafe current’.

To clarify the confusion about load management:
I use the Garo current meter to do protect my fuse box. It measures the total current through my fuse box, reports this to the Unite wallbox. In the wallbox this is called ‘DLM’ or Dynamic Load Management. The wallbox limits the charging current when the total current reported by the Garo current meter exceeds a set number (25A in my case). The Garo connects to the wallbox through a modbus serial interface.
BTW: This is not the options to do load balancing between wallboxes. That option would exclude me from using the Modbus TCP.

The Local Load Management uses a (different) Modbus TPC interface to the wallbox. That is the one I want to get working. With your advice, I will now try to get this to work.

So does the version of the firmware really not matter?

@lemuba I changed input-type to input (instead of holding).
Enabled the modbusTCP in the wallbox and had to do a Hard Reset, but now it has come to life!!!

Thanx so much for the help. Do not really know ‘why’ but it worked.

1 Like

The combination and use case you described with your Garo Meter is called Dynamic Loadmanagement „Stand Alone Modus“… By switching to Modbus TCP to connect to HA, you lost this feature now. Hope you are aware about this?

@lemuba : I do not want to debate whether you’re right or wrong. So excuses in advance. But I would like understand.

I have DLM enabled as follows:


This is generally named DLM, but is technically called Power Optimizer in this wallbox.
I still see that the wallbox is reading the energy meter (as RX/TX is still shown on the Garo).

Next to that I have enabled the ModBus TCP interface as follows:


Which does communicate correctly (thanks to your advice).

To me it looks like the DLM or beter ‘Power optimizer’ is still operational. Am I right in assuming that?

Hi. I am new to adding a walbox to my HA.
I have a Turkish Vestel unit EVC04 (not a German one) that does not have any TCP, display or any of this. Instead it has a physical RS-485 for Modbus and a 5V output (which is great for adding a WiFi TCP modbus device). The 5V and Modbus work only when I enable the DIP switches, which enables the Power Optimizer function.
As per the user manual, the Modbus is used for Power Optimizer. I do not need one as I have a 63A / 3 Phase utlity supply.
From what I read and tested, once I enable the Power Optimizer (set the current limit), the 5V appears and there is a serial communication. If there is no negotiation, after some time the circular lamp shows contant red. This is all logical.
I wonder if the above example of the Modbaus yaml configuration is still valid?
I assume the TCP Modbus adapter is set as the TCP Master, and the Walbox Modbus address is 255.
I do not see any valid data in the sensors created by examples above yaml code. Please help me to understand what is the problem. I have kept the input_type as holding register at this point.

Another issue is the serial port setup. From what I have read, it is is set to even parity (8 bits, 1 stop bit & 9600bps). Is this what you guys set it up?

@niraviry Am I correctly understanding that you have a Vestel EVC04 with serial modbus interface, but no WiFi, LAN or GSM/LTE interface? Thus only dipswitches to configure and no app or web interface.

If so, you (only) have a serial interface to connect to a current metering device (e.g. KL6934) to use the Power Optimizer function. Which you do not need (as your utility supply is 63A / 3 phase). In this serial modbus interface the wallbox is the master and the current metering device is a slave.

This would mean that you can not monitor or control the wallbox via modbus. This function is only available via modbus TCP. And you do not have a network interface (WiFi, LAN or SGM/LTE).

I doubt that you have no network interface. It think the ethernet port is always present. See schematric below.

But I’m quite sure that you do have an ethernet port. See if you can get this to work.

Unfortunately this model does not have it. At the front there is only an RFID reader. I made some progress where I have found out that the 5V exists only if I set the current limit for the Power Optimizer. This also enables the Modbus. If there is no communication the indication circle lamp turns red.
As for the Master /Slave, I have read the open data for the EVC04 and it looks like it must be connected with its default Modbus parameters meaning address 1.
I am currently on vacation so I do not have all info handy but I will try to add up the info in the evening. I use a TCP Modbus over WiFi adapter and it can be set as a TCP server, a TCP client and more.
Another issue is the last entity in the yaml code. It can’t be set to input as it is a switch.
Edited:
The Vester recommended Optimizer is the Klefr 6934. It has m-bus interface and Modbus. Modbus is RTU only so I guess the charger runs inquiries and as per the house limit set be the 3 dip switches, it controls its current charging.