Alfen Eve Pro EV chargepoint interface via TCP modbus

Thanks for the explanation Lieven, I understand now your setup. Do you run both HA and the docker file on the same hardware? I’m running HAOS and I’m not sure how to run a docker image inside HAOS.

Hey @Willli

yes I run all software on an RPi 4 with SSD. Everything runs in docker containers and I am not using HAOS.

But there is no absolute requirement that everything runs on the same hardware. That is why the MQTT broker is involved.

Best regards,
Lieven

sensor:
  - platform: integration
    source: sensor.laadpaal_real_power_sum
    name: LaadpaalTotaal
    unit_prefix: k
    unit_time: h

In configuration.yaml let’s you add “LaadpaalTotaal” to individual device energy usage in the energy dashboard

Hello @Ace132

thanks for the input. I have configured it as follows under the modbus definition:

      - name: laadpaal_energy_delivered_sum_1
        slave: 1
        address: 374
        count: 4
        data_type: float64
        unit_of_measurement: Wh
        device_class: energy
        state_class: total_increasing

and then it is also available in the energy dashboard.

Best regards,
Lieven

Much neater :+1:

Hi @hollie,

How does it work when I don’t want to use the perl script, only migrate from P1 Load-Balancing to Modbus (via HA/MQTT) load-balancing?

How do I present the current ‘delivered_l1/2/3’ MQTT topics from HA/Mosquitto towards the modbus interface of the Alfen so the Alfen can do load-balancing based on this information?

I’m wondering if there is a way to manipulate the MQTT intel towards modbus intel the Alfen understands within HA itself, without the need for extra docker containers :slight_smile:

n.b., (I don’t have any PV so I’m not interested in ‘loading when the sun is shining’ :wink: )

Hey @Mister86NL,

please take a look at the script and the automation I posted in the initial post of this thread.

The automation listens to MQTT topic chargepoint/maxcurrent and passes the info from that topic to the script. The script writes the values over modbus to the chargepoint.

The only thing that is left for you if you don’t use the Perl script is to convert the setpoint for the current from the integer value (e.g. 10A) to the required ‘long’ dataformat required by the chargepoint. That is what is handled by the Perl script in my case.

I am sure it is also possible to do this in Python/HomeAssistant directly. I just don’t know how exactly :slight_smile:

Best regards,
Lieven

Hey @hollie,

How do you anticipate on the car itself actually charging? When I plug my car in on 3 phase 16 A, $energy_balance will have a value of ‘-11.000’, how do you compensate that in your script because how i read it, unless you have a whole roof of PV, you will end up with a current of 6A, the minimum, right?

I have the script currently running on a donor VM and I am trying to modify it for my use-case, but I have to keep in mind that:

  • DSMR can split out detailed info for all 3 phases, why not use this intel?;
  • The chargepoint/car is included in the whole calculation of the power being used at that very moment, how to exclude this info in the calculation…?
  • Max. = 3 phases of 25A each, so I have 9A ‘spare’ on each phase when te car is charging at full speed.

Hey @Mister86NL,

unfortunately most inverters in the car indeed require a charge current of minimum 6A before they start charging.

How I anticipate on the car charging itself: currently the current going into the car is controlled by the available power that is reported by DSMR. If there is energy going into the grid, the charge current is increased up to a maximum of 16A. If there is energy being used from the grid, the charge current is decreased up to the minimum of 6A.

Supposed that you have a PV installation producing energy and there is no car connected to the chargepoint, then the charge current to the chargepoint will be set to 16A. As soon as you attach the car to the chargepoint your energy balance will drop and the current will be reduced until equilibrium is reached, or until the 6A limit is set.

Regarding your questions:

  • I am currently not using the intel of the phase current because it is not of use for me. Our hybrid car only charges single-phase. But it is trivial to add, the phase current is just another MQTT topic to subscribe to and then you have the info available in the script.
  • Indeed, the charge current is included in the power being used. You actually want this otherwise you cannot know if you need to increase the current to the car or not to keep the balance. If you want to exclude it there is another register you can read of the modbus to know the actual amount of power delivered to the car. But for my use case I want to know the grid balance, so I don’t see why I would exclude the car charge current from the calculation.
  • My car is a hybrid and only charges single-phase. In your use case I would indeed add an extra sanity check on the phase current to ensure none of them crosses the 25 A limit of your grid connection.

I’ll look into adding the current info to the script, actually it also makes sense to add this check from single-phase charging now I think of it :slight_smile:

Best regards,
Lieven

Hi Lieven,

Thanks for providing this info.

I do have one more question about the current value you send to the charger. Is it only allowed to use increments of 1A or are decimal values also allowed? (i.e. 10.5A)

I also see the discussion about using current values from your DSMR but I only see 1 value per phase so you can’t determine the direction of the current and therefore can’t determine if you need to charge more or not! Or am I mistaken?

I have done an experiment in node red to get the ‘long’ data format. I still need to clean it up a bit but if there is interest I will be happy to share.

Kind regards,

Luuk

I’m trying to “convert the setpoint for the current from the integer value (e.g. 10A) to the required ‘long’ dataformat reuired by the chargepoint” for 2 weeks now.

