Charging an EV for free - part 2

In part 1 I described the fundamental principle of the system – the inputs and outputs to the system and the concept of having a control loop to maximise the charging power without exceeding the amount of excess energy available.

I’ll let you in on a little secret – at that point I didn’t even have an EV yet. I was still waiting on delivery. I had the charger though, and I wrote a bunch of code with no way to test it.

I’d like to say it all worked perfectly the first time I tested it live, but of course it did not. I’ll cover a few of the more interesting “gotchas” here, but I did eventually end up with this nice result:

Charging for free
Charging for free

So - between roughly 9:30 and 11:00am on this day I charged my car at the maximum rate that I could, only consuming power that I was producing in excess.

Problem 1 - Do your sums right

I mentioned this briefly in part 1. I had at that point briefly tested the system with a borrowed EV and discovered a problem immediately.

As you recall, we can measure our load and our generated energy. Subtracting the two gives us our excess (or deficit in cases where load exceeds generation).

So if you measure an excess of 4000W, you might set the charger setpoint to 4000W to consume all that power.

At this point the vehicle will start charging and your excess power drops to something close to 0W – the system is working. But the next time your control loop runs it will see an excess of 0W, and turn the charger off again.


The solution here is to include the charger power setting in the “available” calculation. However, this leads to the second observed problem:

Problem 2 - Measurement lag

Changing the charger setpoint affects the power usage (house load) almost immediately. However, my measurement of load is delayed – it is 30s delayed on average (because of a per-minute collection rate). Initially I was using a 5m rolling average, as I thought this would smooth out small fluctuations due to cloud coverage and so on. This was a mistake!

Let’s say 2000W are available for charging. I set the charger setpoint to 2000W, and the car starts charging. Next time around the control loop it checks the available power and due to both the averaging and the measurement lag, it might still show 1800W of available energy.

My loop would now decide I can set the charger set to 3800W - as I’d been using 2000W and there was still 1800W available. You can see where this is headed.

After a few minutes of this of course the system catches up and swings wildly back the other way, ultimately turning the charger off completely. The cycle then restarts.

I struggled with this for a while, but then realised the answer was really quite simple and pragmatic:

The second point was the key, and also easy to implement. Because my charger set point is in amps, not watts, I just make sure to change the setting by no more than 1 amp (in either direction) each time around the control loop (once per minute).

This allows time for the system to stabilise and produce a more coherent result.

The downside is that I can’t take immediate benefit of a sudden increase in available energy (e.g. the sun comes out from behind the clouds, or the air-conditioning is turned off), and on the flip side a sudden decrease in available energy (cloud cover, I turn the kettle on) will probably mean drawing power from the grid for a while.

Problem 3 - Sometimes you just want to charge

Of course sometimes the sun isn’t shining, or you just need to charge the car, and don’t care about the expense. The software needs to have an override so you can charge without worrying about where the energy comes from.


As you can from the graph above, the software does work. It’s tentatively named “EV ez”, subject to change! It’s driven by an integrated web interface:

Web interface home
Web interface home

At the top you can see the core datapoints being used to drive the logic, and below that a list of the modbus points of the charger, not terribly useful, but fun to look at.

I’ve also implemented the override function to set the setpoint to some static value, no matter what the excess energy status is:

Web interface home with override active
Web interface home with override active

Making this general purpose

At the moment the software is very much only suited to my system - with energy data made available via the prometheus query API which is simply some HTTP requests, and the charger access is via modbus TCP (with Victron specific point values in my case).

I will make the code available on github soon, when I have removed some hard-coded values and documented the deployment. At that point I will add a “part 3” to this series to walk through some of the actual code.

I am interested in making this more generally useful - to be able to talk to different chargers and fetch energy data from different systems. To that point I am interested in hearing from you, if you would find this useful and you have the ability to provide technical details on interfacing with the hardware you have. If your charger or energy system do not have documented methods for interfacing I am unlikely to be able to help.

Tags: ev  solar  energy  golang