Smoothed way of excess charging electrical vehicle

Dear all,

I would like to create a rule which regulating the charging of my electrical vehicle based on the available photovoltaics power.

In the german forum @Udo_Hartmann supported to create the basic rule:

rule "Ladestrom einstellen"
when
    Item PVLeistung changed or
    Item StromBedarf changed
then
    val Number nPV   = if(PVLeistung.state instanceof Number) (PVLeistung.state as Number).floatValue else 0
    val Number nHaus = if(StromBedarf.state instanceof Number) (StromBedarf.state as Number).floatValue else 2000 // zu erwartender Spitzenbedarf als Default Wert
    val Number nDiff = nPV - nHaus
    var Number nStufe = 0
    if(nDiff < 0) nStufe = 0
    else if(nDiff < 1000) nStufe = 1
    else if(nDiff < 2000) nStufe = 2
    else if(nDiff < 3000) nStufe = 3
    else if(nDiff < 4000) nStufe = 4
    else if(nDiff < 5000) nStufe = 5
    else nStufe = 6
    Ladeleistung.sendCommand(nStufe)
end

In general this is fine, but since the power can vary a lot I would like to implement a “smoothed” regulation. It means for short term I would also consume power directly from grid.

To give you some hints you can see some shapes of the produced power. In some cases its more or less regular in some its fluctuation a lot:
1 (1)


I would like to charge the car with the power seen in the “green area” as much as possible.

Does somebody has experience in such feedback control?

Thanks for your support in advance

2 Likes

Not exactly but I was looking to do the same.
My approach would be to use persistence and the averageSince() function.

BTW you can query most inverters for excess power, some even have a physical output to turn on when excess power is available. Yes this is more tricky but you could trigger upon changes to that value.

I’m not much into PV (yet), but isn’t it contradictory to switch as little as necessary and use as much excess power as possible at the same time?

What I can think of to achieve the goal to switch less would be a hysteresis curve.
https://upload.wikimedia.org/wikipedia/commons/a/aa/Hysteresis_sharp_curve.svg

This will end up similar to using a floating average. In fact, the floating average will perform smoother, if you have high changes in excess in short time periods (high frequency, high amplitude). But I can’t think of that in case of a PV.

A floating average is what you get with the averageSince() I proposed.
A pure simple hysteresis is a baaaad idea as the raw amount of excess power can change within seconds on cloudy days. Won’t take long until you kill/burn your equipment.

Didn’t know about that.

Why that? If PV cannot deliver enough energy for your current consumption, you’ll get it from the grid. If there’s more power generated as you need (including charging the BEV), just deliver it to the grid.

Only thing I can think of what’s bad for your equipment are load steps. And as long as the charing equipment can only be regulated in predefined steps, you can’t avoid them. You can just make them happen as infrequently as possible. Not?

If that’s too much OT, stop me now. But I usually have to know the background to find the appropriate solution.

I meant to say if you switch a little - a lot - a little - every time.
Yes any load step (non-smoothed instant change in amperage) can do harm so avoid wherever possible. No good for the ecar battery either.

Thanks. Shall we start to create together a rule?

I do not have any clue how to start…

val Number nPV   = if(PVLeistung.state instanceof Number) (PVLeistung.averageSince(now.minusMinutes(1)) as Number).floatValue else 0
val Number nHaus = if(StromBedarf.state instanceof Number) (StromBedarf.averageSince(now.minusMinutes(1)) as Number).floatValue else 2000 

should do the trick. Time span for the floating average can be set longer or shorter. It all depends on how often you get updated power values. That’s the OpenHAB part.

Meanwhile, I did some simulation. Assuming, excess power can raise from zero to maximum (and fall vice versa) in between 1 minute. Hysteresis and floating average based control delivered nearly the same results regarding the number of switch events and used amount of excess energy.
Generally, the control will be worse (and you have to retrieve more power from the grid), the longer the period of the floating average controller is (or the broader the hyteresis). E.g. a floating average over 5 minutes behaves bad in this scenario. But it only switches charging power only 15 times in 1 hour (remember, all underlying pv power data is randomly generated).

You have to find a trade-of not to kill your hardware, as @mstormi mentioned.

1 Like

@grizzle: thank you for the simulation. Looks good.

To avoid big jumps from 0 to max pv-power I would set some limits. Eg.

while (nPV > 3000) do ....

This will at least secure that the jumps are limited. What do you think?

BTW: how did you do the simulation? Would like to do something similar to find the right values…

That’s just some Excel with randomized data. I attached it to this reply.PV_EV_Software_Defined_Charge_Controllers.xlsx.txt (236.5 KB) Remove file extension “.txt” - hope this works. It’s just a quick and dirty work by now.

That’s partially done by the floating average controller. Assuming a 1 minute average period a jump from 0 to 6 kW excess power, the controller follows in 4 steps.

Screen

Regard any do-while loop in rule with horror, and avoid them. Try to come up with a non-blocking events based method.
You might find examples of dimmer ramping/fading suitable here.

val Number nPV   = if(PVLeistung.state instanceof Number) (PVLeistung.averageSince(now.minusMinutes(1)) as Number).floatValue else 0
val Number nHaus = if(StromBedarf.state instanceof Number) (StromBedarf.averageSince(now.minusMinutes(1)) as Number).floatValue else 2000 

Does somebody has an idea why I get this error message in the log?

 Rule 'Ladestrom einstellen': cannot invoke method public abstract float java.lang.Number.floatValue() on null

because the item value you read is uninitialized at that time

I dont get. Since this

val Number nPV   = if(PVLeistung.state instanceof Number) (PVLeistung.state as Number).floatValue else 0
val Number nHaus = if(StromBedarf.state instanceof Number) (StromBedarf.state as Number).floatValue else 2000

is working fine, the item should be initilaizied

But that isn’t about the current Item state at all. It’s about persisted data. Perhaps there isn’t any data over that time period. Perhaps the default persistence service is not what you think.

Write code that fails gracefully. Fetch the persisted data, then test to see if that worked before trying to operate on it. There’s a bunch of reasons it might not.

This works fine:

val Number nPV   = if(PVLeistung.state instanceof Number) (PVLeistung.averageSince(now.minusMinutes(1), "rrd4j") as Number).floatValue else 0

May I ask which Wallbox you guys use which you then can control with openHAB?

Well, I am using a Keba Wallbox C-Serie which is fully controllable.