But no luck so far. I’m not a programmer

Hey @Ace132

I have added an example to the docs on how to write 10.0 A via modbus. Please see here.

How to dynamically generate the register value for the register in home assistant > sorry I cannot help you with that I am afraid.

There used to be a posting in this thread by @menloperk with some more details but it appears those posts were removed. Maybe she/he can help you further. Also maybe @DelfuegoNL can provide the example he has?

Kind regards,
Lieven.

Hey @DelfuegoNL,

the data format used to communicate over modbus does support fractional values, but I don’t know if the chargepoint and the inverter in the car support it. For me, charging one-phase, steps of ±220 W are enough to track the production of the PV system. Feel free to share your experiences!

For the phase currents: you have a point, I checked today and there does not seem to be a polarity on the current reports. Bummer :frowning:

Kind regards,
Lieven

Hi Lieven,

I don’t have an EV charger on yet so I can’t try it yet. However, I am planning on 3 phase charging so 1A would mean an immediate step of 690 W. By then I will give it a try.

Below is the node-red flow simulation I use to calculate the long data. I collect four measurement values before sending an average update. I also send an update to mod-bus every 55 seconds because I have read that otherwise it disconnects. I am not sure if that is necessary. Can you just confirm if that sending an update every 55 seconds is really necessary.

