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:
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.
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.
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.
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).
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.
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
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
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.