How to integrate VOOL EV charger with HomeAssistant over modbus.
Disclaimer: I’m not against the VOOL’s idea/logic how to charge EV - it will suit for majority of people - but I wanted to tinker and have “full control” over how to or when to charge the vehicle.
Prerequisites are that modbus is enabled in VOOL (if needed can be asked trough support or enabled according to manual) and charger firmware is at least 1.9.40!
With lower versions modbus will be available on port 502, but register 100 (Charger State) will return ‘3200’ and not the correct information!
As modbus is confiugurable only trough configuration.yaml it is simple copy and paste
modbus:
- name: modbus_hub
type: tcp
host: <CHARGER IP>
port: 502
delay: 1
message_wait_milliseconds: 100
timeout: 5
switches:
- name: vool_charger_switch_charging
address: 500
command_on: 1
command_off: 2
sensors:
- name: vool_charger_charger_state_enum
address: 100
data_type: uint16
- name: vool_charger_ac_current_l1
address: 102
scale: 0.01
unit_of_measurement: A
precision: 2
- name: vool_charger_ac_current_l2
address: 103
scale: 0.01
unit_of_measurement: A
precision: 2
- name: vool_charger_ac_current_l3
address: 104
scale: 0.01
unit_of_measurement: A
precision: 2
- name: vool_charger_voltage_l1
address: 105
scale: 0.1
unit_of_measurement: V
precision: 1
- name: vool_charger_voltage_l2
address: 106
scale: 0.1
unit_of_measurement: V
precision: 1
- name: vool_charger_voltage_l3
address: 107
scale: 0.1
unit_of_measurement: V
precision: 1
- name: vool_charger_active_power
address: 108
data_type: int16
scale: 0.01
unit_of_measurement: kW
precision: 2
- name: vool_charger_active_power_l1
address: 109
scale: 0.01
unit_of_measurement: kW
precision: 2
- name: vool_charger_active_power_l2
address: 110
scale: 0.01
unit_of_measurement: kW
precision: 2
- name: vool_charger_active_power_l3
address: 111
scale: 0.01
unit_of_measurement: kW
precision: 2
- name: vool_charger_energy_imported_msb
address: 200
data_type: uint32
unit_of_measurement: Wh
As charger state returns only number I made a template sensor to make it human readable:
{% set mapper = {
'0' : 'UNDEFINED',
'1' : 'AVAILABLE',
'2' : 'PREPARING',
'3' : 'CHARGING',
'4' : 'SUSPENDED_EV',
'5' : 'SUSPENDED_EVSE',
'6' : 'FINISHING',
'7' : 'RESERVED',
'8' : 'UNAVAILABLE',
'9' : 'FAULTED',
'10' : 'STARTING_CHARGING'
}
%}
{% set state = states.sensor.vool_charger_charger_state_enum.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
And for switching on and off another template switch has been made:
That is because modbus register 500 for charging state does not reflect the state (always 0).
From manual “Reaction to the start/stop command can be concluded from the “Charger State” value.”
template:
- switch:
- name: vool_charger_switch_template
unique_id: vool_charger_switch_template
## state on: 3 (CHARGING), 4 (SUSPENDED_EV), 5 (SUSPENDED_EVSE)
## state off: 1 (AVAILABLE), 2 (PREPARING), 6 (FINISHING)
state: >
{% if states("sensor.vool_charger_charger_state_enum") in ["3", "4", "5"] %}
on
{% elif states("sensor.vool_charger_charger_state_enum") in ["1", "2", "6"] %}
off
{% else %}
{% endif %}
turn_on:
action: switch.turn_on
target:
entity_id: switch.vool_charger_switch_charging
turn_off:
action: switch.turn_off
target:
entity_id: switch.vool_charger_switch_charging
## switch available: cable connected, charger state is: 1 (AVAILABLE), 2(PREPARING), 3(CHARGING), 4 (SUSPENDED_EV), 5 (SUSPENDED_EVSE), 6 (FINISHING),
availability: >
{% if is_state("binary_sensor.cupra_tavascan_charging_cable_connected", "on") %}
{% if states("sensor.vool_charger_charger_state_enum") in ["1", "2", "3", "4", "5", "6"] %}
on
{% endif %}
{% else %}
off
{% endif %}
NB! This solution does not follow the OCPP v1.6 standard!
According to standard - starting charging again from FINISHING state should not be possible.
And some cars manufacturers even fail when trying to restart charging from FINISHING state - so be warned!
At first modbus seemed complicated … but in the end i’d say the solution suits my needs at the moment
.
Maybe that is not the best solution - but that is how I got it working for now.
And as always - there is room for improvement!