[{"id":"49ae0fea6c592846","type":"tab","label":"EV Charger","disabled":false,"info":"","env":[]},{"id":"1834c9a77a8653a1","type":"inject","z":"49ae0fea6c592846","name":"Trigger","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":220,"wires":[["5b5115e39413f7b1"]]},{"id":"be5d765d09060226","type":"modbus-server","z":"49ae0fea6c592846","name":"EV Charger","logEnabled":false,"hostname":"127.0.0.1","serverPort":10502,"responseDelay":100,"delayUnit":"ms","coilsBufferSize":10000,"holdingBufferSize":10000,"inputBufferSize":10000,"discreteBufferSize":10000,"showErrors":false,"x":370,"y":120,"wires":[[],[],[],[],[]]},{"id":"3ce1897a62cb2777","type":"inject","z":"49ae0fea6c592846","name":"Trigger","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"123456","payloadType":"num","x":190,"y":120,"wires":[["be5d765d09060226"]]},{"id":"51f4df65edcae57a","type":"function","z":"49ae0fea6c592846","name":"Calculate Float32","func":"const Float32ToHex = (float32) => {\n    const getHex = i => ('00' + i.toString(16)).slice(-2);\n    var view = new DataView(new ArrayBuffer(4))\n    view.setFloat32(0, float32);\n    return Array.apply(null, { length: 4 }).map((_, i) => getHex(view.getUint8(i))).join('');\n}\n\nlet var1=Float32ToHex(msg.payload);\n\nmsg.payload=var1;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":950,"y":540,"wires":[["c7574fbe6ec3bf3a"]]},{"id":"c7574fbe6ec3bf3a","type":"split","z":"49ae0fea6c592846","name":"","splt":"4","spltType":"len","arraySplt":"4","arraySpltType":"len","stream":false,"addname":"","x":310,"y":620,"wires":[["0cfce7f15887cd55"]]},{"id":"1492687c563eced4","type":"join","z":"49ae0fea6c592846","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":610,"y":620,"wires":[["55e4d6d1aabc4e3e"]]},{"id":"0cecb6bd73e178ee","type":"modbus-flex-write","z":"49ae0fea6c592846","name":"Write Modbus","showStatusActivities":true,"showErrors":false,"server":"45116883a93e505c","emptyMsgOnFail":false,"keepMsgProperties":true,"x":980,"y":700,"wires":[[],[]]},{"id":"7ba43ef9f85342ec","type":"function","z":"49ae0fea6c592846","name":"Prepare writing","func":"msg.payload = { \n    value: msg.payload,\n    'fc': 16, \n    'unitid': 1, \n    'address': 100 , \n    'quantity': 2 } \nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":700,"wires":[["0cecb6bd73e178ee"]]},{"id":"98b1a24c615b20ad","type":"modbus-flex-getter","z":"49ae0fea6c592846","name":"Read modbus","showStatusActivities":false,"showErrors":false,"logIOActivities":false,"server":"45116883a93e505c","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"keepMsgProperties":false,"x":640,"y":220,"wires":[[],[]]},{"id":"5b5115e39413f7b1","type":"function","z":"49ae0fea6c592846","name":"Prepare reading","func":"msg.payload = { \n    'fc': 3, \n    'unitid': 1, \n    'address': 100 , \n    'quantity': 2 } \nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":220,"wires":[["98b1a24c615b20ad"]]},{"id":"0cfce7f15887cd55","type":"function","z":"49ae0fea6c592846","name":"Hex2Dec","func":"msg.payload = parseInt(msg.payload,16);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":620,"wires":[["1492687c563eced4"]]},{"id":"0a9c11821a47340f","type":"server-state-changed","z":"49ae0fea6c592846","name":"Power","server":"3f53ed1d.fd3d32","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"sensor.power_production_phase_l1","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":70,"y":420,"wires":[["72f71969c21512b1"]]},{"id":"9c3e7adcd983623f","type":"calculator","z":"49ae0fea6c592846","name":"to W","inputMsgField":"payload","outputMsgField":"payload","operation":"mult","constant":"1000","round":true,"decimals":0,"x":310,"y":540,"wires":[["f5ccb4744888d741"]]},{"id":"f5ccb4744888d741","type":"calculator","z":"49ae0fea6c592846","name":"to A","inputMsgField":"payload","outputMsgField":"payload","operation":"div","constant":"230","round":true,"decimals":"0","x":470,"y":540,"wires":[["14b2b7d2fdc6acd7"]]},{"id":"55e4d6d1aabc4e3e","type":"looptimer","z":"49ae0fea6c592846","duration":"55","units":"Second","maxloops":"100","maxtimeout":"60","maxtimeoutunits":"Minute","name":"","x":510,"y":700,"wires":[["7ba43ef9f85342ec"],[]]},{"id":"0cb6544526b45a0d","type":"calculator","z":"49ae0fea6c592846","name":"Avarage","inputMsgField":"payload","outputMsgField":"payload","operation":"avg","constant":"","round":true,"decimals":"3","x":380,"y":340,"wires":[["9c3e7adcd983623f"]]},{"id":"72f71969c21512b1","type":"join","z":"49ae0fea6c592846","name":"Collect 4 values","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"4","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":190,"y":340,"wires":[["0cb6544526b45a0d"]]},{"id":"cbb8a9f87263a145","type":"change","z":"49ae0fea6c592846","name":"Minimal 6A","rules":[{"t":"set","p":"payload","pt":"msg","to":"6","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":710,"y":320,"wires":[["51f4df65edcae57a"]]},{"id":"75d83cb77f42ce7b","type":"change","z":"49ae0fea6c592846","name":"Maximal 16A","rules":[{"t":"set","p":"payload","pt":"msg","to":"16","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":660,"y":540,"wires":[["51f4df65edcae57a"]]},{"id":"14b2b7d2fdc6acd7","type":"switch","z":"49ae0fea6c592846","name":"","property":"payload","propertyType":"msg","rules":[{"t":"lt","v":"6","vt":"num"},{"t":"gt","v":"16","vt":"num"},{"t":"btwn","v":"4","vt":"num","v2":"20","v2t":"num"}],"checkall":"false","repair":false,"outputs":3,"x":530,"y":420,"wires":[["cbb8a9f87263a145"],["75d83cb77f42ce7b"],["51f4df65edcae57a"]]},{"id":"45116883a93e505c","type":"modbus-client","name":"EV Charger","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"tcpHost":"localhost","tcpPort":"10502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","serialAsciiResponseStartDelimiter":"0x3A","unit_id":"1","commandDelay":"1","clientTimeout":"1000","reconnectOnTimeout":true,"reconnectTimeout":"2000","parallelUnitIdsAllowed":true},{"id":"3f53ed1d.fd3d32","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30}]

Kind regards,

Luuk

3 Likes

It works!
Only thing I had to change was the IP address of my charger and there was a small error in the “prepare writing” node. The address should be 1210 not 100.

I never played with node red. I will have to do some investigation.
But thanks a lot !

Hi All,

I managed to read the Alfen charging point.
I have the DSMR values in HA available through the ‘DSMR Slimme Meter’ Integration, without MQTT.
I would like to handle this completely in HA. Is that possible?
@Ace132 did you manage it in HA? If so, can you share your example?

Kind regards,
EJ

I’m reading the modbus values through the configuration.yaml file like Lieven describes. But writing I do with node red like the example of Luuk.
All exclusive in home assistant (with node red addon)
I also use DSMR ‘slimmer meter’ integration. No MQTT here.

He only made a mistake by taking the production power as value for the charge rate. When you start to charge the production value will drop (in best case to 0). Then the charger will decrease it’s current. This becomes an infinite loop.

I’m adjusting the code en testing in real setup.
I also added a modbus write to set te charger to 1 fase when solar drops below 4,2 kW. (3x230x6a) so the charger can go as low as 1380kW (1x230x6)

There are still a lot of hiccups to be fixed in the code. I will post it when it’s ready.

2 Likes

I have my alfen eve single pro connected via both P1 and UTP.
The load balancing is working fine via the P1.

I only want to read some modbus values, not write any. Especially the amount of energy that was delivered to the car, so i can visualise it in the Home Assistant Energy view.

From what I read above, you cannot have both P1 loadbalancing and modbus enabled at the same time, is that correct? If so, best thing to do might be a feature request at alfen to allow reading modbus values (read only) while P1 meter loadbalancing is enabled.

1 Like

Hi Ace132,

Thank you for sharing. It sounds good and looks exactly like what I have in mind.

I have installed the node red addon. When I have imported the code I get the message: missing node type calculator.

Does that sound familiar to you and how did you solve it?

Gr. EJ

Update: You can install missing node types!

@Ace132,

When you have the code ready, I would be happy to receive it!