Home Assistant: Nord Pool cheapest hours with AIO Energy Management
I’ve already done couple of iterations of finding Nord Pool cheapest hours every day using Home Assistant templated sensors and bunch of helpers and automations. It can really get complicated when using multiple sensors and copy-pasting the automations. Not to even mention about changes in the code for updates! But, the help is now here: I’ve done a huge revamp of the cheapest hours system and everything is now much easier to configure and maintain. Behold the AIO Energy Management integration!
But, before continuing let’s go back a bit.. During early summer I started finding a way for my solar energy to be used along with Nord Pool. Trying to decide when to use solar and when to use grid energy. Things got really out of hands and the automation came out as a mess. Then it hit me: I’ll write a Home Assistant custom component as an integration, so I can write everything with Python and re-use code without making tons of copy-pasting from an automation to another. The work is now done for the Nord Pool part, but solar management is still to be implemented. Now it’s a good time to make the first MVP release..
What is AIO Energy Management?
AIO Energy Management is a custom component for Home Assistant that currently supports finding cheapest or most expensive hours for energy using Nord Pool prices, so mostly targeted for nordic European people using Home Assistant! It’s meant to replace my old creation of cheapest hours and cheapest hours with calendar.
Why it’s called All-In-One Energy Management, if it’s just using Nord Pool you might ask? Well, this integration is planned to become a solution handling all my energy management needs including solar power and later also include other regions of electric stock market*. A long way to go for actually becoming AIO solution, but hopefully I’ll get there someday..
*Need to support for your regions electric stock market? Write an issue to my GitHub repository or write a comment below and lets see what can be done..
Setting up the integration
Definitely the best way to install AIO Energy Management is to use HACS. Using HACS will provide you automatic installation and providing updates. On updates your job is only to check for possibly breaking changes and press the update button.
To install using HACS either press ‘Open HACS repository on Home Assistant‘ -button below or manually setup the custom repository.
Automatic setup:
Manual Setup:
- Go to `HACS` -> `Integrations`
- Select `…` from upper right corner
- Select `Custom repositories`
- Add `https://github.com/kotope/aio_energy_management` and select Category as `Integration`
- Search for `AIO Energy Management` and select it
- Press `Download`
- Restart Home Assistant
Using Nord Pool cheapest hours binary sensor
The first released component of AIO Energy Management is the Nord Pool cheapest hours sensor. This sensor will provide a binary_sensor type that will turn ‘on’ when the cheapest hour is active and ‘off’ when not making it easy for automations to make proper device actions (see ‘automations’ section for more details).
To use the Nord Pool cheapest hours binary sensor, a Nord Pool integration must be installed and configured first. To do that, check installation instruction from the Nord Pool integration GitHub.
The cheapest hours configuration has all the same features as earlier version of the automation: finding number of hours from a specified time frame, getting the expensive hours and of course a failsafe functionality in case of data fetch failure.
All the configuration is done through configuration.yaml and no config flow is supported at the moment. The table shown below presents all the configuration parameters to make the cheapest hours sensor to suit best for your needs!
configuration | mandatory | description |
nordpool_entity | yes | Entity id of the nord pool integration sensor. Look this from your nord pool integration! |
unique_id | yes | Unique id of this entity |
name | yes | Friendly name of the sensor. Is the one shown on UI and marked on energy management calendar if in use. |
number_of_hours | yes | Number of cheapest hours to seek. This can either be a number between 24-1 or dynamic entity_id. If entity_id is given, the value will be read from that entity when locking in the next cheapest hours sequences. |
first_hour | yes | Starting hour (0-23) |
last_hour | yes | Ending hour (0-23) |
starting_today | yes | True if the look up should be started on today. Note that if set to true, the starting hour must be after nord pool price publish (about 14.00 CET). False if only tomorrow prices should be looked for. |
sequential | yes | True if required to find sequential cheapest hours. False if multiple slots are ok. |
failsafe_starting_hour | no | Failsafe starting if nord pool price data can’t be received by external reason. Setting for example to 22, the binary_sensor value will be set as ‘on’ at 22.00 if no electric prices are received by that time. |
inversed | no | Want to find the most expensive hours? Set to true! |
Ok, the parameters are now introduced.. here’s a full example that can be set into configuration.yaml. The following example has two sensors: one for cheapest and one for most expensive hours. Note that the example of expensive hours uses a helper input_number entity to get dynamic number of hours to seek.
aio_energy_management:
cheapest_hours:
- nordpool_entity: sensor.nordpool
unique_id: my_cheapest_hours_sensor
name: My Cheapest Hours
first_hour: 21
last_hour: 12
starting_today: true
number_of_hours: 3
sequential: False
failsafe_starting_hour: 22
- nordpool_entity: sensor.nordpool
unique_id: my_expensive_hours_sensor
name: My Expensive Hours
first_hour: 20
last_hour: 16
starting_today: true
number_of_hours: 2
sequential: False
inversed: true
Once the configuration is in place, just restart your Home Assistant and enjoy the newly created sensor(s)! The sensors can be easily found from settings -> devices & services -> entity -tab. Just look for ‘AIO Energy Management‘ integration π
AIO Energy Management Calendar
AIO Energy Management can create you a calendar to present all upcoming energy management events, like upcoming cheapest hours or expensive hours slot. The calendar is purely optional, but it can be used to trigger an automation as in with my old template/helper/automation based implementation.
To configure calendar to be used, just setup ‘calendar’ slot in the ‘aio_energy_management’ configuration section and add ‘unique_id’ and ‘name’ as parameters. Everything else is done automatically, just enable and restart Home Assistant!
Once restarted, go to Home Assistant -> Calendar and you should see a newly created calendar with the name you gave during configuration!
Example configuration below:
aio_energy_management:
calendar:
name: My Energy Management Calendar
unique_id: my_energy_management_calendar
NOTE: Cheapest hours sensor failsafe is not marked on the calendar!
Automations
Then the most interesting one, how can I do the automations based on the cheapest hours? Well, it’s almost too easy with AIO Energy Management Cheapest Hours component: just set the automation to follow ‘on‘ and ‘off‘ states of the binary_sensor!
Here’s an example aution of using triggers ids to check for ‘on’ and ‘off’ states of the binary_sensor to toggle dummy input_boolean helper. This way everything can just use a single automation! Of course it’s possible to create one for ‘on‘ and one for ‘off‘ states, it’s up to you really which way you prefer, just follow the binary_sensor status π
alias: Cheapest hours turn on switch
description: ""
trigger:
- platform: state
entity_id:
- binary_sensor.my_cheapest_hours
from: "off"
to: "on"
id: turn_on
- platform: state
entity_id:
- binary_sensor.my_cheapest_hours
from: "on"
to: "off"
id: turn_off
condition: []
action:
- if:
- condition: trigger
id:
- turn_on
then:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.test_toggle
else:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.test_toggle
mode: single
Technical details of cheapest hours sensor
If you have no interest about internal and advanced functionality you can just skip this section. But if you want to make some more complicated automations on some specific occasions, you might find this information useful.
The logic of Nord Pool cheapest hours is quite simple: As soon as the Nord Pool data is received from Nord Pool sensor, the data is stored into Home Assistant. The sensor attributes described below might come handy:
Expiration: The data stored contains expiration time that will tell us when we are ready to get new Nord Pool data as we don’t want to make the decision if already on a cheapest hours. The expiration is set just after last_hour.
Updated_at: This value is being set as the time we got the data from Nord Pool. This attribute can be followed on an automation, if we want to trigger some actions when the cheapest hours list is ready.
Failsafe_active: This value will be set to true when we are running on failsafe. Failsafe will be run at given failsafe_starting_hour, if the data expiration has been passed and no new Nord Pool data has been received, Might be useful if we want to do something different when on failsafe..
Active_number_of_hours: this presents the actual value used to get amount of hours. Is either the same value as set on number_of_hours or received from entity if entity_id is used on configuration. This is updated right after data is received from the nord pool sensor and values are calculated! Entity value changes afrer calculations won’t change this!
List: Actual list data of cheapest hours! Might become useful if you want to export the cheapest hours to some external device itself rather than letting Home Assistant to control it.
What next…
Cheapest and expensive hours is now up and running with a failsafe support! However, the work continues. There’s a lot to be done for the cheapest hours implementation and especially with all the other features like solar energy calculations!
Here’s few things you might be seeing in very near future:
- Trigger time.. if you want to wait for some other input before locking in the cheapest hours. Currently the cheapest hours slot is locked as soon as the energy prices are published by Nord Pool!
- Multi state sensor. Want to avoid high prices and prioritise the low prices? A sensor with ‘low’, ‘normal’ and ‘high’ should do the trick
- Use of solar forecast integration to make entries of the best solar hours!
And in a long run .. mixing up solar forecast and Nord Pool cheapest hours to get the best out of all!
Anything else? Need a support for another electric stock market or other new fancy feature? GitHub contributions are always welcome and please leave a comment below if you are looking for something specific!
Update: Want to use Entso-E instead of Nord Pool? It’s now available with AIO Energy Management 0.2.0
N I C E
Hello!
I cant get the calendar to display the events. What could be wrong?
Hi!
But you can see the correct calendar?
Does your binary_sensor attributes contain ‘list’-attribute with values?
You could also enable debug logging by adding following line(s) to the configuration.yaml to see what’s going on:
logger:
default: warning
logs:
custom_components.aio_energy_management: debug
Hi!
I do have the calendar (literally copy-pasted all your settings). I have the “My Energy Management” calendar and I also have one of your previous blog posts, the “electricity” calendar. I also have the “Cheapest hours energy” under the “electricity” calendar, not in “My Energy Management” calendar, which does not make sense to me but ok. In Settings > services > entities I have the My Cheapest Hours (binary_sensor.my_cheapest_hours) and the My Expensive Hours (binary_sensor.my_expensive_hours) BUT they have a mark of red circle and “not provided” status. Does this all make sense?
Also, couldnt run debugger, said Failed to restart Home Assistant
Invalid domain custom_components.aio_energy_management, but I just downloaded and reinstalled it, did everything from top to bottom in this blog post.
Thank you for your effort in resolving it π
Hi!
Just realised that maybe the guide is not 100% clear on the configuration part. calendar and cheapest_hours sensors need to both be in the same block under aio_energy_management and there should not be aio_energy_management component defined twice. Could this be the case on your issue?
Here’s an example of the config I’m using myself.
aio_energy_management:
calendar:
unique_id: energy_management_calendar
name: Energy Management Calendar
cheapest_hours:
- nordpool_entity: sensor.nordpool_kwh_fi_eur_3_10_024
unique_id: my_cheapest_hours
name: My Cheapest Hours
first_hour: 21
last_hour: 12
starting_today: true
number_of_hours: 3
sequential: false
failsafe_starting_hour: 1
- nordpool_entity: sensor.nordpool_kwh_fi_eur_3_10_024
unique_id: my_expensive_hours
name: Expensive Hours
first_hour: 0
last_hour: 22
starting_today: false
number_of_hours: 2
sequential: false
failsafe_starting_hour: 1
inversed: true
If you wish, you could send me your configuration.yaml to creatingsmarthome (at) gmail.com and I’ll have a look. π
Nice work! Im going to try out this one. Is there a possibility to add multiple time ranges in to on sensor? like 00-06 and 12-18 and seek one hour in both ranges?
And does the upcoming 15min market effect on to this? Would love to see adjustable span to optimize heat pumps etc for enought long periods to heat up dhw ie.
Yes it’s possible to add another time range of course, just add another entity into configuration like the expensive hours in the example.
15min market is still quite far away, but of course when it’s released from Nord pool this will support it at the time. Would be a breaking change though π
Yeah I did it that way but all automation requires both entities now. Testing out it with DHW currently which only requires two cycles in a day.
Does the automation fetch all hours after reciving new spot prices from Nord pool or before first hour?
This integration (aio energy management) calculates all data as soon as Nord pool prices have been fetched.
Only exception is if the last_hour is set after price publishing. In that case, the new prices will be calculated once last_hour has passed. Called “expiration” in attributes.
I’m currently improving the functionality by adding an optional ‘trigger_time’ so you can specify a time after the prices should be calculated. This feature is not yet ready though.
Oh I see. I think thats why it didnt work on the first cycle. Additional trigger time or even a force button would be nice if you upgrade the sensors itll require full cycle before it starts to work.
Hello,
First – thanks π
I have installed everything and it works – but I cannot see the “my_expensive_hours” – sensor under entities.
I only have the cheapest_hour -sensor.
Not sure what you mean with “Note that the example of expensive hours uses a helper input_number entity to get dynamic number of hours to seek.”
Do I need to create that helper for it to work?
I have used your configuration examples in configuration.
Hi!
You can also add integer value instead of an entity. Similar to cheapest hours example (number_of_hours: 3)
If you wish to use dynamic value from a helper, you need to create that helper yourself of course.
Yes, I realised my mistake (still newbie on HA…)
It works fine, thanks!
I have followed your projects for a while and like the way you are heading.
Have you had a look at Emhass? (Energy Management for Home Assistant) https://emhass.readthedocs.io/en/latest/intro.html
Its feels like its in the direction you are heading and it also runs python.
Hi!
I’ve checked that out briefly, but it feels quite complicated.
Though eventually my integration could end up to be as complex as well, since the logic is not straight forward in all the cases.. but let see π
Hello Toni, thanks for the good explanation. It is working fine for me now. In my calendar i see the cheapest and expensive hours. It is just not clear to me how i can set my waterboiler to make use of this so that it can heat at the cheapest hour.
Hi!
You should just turn on the waterheater when cheapest hours binary_sensor changes it state to ‘on’ and vice versa.
Create a new automation and the example configuration below that controls the input_boolean.
I guess you have a switch entity to control the water heater so change your data to match the example π
Let me know if you need more help. You can also mail me at creatingsmarthome (at) gmail.com.
I got it working, thanks very much.
I used your scripts before but this seems much better, but cannot get it to work.
Im apparently doing something wrong. But I only copied your config and changed to another nordpool entity (swedish kronor). And get this error.
Any idea what could be wrong?
2024-08-28 20:29:29.985 DEBUG (MainThread) [custom_components.aio_energy_management.coordinator] Query data from store for my_cheapest_hours
2024-08-28 20:29:29.985 DEBUG (MainThread) [custom_components.aio_energy_management.nordpool_binary_sensor] No stored value found for my_cheapest_hours or value is expired. Request new data from nord pool integration
2024-08-28 20:29:29.986 ERROR (MainThread) [custom_components.aio_energy_management.math] Invalid configuration for non-sequential cheapest hours sensor
2024-08-28 20:29:29.986 DEBUG (MainThread) [custom_components.aio_energy_management.nordpool_binary_sensor] No valid data found. Check failsafe
Hi Joel!
If you’ve copied the example as is, you should define helper for input_number.my_input_number used on my_expensive_hours.
The example uses dynamic hours for this specific entity π
You can replace input_number.my_input_number with some static number as well.
If you still have problem after this change, you can mail your configuration me to creatingsmarthome (at) gmail.com and I canhave a look if there’s something odd in there
at what time does the new nordpool data comes in? after Expiration ie 21 if thats my last hour?
Hi!
Yes, current versio fills new data after expiration, if Nord pool data is available. If not available yet, then right after data is published.
Next version will have the new data set as soon as it is published.
Tyvm π
Really nice and easy to integrate. Is it possible to add half hours or minutes. By example 1:30 or 90 minutes?
Hi!
Currently only full hours are supported.
I’ll add this feature request to end of me TODO list and see if something can be done at some point (don’t hold your breath though as TODO list is quite big already..) π
Hi Toni!
Amazing work!
Just wondering can u make multiple calendar entry.
Example: 5 cheapest hours and 3 cheapest hours and also 2 expensive hours.
For my config calendar accepts only last calendar entity.
Binary sensors work great, but calendar won’t work.
Hi and thanks for the feedback! π
Multiple calendar entities should work, at least it’s working in my env as should.
Make sure you’ve defined your calendar only once in the configuration, e.g. calendar should not be defined in every sensor.
Also current version will remove the calendar entry as soon as the data expires. That is after last_hour has been passed. If you think that could be reason in your case, check again after nord pool prices has been published again.
If you think it’s still not working properly, you could open an issue on the GitHub project page and try to describe the error situation as detailed as you can. I’ll try to fix it then π
Jep. My bad. I try to use same unique id in sensor and calendar. When i take “silmΓ€n kΓ€teen” and read your instructions… Everything works fine. π Thanks!
Great work!
Thank you very much for your feedback! ..and even more thanks for the coffees π
Hi Toni.
Awesome work and thank you for adding the max_price parameter.
Should it be possible to use input slider as a input for the max_price?
I have troubles to get it to work. Does it matter which decimal separator is used comma/dot?
Error i got:
This error originated from a custom integration.
Logger: custom_components.aio_energy_management.binary_sensor
Source: custom_components/aio_energy_management/binary_sensor.py:71
integration: AIO Energy Management (documentation)
First occurred: 20:15:19 (1 occurrences)
Last logged: 20:15:19
Configuration validation error for nord pool cheapest hours sensor: expected float for dictionary value @ data[‘max_price’]
Hi!
Currently max_price only supports decimal so no dynamic slider can be used. I will add it to next release though.
Use dot as decimal separator. Full integers should also be entered as decimal numbers. E.g 5 should be configured as 5.0 on max_price
Hi Toni!
I’ve previously also used your HA integration to select cheapest hours. Recently I noticed on your github page this new integration and its trigger_time possibility with number_of_hours set by input_number entity. And hurried upgrading to this new integration. The end goal was to being able to set the required number_of_hours entity to heat up the water heater with actually needed hours, based on a script calculating it.
After I did not get it to working, I came to here and noticed that number_of_hours is locked when Nordpool data is received. Bummer. And the trigger_time is not implemented yet. Double bummer. I commented out the trigger_time and got the integration working. But my simple script ain’t doing its job as it should, because it keeps changing, but it’s value is taken in use 7-8 hours before I anticipated it would.
Well, I have to keep checking here, to see when they are implemented. π
Thanks!
Hi!
trigger_time is already implemented with latest 0.3.0 and should work if you are running the latest version π
Oh sorry, you meant that trigger_time should be from entity. That’s not quite there yet.
The next version should be ready next week and hopefully I can get it implemented for that release. Shouldn’t be a big task.
I meant that trigger_time is set in configuration.yaml, but the number_of_hours should be read from the input_number entity at the time set with trigger_time in configuration.yaml.
IIRC, when I was building the automation I noticed that the number_of_hours input_number entity was read when new nordpool data came available. And because my input_number entity keeps updating higher as the water heater temp goes down, the amount of hours selected was 8-10 hours old value, not the value it had at the trigger_time moment.
It should update again at the point when trigger_time is reached with the latest 0.3.1 version.
Maybe update should not be done before trigger_time at all, but anyhow the lock-in should happen on trigger_time hit.
I’ll fix the update to be ignored before trigger_time hit for the next release.
Hello, Toni!
Thank you for the excellent integration. Iβve been using it for about a year now.
Currently, Iβm using the AIO Nordpool configuration, and itβs been working well overall. However, after the recent daylight saving time adjustment, it seems like the times are now shifted by an hour. For example, today we have the highest Nordpool price between 15:00-16:00 (for a setup for 2 expensive hours), but in the calendar, itβs showing as 15:00-17:00.
Thank you for your help!
Haralds
Hi Haralds!
Just checked my calendar and it seems to work as should (now GMT+2). Which timezone are you in and which Nord Pool region are you using?
The winter/summertime conversions are not currently implemented, so Sunday + Monday could have gone a one hour off in theory, but it should work by now already.
First I’d suggest to restart Home Assistant and see if tomorrow is going to be ok.
Br, Toni
Restart helped. Now it generated tomorows hours and it looks correct.
Thank You!
Thanks for your integration. I’m not sure if I fully understand all the parameters, espessally starting_today, sequential and failsafe_starting_hour is confusing.
I want to get 16 cheapest hours during the day (24h) to trigger my water heater, this is my config:
aio_energy_management:
cheapest_hours:
– nordpool_entity: sensor.nordpool_kwh
unique_id: nordpool_cheapest_hours
name: Nordpool Cheapest Hours
first_hour: 0
last_hour: 23
starting_today: false
number_of_hours: 16
sequential: False
failsafe_starting_hour: 01
– nordpool_entity: sensor.nordpool_kwh
unique_id: nordpool_expensive_hours
name: Nordpool Expensive Hours
first_hour: 0
last_hour: 23
starting_today: false
number_of_hours: 8
sequential: False
inversed: true
Cheapest sensor have this attributes:
List
– start: ‘2024-11-09T00:00:00+01:00’
end: ‘2024-11-09T15:00:00+01:00’
– start: ‘2024-11-09T16:00:00+01:00’
end: ‘2024-11-09T17:00:00+01:00′
Active number of hours
16
Failsafe
start: ’01:00:00′
end: ’17:00:00’
Expiration
November 10, 2024 at 12:00:00 AM
Updated at
November 8, 2024 at 5:00:28 PM
Fetch date
November 8, 2024
Maybe it will reset tomorrow?
Hi!
Config looks ok, but avoid using leading zeros on hour configuration. Should be failsafe_starting_hour: 1
– starting_today should be set to true if you want to seek cheapest hours on two different days (eg. 22:00 (today) – 08:00 (tomorrow))
– failsafe is used if Nord pool data is not received by the time failsafe starting is set (e.g. nordpool service or network error for full day..)
– sequential is used when consequtive cheapest slot needs to be found.
Your values will update every day as soon as Nord pool publishes new next day prices. So tomorrow next time.
Btw, you must have huge water heater if you need to heat 16 hours π
Hi,
thanks for your reply.
You’re right about number of hours, 16h is probably to much. But the hot water tank is almost empty after morning showers, and I need to be sure it’s warm again in the evening when kids are coming home from sports. So in essens, I want it to heat during the night and during the day – say 10-16. I don’t have any external temp sensor on the tank, and my girls (kids and wife) will kill me if shower is ice cold π
Ha, I understand π
Maybe a better approach instead would be to avoid highest hours in your case?
You can do it by setting ‘inversed: true’ and change number_of_hours to hours avoid, in your case: ‘number_of_hours: 8’
..And of course change to automation to turn on the water heater on ‘off’ state and vice versa.