Hello,
I implemented an interface to read out sensors and set the charge current on an Alfen Eve Pro chargepoint for electrical vehicles.
My goal: being able to store locally generated energy in the car battery instead of delivering it back into the grid.
We have a digital electricity meter that has a P1 port. This port tells you every second how much energy is consumed from the net, and -in case of overproduction- how much energy is sent back into the grid.
This port can be interfaced with DSMR reader that will post energy consumption figures via MQTT. Using that information I can figure out if the house is delivering energy back to the grid, and if it is, instruct the chargepoint to charge the car battery instead. At the current electricity prices, this bring me a netto gain of 0.20 per kWh.
What I implemented results in dynamic control of the charge current for the electric vehicle taking into account the local consumption of the house too. The graph below shows how this looks (static charging from 9:30 ⊠10:30 and then dynamic charging on a day with fluctuating solar generation).
The interface to the chargepoint happens via modbus over TCP. You need to enable this setting on your chargepoint via the control software of Alfen, it is not enabled by default.
To read out the sensors, add the following section to your configuration.yaml
:
modbus:
- name: laadpaal
type: tcp
host: 192.168.xxx.yyy
port: 502
sensors:
- name: laadpaal_name
slave: 200
address: 100
count: 17
data_type: string
- name: laadpaal_temperature
slave: 200
address: 1102
data_type: float32
unit_of_measurement: °C
- name: laadpaal_active_max_current
slave: 200
address: 1100
data_type: float32
unit_of_measurement: A
- name: laadpaal_real_power_sum
slave: 1
address: 344
data_type: float32
unit_of_measurement: W
- name: laadpaal_mode3_state
slave: 1
address: 1201
count: 5
data_type: string
scan_interval: 5
- name: laadpaal_actual_applied_maxcurrent
slave: 1
address: 1206
data_type: float32
unit_of_measurement: A
- name: laadpaal_modbus_maxcurrent
slave: 1
address: 1210
data_type: float32
unit_of_measurement: A
- name: laadpaal_socket1_current_valid_time
slave: 1
address: 1208
data_type: uint32
unit_of_measurement: s
Then to convert the chargepoint mode sensor to a human-readable chargepoint status that you can use in automations, add this template:
template:
- sensor:
- name: mode3_sanitized
state: "{{states('sensor.laadpaal_mode3_state').replace('\0','') }}"
- name: chargepoint_status
state: >
{% set m3 = states('sensor.mode3_sanitized') %}
{% if m3 in ['A', 'E'] %} available
{% elif m3 in ['B1', 'B2', 'C1', 'D1'] %} connected
{% elif m3 in ['C2', 'D2'] %} charging
{% else %} {{ m3 }}
{% endif %}
With this you can already read the sensors and the current on your chargepoint and make automations to enable your front lights when you plug in the car when you arrive home in the evening
Now onto the more interesting part: to be able to set the charge current based on the energy produced by your solar installation. For this you need to be able to call the modbus.write_register
function with as parameter a 32-bit float that sets the charge current in amps. If you lookup how a float is represented as a 32-bit value (IEEE 754 format), youâll see that 16
decimal is represented as 0x41800000
. Because a single modbus register can only contain 16 bits, the modbus.write_register
function needs to be called with two parameters so that the function knows it needs to perform two consecutive writes to the chargepoint at the right target address.
This means to set the charge current to 16A
you need to pass to the function the base address of the correct register and then the parameters 0x4180
and the parameter 0x0000
.
I do this via a script in Home Assistant that takes as input the two bytes and passed those to the modbus.write_register
function. It looks like this:
alias: Set modbus maxcurrent
variables:
value_msb: 16768
value_lsb: 0
sequence:
- service: modbus.write_register
data:
address: 1210
unit: 1
hub: laadpaal
value:
- '{{ value_msb }}'
- '{{ value_lsb }}'
mode: single
Then you need a way to call the script to pass the parameters. I do this via an automation that takes the input from MQTT and passes it to the script. This automation looks like this:
alias: '[elek] Set the chargepoint current'
description: 'Pass MQTT current to the script'
trigger:
- platform: mqtt
topic: chargepoint/maxcurrent
condition: []
action:
- service: script.set_modbus_maxcurrent
data_template:
value_msb: '{{ trigger.payload_json.value_msb | int}}'
value_lsb: '{{ trigger.payload_json.value_lsb | int}}'
mode: single
Weâre almost there
Now all we need is a script that implements the rules on when to charge with which current.
The rules I have are simple:
- default to minimum charge current (6A)
- when we deliver back to the grid, increment the charge current
- when we start consuming electricity from the grid, decrement the charge current but not lower than minimum
- allow to set a time for âboost chargeâ that charges the car at full speed (16A) in case this is required.
Now as I am more of a Perl guy instead of a Python guru I wrote this script in Perl. I could not find an efficient way to implement this in Home Assistant itself. This is due to a lack of knowledge from my side and not a limitation of Home assistant
This script is published here.
Actually, the thing I was struggling most with was to convert the integer value of the charge current into the correct 2x16-bit values. In Perl I just do pack/unpack. In Python I donât know how.
# Warning: Perl code ahead ;-)
my $network_long = unpack 'L', pack 'f', $current;`
my $parameters = {
'value_msb' => $network_long / 2**16,
'value_lsb' => $network_long % 2**16,
'current' => $current
};
Then I send that over MQTT into the Home Assistant automation. My attempts to implement this in Home Assistant with templates were futile. Either way: I am all open for suggestions on this part!
Some important/interesting notes when you would want to duplicate this:
- it appears that (EU) electric vehicles that use a standard AC charge socket only support charge currents from 6A and upwards. If you set the current lower, the vehicle stops charging. You can use this to halt charging, e.g. until the sun comes back during the day. Simply set the charge current to â0â in that case.
- the Eve chargepoint only supports a single modbus TCP connection. I first tried to set the current from the Perl script and use Home Assistant to read out the sensors and monitor the status. This led to Home Assistant losing the connection to the chargepoint when it tried to read out sensor values.
- if you happen to have an Alfen Eve Pro double chargepoint, then you can access the socket-specific settings of the rightmost charge plug by accessing the registers I documented above, but then at slave address
2
. Slave address1
are the settings of the leftmost charge plug, or the only plug in case of the Eve Pro Single chargepoint.
Have fun,
Hollie.