node-red-contrib-power-saver
node-red-contrib-power-saver copied to clipboard
best save not working well
bestsave heats my water at too many expensive hours. It's configured with 2H recovery but runs at least 4 hours/day - and tomorrow will run 7 hours of which 4 are quite expensive compared to the 3 cheapest hours that day (which SHOULD have been the only hours picked).

{"schedule":[{"time":"2022-09-16T00:00:00+02:00","value":false,"countHours":4},{"time":"2022-09-16T04:00:00+02:00","value":true,"countHours":4},{"time":"2022-09-16T08:00:00+02:00","value":false,"countHours":22},{"time":"2022-09-17T06:00:00+02:00","value":true,"countHours":2},{"time":"2022-09-17T08:00:00+02:00","value":false,"countHours":8},{"time":"2022-09-17T16:00:00+02:00","value":true,"countHours":2},{"time":"2022-09-17T18:00:00+02:00","value":false,"countHours":1},{"time":"2022-09-17T19:00:00+02:00","value":true,"countHours":1},{"time":"2022-09-17T20:00:00+02:00","value":false,"countHours":2},{"time":"2022-09-17T22:00:00+02:00","value":true,"countHours":2}],"hours":[{"price":2.8061,"onOff":false,"start":"2022-09-16T00:00:00+02:00","saving":0.522},{"price":2.5601,"onOff":false,"start":"2022-09-16T01:00:00+02:00","saving":0.276},{"price":3.2771,"onOff":false,"start":"2022-09-16T02:00:00+02:00","saving":0.993},{"price":2.7001,"onOff":false,"start":"2022-09-16T03:00:00+02:00","saving":0.416},{"price":2.2841,"onOff":true,"start":"2022-09-16T04:00:00+02:00","saving":null},{"price":3.1831,"onOff":true,"start":"2022-09-16T05:00:00+02:00","saving":null},{"price":5.1421,"onOff":true,"start":"2022-09-16T06:00:00+02:00","saving":null},{"price":5.8301,"onOff":true,"start":"2022-09-16T07:00:00+02:00","saving":null},{"price":5.7561,"onOff":false,"start":"2022-09-16T08:00:00+02:00","saving":4.146},{"price":5.5991,"onOff":false,"start":"2022-09-16T09:00:00+02:00","saving":3.989},{"price":5.6261,"onOff":false,"start":"2022-09-16T10:00:00+02:00","saving":4.016},{"price":5.6081,"onOff":false,"start":"2022-09-16T11:00:00+02:00","saving":3.998},{"price":5.6651,"onOff":false,"start":"2022-09-16T12:00:00+02:00","saving":4.055},{"price":5.6431,"onOff":false,"start":"2022-09-16T13:00:00+02:00","saving":4.033},{"price":5.6411,"onOff":false,"start":"2022-09-16T14:00:00+02:00","saving":4.031},{"price":5.6261,"onOff":false,"start":"2022-09-16T15:00:00+02:00","saving":4.016},{"price":5.5781,"onOff":false,"start":"2022-09-16T16:00:00+02:00","saving":3.968},{"price":3.8571,"onOff":false,"start":"2022-09-16T17:00:00+02:00","saving":2.247},{"price":4.6161,"onOff":false,"start":"2022-09-16T18:00:00+02:00","saving":3.006},{"price":5.2701,"onOff":false,"start":"2022-09-16T19:00:00+02:00","saving":3.66},{"price":5.0891,"onOff":false,"start":"2022-09-16T20:00:00+02:00","saving":3.479},{"price":3.4701,"onOff":false,"start":"2022-09-16T21:00:00+02:00","saving":1.86},{"price":3.8851,"onOff":false,"start":"2022-09-16T22:00:00+02:00","saving":2.275},{"price":3.3911,"onOff":false,"start":"2022-09-16T23:00:00+02:00","saving":1.781},{"price":5.3271,"onOff":false,"start":"2022-09-17T00:00:00+02:00","saving":3.717},{"price":5.0041,"onOff":false,"start":"2022-09-17T01:00:00+02:00","saving":3.394},{"price":3.5241,"onOff":false,"start":"2022-09-17T02:00:00+02:00","saving":1.914},{"price":3.5031,"onOff":false,"start":"2022-09-17T03:00:00+02:00","saving":1.893},{"price":3.4931,"onOff":false,"start":"2022-09-17T04:00:00+02:00","saving":1.883},{"price":2.9181,"onOff":false,"start":"2022-09-17T05:00:00+02:00","saving":1.308},{"price":1.6101,"onOff":true,"start":"2022-09-17T06:00:00+02:00","saving":null},{"price":3.6631,"onOff":true,"start":"2022-09-17T07:00:00+02:00","saving":null},{"price":3.4731,"onOff":false,"start":"2022-09-17T08:00:00+02:00","saving":2.484},{"price":5.4191,"onOff":false,"start":"2022-09-17T09:00:00+02:00","saving":4.43},{"price":5.4881,"onOff":false,"start":"2022-09-17T10:00:00+02:00","saving":4.499},{"price":5.4021,"onOff":false,"start":"2022-09-17T11:00:00+02:00","saving":4.413},{"price":5.4131,"onOff":false,"start":"2022-09-17T12:00:00+02:00","saving":4.424},{"price":3.4631,"onOff":false,"start":"2022-09-17T13:00:00+02:00","saving":2.474},{"price":2.8711,"onOff":false,"start":"2022-09-17T14:00:00+02:00","saving":1.882},{"price":2.9381,"onOff":false,"start":"2022-09-17T15:00:00+02:00","saving":1.949},{"price":0.9891,"onOff":true,"start":"2022-09-17T16:00:00+02:00","saving":null},{"price":1.4051,"onOff":true,"start":"2022-09-17T17:00:00+02:00","saving":null},{"price":3.5291,"onOff":false,"start":"2022-09-17T18:00:00+02:00","saving":0.128},{"price":3.4011,"onOff":true,"start":"2022-09-17T19:00:00+02:00","saving":null},{"price":4.8271,"onOff":false,"start":"2022-09-17T20:00:00+02:00","saving":1.262},{"price":5.5131,"onOff":false,"start":"2022-09-17T21:00:00+02:00","saving":1.948},{"price":3.5651,"onOff":true,"start":"2022-09-17T22:00:00+02:00","saving":null},{"price":3.8011,"onOff":true,"start":"2022-09-17T23:00:00+02:00","saving":null}],"source":"Nordpool","config":{"maxHoursToSaveInSequence":"22","minHoursOnAfterMaxSequenceSaved":"2","minSaving":0.02,"sendCurrentValueWhenRescheduling":true,"outputIfNoSchedule":false,"contextStorage":"memory"},"sentOnCommand":false,"time":"2022-09-16T23:40:41.117+02:00","version":"3.6.2","current":false}
I believe you have interpreted the result incorrect. It finds the best saving at 08:00 on the 16th, and it saves for 22 hours, that is your maximum. That period is selected first. Then it selects some additional periods that also gives savings, but there is no room for other that long periods. This is how Best Save is supposed to work. You can try yourself here: https://powersaver.no/faq/best-save-viewer.html#tool
If you expect another result, maybe what you need is the Lowest Price node?
I guess I want a lowest price node that finds the lowest price for the configured amount of non-consecutive hours but still provides power on other scattered hours where the price is low (a configurable % diff from min/avg/max) in the selected period.
Regardless, bestsave logic/idea seems a bit broken. If it is set with recovery for 2 hours after a 22 hour period, there is no need for bestsave to power on for 2 consecutive much pricier hours at scattered times within the 22 hour saving period as well. It should only power on for single hours beyond the 2 hours configured for recovery.
I don't understand why these would be ON since their price is much higher than the minimum price in that period: {"price":3.4011,"onOff":true,"start":"2022-09-17T19:00:00+02:00","saving":null}, {"price":3.5651,"onOff":true,"start":"2022-09-17T22:00:00+02:00","saving":null}, {"price":3.8011,"onOff":true,"start":"2022-09-17T23:00:00+02:00","saving":null}
I dont't think you understand the idea with the Best Save node. It assumes that energy is consumed more or less continuously, like you do with a water heater, for example, or a jacuzzi, etc. However, it is also assumed that you can postpone the "replacement" of the consumed energy, that is you can postpone heating the water, and the idea is that you can postpone this up to a certain number of hours. But you postpone only if that makes you save money. If there is nothing to save, there is no reason to postpone. Then you can just as well heat the water immediately.
For me it makes little sense to postpone for 22 hours. If that is ok, you can just look for the 2 cheapest hours in the whole day and use them. That is what you do with the Lowest Price node. The Best Save node looks for the optimal places to postpone consumption within the rules that are configured. And it is absolutely not broken. And as far as I can see it is working well in your case too. Maybe not what you want, but it is working as it is supposed to do.
I'm using it for my water heater. Usually 2 hours/day is enough. Sometimes not (so I wouldn't mind it to heating the water during some slightly more expensive hours also - especially if they are scattered a bit throughout the day).
I just think in my example it shouldn't have planned to heat water in the mentioned hours where the price was 2x or 3x higher than just a few hours earlier in that day.
On the 16th it shouldn't have heated these hours: {"price":5.1421,"onOff":true,"start":"2022-09-16T06:00:00+02:00","saving":null} {"price":5.8301,"onOff":true,"start":"2022-09-16T07:00:00+02:00","saving":null} (which were directly following these much cheaper hours: {"price":2.2841,"onOff":true,"start":"2022-09-16T04:00:00+02:00","saving":null} {"price":3.1831,"onOff":true,"start":"2022-09-16T05:00:00+02:00","saving":null}
Instead if could have heated these hours on the 16th: {"price":3.4701,"onOff":false,"start":"2022-09-16T21:00:00+02:00","saving":1.86} {"price":3.3911,"onOff":false,"start":"2022-09-16T23:00:00+02:00","saving":1.781}
Are you able to explain why you think the bestsave plan in my example is better than my proposal?
Consider this; on 16th the plan started heating at 4AM. At this point and also at 5AM, 6AM and 7AM it only knows the price until midnight... so it doesn't know the price 22 hours ahead. It does however know that at 9PM and 11PM (last hour it knows the price for) the price is going to be cheaper than at 6AM and 7AM. Despite this, it choses to heat 6AM-7AM (Directly after a 2-hour recovery period where one would expect the water to be fully heated)...? It just doesn't make sense.
@vidarak What @ottopaulsen said.
If you want to make sure you heat water at the cheapest periods, use the "lowest price" node. I'm using two of them, each looking at a 12hour interval, to make sure I run the heater at least a couple of hours every 12 hours. See my response here for details.
Thanks, I'm not a developer but I was hoping to fix this by building my own forked and optimized powersaver module. As a start, I'm now using the dynamic configuration option.
It checks if tomorrow's price data is available and configures Lowest Price from 14:00 to 14:00 based on that. (if not, from 00 to 00). It also looks at price deviation beyond the configured hours while considering how many hours have passed since the water last reached max temp (no power drawn while switch is still on) to possibly add a couple of extra hours. If the price in the evening (2300) is high (prices likely trending upwards) it will try adding an extra hour today. If the price in the evening is low, it will avoid adding extra hours that day (anticipating lower prices the next day). Saturdays and Sundays I add an extra hour just because prices are typically low.
Code is ugly and not rigorously tested/tuned so prefer not to share publicly yet (It should have heated 2 hours today). ;-)
I have a very similar issue, that is clearly visible in the chart above. The algorithm above finds the hour with lowest cost, and then run for the recovery time.
The issue I have is that the lowest cost for the recovering time may not start on the our with lowest cost, it may very well be some hours before if you are recovering for several hours.
Take a look at the image from @vidarak. It starts at about 6 in the morning, and then recovers during the most costly time of day. That is because the least costly and most costly hours are next to each other.
What would be more interesting, for an end user perspective, is to have the recovery during the least costly period, not starting on the least costly hour. In this case it may have been better to start an hour earlier to avoid the very costly time.
Instead of doing:
- Find least costly hour
- Add recovery time to this hour as period end time, regardless of price on recover hours
Consider doing:
- Foreach possible start period
- Summarize price for current period + recovery duration and remember price as a possible recovery period
- Use the least costly period
It is true that the algorithm assumes that you recover all the saved energy during the first hour of recovery, and as you suggest, it would have been more accurate to use the average price for all the recovery hours. I will consider making such a change.