Home Assistant: Nord Pool Spot prices and how to automate devices for cheapest hours

Most of this information can already be found around the internet, but since I wanted to integrate one as well for my Home Assistant instance, why not to share the same with you?

So, the energy prices have gone up by a mile. The best way to balance the energy bill is to schedule some devices to cheapest hours of the day.. those devices could be something like washing machines, water boilers or car charging? Most of the devices needs a specific timeframe to run so sequential cheap hours are needed instead of scattered ones. It’s generally a bad idea to run a washing machine at 01:00, pause it at 02:00 and then continue at 05:00 🙂

Integrating Nord Pool to the Home Assistant

First we need to get the Nord Pool prices into the system so a new integration is needed. Luckily (again) someone has already made it happen and it can be installed using HACS. If you don’t know what HACS is, it’s a Home Assistant Community Store, a place where tons of integrations and frontend elements are published and can be easily installed. Just need to remember that those are not official Home Assistant components and are maintained by individual people and therefore can break more easily than official ones.

Anyway, start by installing Nord Pool custom component. This integration does not have UI configuration so the has to be done manually to the configurations.yaml.

For example, here’s my config:

nordpool:

sensor:
  - platform: nordpool
    VAT: true
    currency: "EUR"
    price_in_cents: true
    region: "FI"
    precision: 3
    price_type: kWh

In above configration firstly we enable the integration and second we configure the sensor to use region Finland and currency in Euros. Some tweaking to precision and VAT is also done, but more configuration details can be found from the integration repository.

After everything is configured, restart the Home Assistant and continue to the UI part.

Making the UI

First let’s find the entity id from our integrations. In Home Assistant go to Settings->Devices & Services->Entities and search with the filter ‘nordpool‘. You should find a entity id (that is same as unique id) and write it down somewhere. Unique id is generated by the Nord Pool integration from the configuration we made in the previous chapter.

For this part I’m using Apex Charts Card that is very versatile graphical presentation card of various values. Again, this frontend card can be installed using HACS. So go to the HACS and search for Apex and install it.

After installation is succeeded, it’s time to configure two cards (one for today and one for tomorrow).

Here’s my configuration for the cards (example UI shown at the end of this chapter):

type: custom:apexcharts-card
graph_span: 24h
header:
  title: Energy price today (snt/kWh)
  show: true
span:
  start: day
now:
  show: true
  label: Now
series:
  - entity: sensor.nordpool_kwh_fi_eur_3_10_024
    type: column
    data_generator: |
      return entity.attributes.raw_today.map((start, index) => {
        return [new Date(start["start"]).getTime(), entity.attributes.raw_today[index]["value"]];
      });
type: custom:apexcharts-card
graph_span: 1d
header:
  title: Energy price tomorrow (snt/kWh)
  show: true
span:
  start: day
  offset: +1d
series:
  - entity: sensor.nordpool_kwh_fi_eur_3_10_024
    type: column
    data_generator: |
      return entity.attributes.raw_tomorrow.map((start, index) => {
        return [new Date(start["start"]).getTime(), entity.attributes.raw_tomorrow[index]["value"]];
      });

Again, you can use the same configurations, just remember to change the proper entity id for the cards (the one that we wrote down in previous chapter).

That’s it! Now there should be todays electrical spot prices and tomorrows spot prices available in the Home Assistant for any use!

To make it smart keep on reading the next chapters..

Finding the cheapest hours

One of the key points of having Nord pool is of course finding the cheapest hour(s) and automate devices to run during those hours.

For this I’ve created a template sensor that ensures validity of next day prices (usually published by Nord Pool at 12:00) and finds the sweet spot of requested lenght!

It’s easily modifiable by changing numberOfSequentialHours (how long period are we looking for), firstHour (first possible hour we want to start) and last hour (final hour we want to stop latest). E.g. you can also use it to find cheapest hours during the next night by setting the last hour to something like 06:00.

NOTE 2022/09/19: There was a bug in the calculation previously that has been now fixed. If you copied the template before that, please copy the new template below!

sensor:
  - platform: template
    sensors:
      cheapest_hours_energy_tomorrow:
        device_class: timestamp
        friendly_name: Cheapest sequential electricity hours
        value_template: >
          {%- set numberOfSequentialHours = 3 -%}
          {%- set lastHour = 23 -%}
          {%- set firstHour = 0 -%}

          {%- if state_attr('sensor.nordpool_kwh_fi_eur_3_10_024', 'tomorrow_valid') == true -%}
            {%- set ns = namespace(counter=0, list=[], cheapestHour=today_at("00:00") + timedelta( hours = (24)), cheapestPrice=999.00) -%}
            {%- for i in range(firstHour + numberOfSequentialHours, lastHour+1) -%}
              {%- set ns.counter = 0.0 -%}
              {%- for j in range(i-numberOfSequentialHours, i) -%}
                {%- set ns.counter = ns.counter + state_attr('sensor.nordpool_kwh_fi_eur_3_10_024', 'tomorrow')[j] -%}
              {%- endfor -%}
              {%- set ns.list = ns.list + [ns.counter] -%}
              {%- if ns.counter < ns.cheapestPrice -%}
                {%- set ns.cheapestPrice = ns.counter -%}
                {%- set ns.cheapestHour = today_at("00:00") + timedelta( hours = (24 + i - numberOfSequentialHours)) -%}
              {%- endif -%}
            {%- endfor -%}
            {{ ns.cheapestHour }}
            {%- set ns.cheapestPrice = ns.cheapestPrice / numberOfSequentialHours -%}
          {%- endif -%}


Finally making the automations

Now that we know the cheapest hours for the next day, only thing to do is actually do the automations for various devices.

My automation is actually in two parts:

  • First I save the cheapest hour(s) at 23:10, because we can’t be following ‘tomorrow’ state after midnights since it obviously is not ‘tomorrow’ anymore after that 🙂
    • UPDATE: Time changed from 18:00 to 23:10. If cheapest hours happens between automation start time and midnight, the device might start on a wrong day!
  • Second I run the automation when the time trigger is hit
# Helper to keep the start time
input_datetime:
  device_start_time:
    name: Device Start Time
    has_time: true
    has_date: false

automation:
# Update time trigger to cheapest hours
  - id: '1663398489357'
    alias: 'Set device start time'
    description: ''
    trigger:
    - platform: time
      at: '23:10:00'
    condition:
    - condition: not
      conditions:
      - condition: state
        entity_id: sensor.cheapest_hours_energy_tomorrow
        state: unknown
    action:
    - service: input_datetime.set_datetime
      data:
        time: '{{ as_timestamp(states(''sensor.cheapest_hours_energy_tomorrow'')) | timestamp_custom(''%H:%M'') }}'
      target:
        entity_id: input_datetime.device_start_time
    mode: single

# Finally do the actions when time trigger is hit
  - id: '1663399614818'
    alias: Increase heating
    description: ''
    trigger:
    - platform: time
      at: input_datetime.device_start_time
    condition: []
    action:
    - service: climate.set_temperature
      data:
        temperature: 24
      target:
        entity_id: climate.heat_pump
    mode: single

Nord pool integration have had some issue of not updating properly from time to time (not happened to me though), so with this kind of automation previous day time schedule is being kept if the price template fails for a reason or another. That way no critical devices are left in cold (like water heater).

In my example I’m just increasing heating values, change it to anything you wish to use on cheap hours. Just remember to turn it off as well if the action is not just simple launch action.

If you made it this far, you can also check the ready made Home Assistant package in the next post!

Conclusion

So far so good.. even though I’m currently having still a static electric price for some months, I’m using this automation for the common good. I believe that if it’s possible to time electric consumption for the cheapest hours it will eventually balance the high and lows in general.

Anyway, possibilities to run devices at cheaper prices are great as long as the device has a remote control option! This type of behaviour could be also used for heating to reserve heat into structural parts of the house (e.g. floor heating) during nights.

80 Replies to “Home Assistant: Nord Pool Spot prices and how to automate devices for cheapest hours”

  1. Shouldn’t it be

    {%- if ns.counter < numberOfSequentialHours*ns.cheapestPrice -%}
    {%- set ns.cheapestPrice = ns.counter / numberOfSequentialHours -%}
    {%- set ns.cheapestHour = today_at("00:00") + timedelta( hours = (24 + i – numberOfSequentialHours)) -%}

    ?

    1. Actually you are perfectly right, thanks for pointing the bug out!

      However, I’d rather fix it by removing the whole average calculation and add it on the end (even though the avg. price is not even used).

      I’ve been running this automation myself with a broken implementation (it’s been quite accurate still though) 😀

      Fixed the issue in the post now!

  2. I’m extremely grateful to Your post, during this extremely perfect time 😉
    I have spent couple of nights studying HASS & how to solve hitting heat pump on during cheapest hours. With Toni’s good instructions I have already managed to switch my Shelly on when cheapest hour has been reached, but I’m still lacking how to switch it off, when desired amount of “cheap” hours has been gone. Do you have any idea for this?

    Side note: During today, I have HASS coding experiense almost 48 hours =)

    1. Hi and thanks for the nice feedback!

      There’s couple of ways you can do to switch the things off:
      1. Make another input_datetime entity and set time to it in the same automation with the start time like this: (I use this method)
      device_end_time:
      name: Device End Time
      has_time: true
      has_date: false


      - id: '1663398489322'
      alias: 'Set device/end start time'
      description: ''
      trigger:
      - platform: time
      at: '08:37:00'
      condition:
      - condition: not
      conditions:
      - condition: state
      entity_id: sensor.cheapest_hours_energy_tomorrow
      state: unknown
      action:
      - service: input_datetime.set_datetime
      data:
      time: '{{ as_timestamp(states(''sensor.cheapest_hours_energy_tomorrow'')) | timestamp_custom(''%H:%M'') }}'
      target:
      entity_id: input_datetime.device_start_time
      - service: input_datetime.set_datetime
      data:
      time: '{{ ((as_timestamp(states(''sensor.cheapest_hours_energy_tomorrow'')) + (3600*3)) | timestamp_custom(''%H:%M'')) }}'
      target:
      entity_id: input_datetime.device_end_time
      mode: single

      ..and then of course make automation that listens for this input_datetmime.device_end_time entity and turns off the device.

      2. In the launch action you can use ‘delay’ to wait for 3 hours and then switch the device off. This way the automation stays ‘active’ until process is fully finished (turned on and off).
      For this I do not have an example right now, but I think you got the idea 🙂

      1. Great. Thanks for the fast repply.
        Yes I’ll survive with the device activation part. But that option no. 2… how obvious 🙂

  3. Nice work, It look a lot better than my current code. I have a question if I set firsthours to 22:00 and last hour to 6:00, will it work to search for a six hour span that start at 23 tonight? //Erik

    1. Nope, this currently works only on one full day.

      But your question is something that I’ve been also thinking of implementing.. for that we would need to combine nord pool ‘today’ and ‘tomorrow’ into one array and loop that through. Shouldn’t be too difficult to do some rainy day 🙂

        1. It has rained,
          I hope it will take in account both today and tomorrow when finding cheapest hour to start.
          cheapest_hours_energy_tomorrow:
          device_class: timestamp
          friendly_name: Cheapest sequential electricity hours
          value_template: >
          {%- set numberOfSequentialHours = 1 -%}
          {%- set lastHour = 23 + 24 -%}
          {%- set firstHour = 13 -%}

          {%- if state_attr(‘sensor.el_spotpris’, ‘tomorrow_valid’) == true -%}
          {%- set ns = namespace(counter=0, list=[], cheapestHour=today_at(“00:00”) + timedelta( hours = (24)), cheapestPrice=999.00) -%}
          {%- for i in range(firstHour + numberOfSequentialHours, lastHour + 1) -%}
          {%- set ns.counter = 0.0 -%}
          {%- for j in range(i-numberOfSequentialHours, i) -%}
          {%- if j < 24 -%}
          {%- set ns.counter = ns.counter + state_attr('sensor.el_spotpris', 'today')[j] -%}
          {%- else -%}
          {%- set ns.counter = ns.counter + state_attr('sensor.el_spotpris', 'tomorrow')[j-24] -%}
          {%- endif -%}
          {%- endfor -%}
          {%- set ns.list = ns.list + [ns.counter] -%}
          {%- if ns.counter < ns.cheapestPrice -%}
          {%- set ns.cheapestPrice = ns.counter -%}
          {%- set ns.cheapestHour = today_at("00:00") + timedelta( hours = (i – numberOfSequentialHours -2)) -%}
          {%- endif -%}
          {%- endfor -%}
          {{ ns.cheapestHour }}
          {%- set ns.cheapestPrice = ns.cheapestPrice / numberOfSequentialHours -%}
          {%- endif -%}

          1. A mistake
            {%- set ns.cheapestHour = today_at(“00:00”) + timedelta( hours = (i – numberOfSequentialHours -2)) -%}
            should be
            {%- set ns.cheapestHour = today_at(“00:00”) + timedelta( hours = (i – numberOfSequentialHours )) -%}

          2. Nope this doesn’t work either. I have a new version I’ll check the next 24h before posting a mistake again…. 🙂

          3. This code works.
            sensors:
            billigaste_energi_hushallsmaskiner:
            device_class: timestamp
            friendly_name: billigaste energi hushallsmaskiner

            value_template: >
            {%- set numberOfSequentialHours = states(‘input_number.num_timmar_till_hushallsmaskiner’) | int() -%}
            {%- set lastHour = 24 -%}
            {%- set firstHour = ((as_timestamp(now() ) | timestamp_custom(‘%H’)) | int() ) -%}
            {%- if state_attr(‘sensor.el_spotpris’, ‘tomorrow_valid’) == true and now().hour >=13-%}
            {%- set ns = namespace(counter=0, list=[], cheapestHour=today_at(“00:00”) + timedelta( hours = (24)), cheapestPrice=999.00) -%}
            {%- for i in range(firstHour + numberOfSequentialHours, lastHour +9 ) -%}
            {%- set ns.counter = 0.0 -%}
            {%- for j in range(i-numberOfSequentialHours, i) -%}
            {%- if j < 24 -%}
            {%- set ns.counter = ns.counter + state_attr('sensor.el_spotpris', 'today')[j] -%}
            {%- else -%}
            {%- set ns.counter = ns.counter + state_attr('sensor.el_spotpris', 'tomorrow')[j-24] -%}
            {%- endif -%}
            {%- endfor -%}
            {%- set ns.list = ns.list + [ns.counter] -%}
            {%- if ns.counter < ns.cheapestPrice -%}
            {%- set ns.cheapestPrice = ns.counter -%}
            {%- set ns.cheapestHour = today_at("00:00") + timedelta( hours = (i – numberOfSequentialHours )) -%}
            {%- endif -%}
            {%- endfor -%}
            {{ ns.cheapestHour }}
            {%- set ns.cheapestPrice = (ns.cheapestPrice / numberOfSequentialHours) -%}
            {%- else -%}
            {%- set ns = namespace(counter=0, list=[], cheapestHour=today_at("00:00") + timedelta( hours = (24)), cheapestPrice=999.00) -%}
            {%- for i in range(firstHour + numberOfSequentialHours, lastHour + 1) -%}
            {%- set ns.counter = 0.0 -%}
            {%- for j in range(i-numberOfSequentialHours, i) -%}
            {%- set ns.counter = ns.counter + state_attr('sensor.el_spotpris', 'today')[j] -%}
            {%- endfor -%}
            {%- set ns.list = ns.list + [ns.counter] -%}
            {%- if ns.counter < ns.cheapestPrice -%}
            {%- set ns.cheapestPrice = ns.counter -%}
            {%- set ns.cheapestHour = today_at("00:00") + timedelta( hours = (i – numberOfSequentialHours )) -%}
            {%- endif -%}
            {%- endfor -%}
            {{ ns.cheapestHour }}
            {%- set ns.cheapestPrice = (ns.cheapestPrice / numberOfSequentialHours) -%}
            {%- endif -%}

          4. Tanks a lot Erik!

            I think this your piece of code will help others that are trying to setup two day automation as well 🙂

          5. Hi Erik.
            I don’t seem to get your two day sensor working.
            I think it because intends(configuration valitadion wont pass), but i can’t figure it out.
            Any help, please?

          6. Great work Erik and Toni! Got my automations working perfectly with your examples. I have found that attribute “tomorrow_valid” is’nt reliable anymore. Instead I’m using:
            {% if state_attr(“sensor.YOURNORDPOOLSENSORNAME”, “tomorrow”) [1] is number == true %}
            Also for those who use code from comments of this site. I had to replace minus hyphens from code after pasting to my text editor. Propably due to textcoding differenses with this site and my editor.
            So safe bet is to rewrite whole code your self and use code from this site as refrence. Below is my code (mostly copied from Erik) that works for my automations for now:
            #Note I have added helper “input_number.sequentialhours” and sensor “sensor.time” for automation reasons, but you can use your own variables here or just integers.

            cheapest_sequential_spot_hours_input:
            device_class: timestamp
            friendly_name: Cheapest sequential hours
            value_template: >
            {%- set numberOfSequentialHours = states(‘input_number.sequentialhours’) | int() -%}
            {%- set lastHour = 24 -%}
            {%- set firstHour = states(“sensor.time”)[0:2]|int -%}
            {%- if state_attr(‘sensor.nordpool_kwh_fi_eur_1_10_024’, ‘tomorrow_valid’) == true and state_attr(“sensor.nordpool_kwh_fi_eur_1_10_024”, “tomorrow”) [1] is number == true -%}
            {%- set ns = namespace(counter=0, list=[], cheapestHour=today_at(“00:00”) + timedelta( hours = (24)), cheapestPrice=999.00) -%}
            {%- for i in range(firstHour + numberOfSequentialHours, lastHour +25 ) -%}
            {%- set ns.counter = 0.0 -%}
            {%- for j in range(i-numberOfSequentialHours, i) -%}
            {%- if j < 24 -%}
            {%- set ns.counter = ns.counter + state_attr('sensor.nordpool_kwh_fi_eur_1_10_024', 'today')[j] -%}
            {%- else -%}
            {%- set ns.counter = ns.counter + state_attr('sensor.nordpool_kwh_fi_eur_1_10_024', 'tomorrow')[j-24] -%}
            {%- endif -%}
            {%- endfor -%}
            {%- set ns.list = ns.list + [ns.counter] -%}
            {%- if ns.counter < ns.cheapestPrice -%}
            {%- set ns.cheapestPrice = ns.counter -%}
            {%- set ns.cheapestHour=today_at("00:00") + timedelta( hours = (i – numberOfSequentialHours )) -%}
            {%- endif -%}
            {%- endfor -%}
            {{ ns.cheapestHour }}
            {%- set ns.cheapestPrice = (ns.cheapestPrice / numberOfSequentialHours) -%}
            {%- else -%}
            {%- set ns = namespace(counter=0, list=[], cheapestHour=today_at("00:00") + timedelta( hours = (24)), cheapestPrice=999.00) -%}
            {%- for i in range(firstHour + numberOfSequentialHours, lastHour + 1) -%}
            {%- set ns.counter = 0.0 -%}
            {%- for j in range(i-numberOfSequentialHours, i) -%}
            {%- set ns.counter = ns.counter + state_attr('sensor.nordpool_kwh_fi_eur_1_10_024', 'today')[j] -%}
            {%- endfor -%}
            {%- set ns.list = ns.list + [ns.counter] -%}
            {%- if ns.counter < ns.cheapestPrice -%}
            {%- set ns.cheapestPrice = ns.counter -%}
            {%- set ns.cheapestHour = today_at("00:00") + timedelta( hours = (i – numberOfSequentialHours )) -%}
            {%- endif -%}
            {%- endfor -%}
            {{ ns.cheapestHour }}
            {%- set ns.cheapestPrice = (ns.cheapestPrice / numberOfSequentialHours) -%}
            {%- endif -%}

  4. Does the nord pool integration still work for you after the HA core 2022.9 update?
    Mine doesn’t 🙁

    1. Yes, I haven’t had any problems with it even after 2022.9.

      Have you checked the logs why it fails?

  5. Sorry, I am new to HA. I tried to put that template sensor code to configure.yaml but could not get it working. Could you please give me newbie guidance how to get it working?

    I got those Apex charts card working but not that template for cheapest hours.

    I

    1. I’ve got similar feedback from other channels as well so maybe this is not very clear to people that are new to HA.

      Anyway, template_sensor goes in the configurations.yaml, but the catch is if there’s already sensor: block existing.
      In that case, remove the “sensor:” from above and add after existing block.

      Same goes to automations.yaml, remove “automation:” in there before adding.

      input_datetime also goes into configurations.yaml. No need to find existing items for that one.

      Hopefully this helps. If not, please reply and let’s look more deep into it 🙂

      1. Thank you very much. Now it works and actually i feel really stupid not to got it by myself.

        Luckily there are people like you who makes this world much better place to live 🙂

    1. Hi!

      You can add delay to the start automation and wait for your ‘amount of hours’ after it.
      Other way would be to add another input_datetime that is being setup at the same when start time is updated.
      Then just trigger automation off on that time.

      Ps. I’ve received quite many questions related to this automation so I will write a follow-up near future with examples 🙂

      1. I’ve a delay to turn heater in the office off after 1h. What I need is a switch to turn automation off for example if I’m sick and not working tomorrow or so. Normally it’s always on on weekdays but sometimes I’m not using the office. I already have everything else working but I don’t know how to solve this and I’m sure I’m not the only one who needs this

  6. Thank you so much for sharing this great project!
    Question: is it possible to somehow modify it to work on TODAY’s prices instead of tomorrow’s?

    1. Hi and thanks for the feedback!

      It should be possible quite easily.
      Just use ‘today’ values instead of ‘tomorrow’ and trigger the update same day at 00:00.

      Also tomorrow_valid check should be removed from the automation.

      1. Thanks for the reply!
        I tried doing the suggested modifications, but I don’t think I did it right, since the output seems incorrect to me (tomorrow works fine).
        Could I possibly bother you to paste a modified sensor for today here in a reply or to my gmail? I only have the bare minimum Yaml skills.
        Very grateful for any assistance!

        1. Hi!

          I don’t have example at the moment, but I’ll try it this weekend and post it here after that 🙂

          1. Hi Toni, great post! Has really inspired me to set automatic charging times for our EV. Just as Christoffer has asked, I’ve also tried to make a sensor showing ‘Cheapest electricity today’, but it just shows as unavailable. Would you mind trying to make a new version of the code, which looks for the cheapest time today? Would be greatly appreciated.

          2. Thanks for the feedback!

            This is on my worklist and will create a follow-up post containing this issue as well, but unfortunately I haven’t had time to write it fully yet.

  7. Hello,

    Thanks for sharing the project. This has given me the encouragement to try something similar. I’m planning to control relays with GPIO’s. I have managed to load and show the Nordpool data with Apex charts. In addition controlling relays works now manually by switches in UI. I’m a newbie with this HA. Should these entities “Device Start Time” & Device End Time” be updated on the time given in the code 23:10 & 8:37 when the prices are checked and cheapest hours determined? I’m suspecting that this “Finding the cheapest hours” does not currently work for me…

    1. Yes, the device start time (and end time, if you are using it) should be updated properly at 23:10.

      Do you get any value for the start time or does it stay ‘unknown’ ?

      1. I got the value 10:00 for the Start Time. But not functioning since it is not changing when I test. This entity ” Cheapest sequential electricity hours” does not show up to me. I wonder if I’m doing something wrong in this creation of template sensor. Is it so that all of the following code can be added to the configuration.yaml file, except the apex cards which I succesfully was able to add with the UI?

        1. The automation part goes into automations.yaml, except that you should remove the “automation:” line from it and set the idents properly as in the other automations you have in the file.

          1. Moikka Toni.

            Mulla on jäätäviä ongelmia automaation kanssa. Olen ottanut kuvat word-dokumenttiin mun config- ja automations -fileistä, joka löytyy tämän linkin takaa. Voisitko lyhyesti tsekata missä mättää?

            Olen pyrkinyt tekemään kaiken kuten blogissasi olet ohjeistanut, mutta device.start.time tai device.end.time (helpers) ei päivity ja siten ei kai valokaan (testi).

            https://1drv.ms/w/s!AhLSAx_PmMjU01_9CQ5huTOzfQfq?e=468WDy

          2. Hi!

            At least from automations.yaml lines 9 to 12 idents (sisennys) are wrong, add one more ident tab to those.
            If you need more assistant in Finnish, please send email to creatingsmarthome (at) gmail.com.

            I’ll try to keep this blog English only, since most of the readers are outside Finland 🙂

  8. Hi, and thanks a lot for your examples. I just starting up my automated heating with nordpool cheapest times. There is some things which i still need to understand and get some switch/sensors. But in mean while here are some additions to those charts. This adds values of current bar when hovering over it
    extremas: true
    float_precision: 3

    Also it shows peak points. There is also 24H setting to clock in xaxis (hours_12: false)

    type: custom:apexcharts-card
    graph_span: 24h
    hours_12: false
    header:
    title: Energy price today (cnt/kWh)
    show: true
    span:
    start: day
    now:
    show: true
    label: Now
    series:
    – entity: sensor.nordpool_kwh_fi_eur_3_05_024
    type: column
    show:
    extremas: true
    float_precision: 3
    data_generator: |
    return entity.attributes.raw_today.map((start, index) => {
    return [new Date(start[“start”]).getTime(), entity.attributes.raw_today[index][“value”]];
    });

  9. Thank you. It’s working as intended. As someone else asked about. How about a stop timer? I’m aware of the delay function, but it’s not recommended. Since your math and scripting are beyond mine, shouldn’t it be possible to create a set device stop? I tried with some minus etc. but no cigar.

    1. Hi and thanks for the feedback!

      If you see comment written 23/09/2022 at 05:41, I’ve already wrote a small example how to calculate the device stop time 🙂

      I’m planning to write a follow-up to display all these new information in another post once I manage to schedule some time for that.

      Will the comment (23/09/2022 at 05:41) help you or did you mean something else?

  10. Hi!

    Nice work… planning to do this kind of automation at my summer cottage…

    You have code at the beginning of page… is it updated/modified based these comments? So is it putting AC also off after cheapest hours?

    Also.. I don’t have knowledge to modify this… Is it “wise” to modify and ask you to modify this with low price / high price triggers?

    What I mean that there can be a trigger (best way is that you can modify trigger price with lovelace) where (if high price trigger) AC won’t go on at cheapest hours if price is higher than “high price trigger” and vice versa with low price trigger.

    1. The post itself does not turn anything, only turn on is written down on it. In the comments parts there are also some small pieces of code to turn the device off.

      It would be rather simple modification to just add some ‘high price/low price’ boolean value to check if the device start automation should be run or not.
      I would but the price condition inside ‘device start’ automation to ensure the price is within specified range and not touch the ‘cheapest hours’ template at all.

      These are quite far fetched cases related to this post, but I can help you to get started. You can mail me to creatingsmarthome (at) gmail.com if you need more detailed support with the automations 🙂

  11. Wow, what a fantastic article! I was able to get the Nordpool prices working really easily.

    This will save me a lot of money in the spring when our current contract expires and we move into spot pricing.

    Thank you so much! Excellent work.

  12. How can i swap this for most expensive sequential hours?

    I want to create 2 sensors with interval for example 00:00 – 12:00 and 13:00 – 23:00 and turn of heating during the 3 most expensive hours in each interval.

    1. The most convenient way would be to just change the the less than operator to greater than operator.. and of course I’d recommend to rename the “cheapestHours” variable to “highestHours” or something..

      Conversion like this:
      {%- if ns.counter < ns.cheapestPrice -%}
      =>
      {%- if ns.counter > ns.cheapestPrice -%}

      Disclaimer: I've not tested it out, but it 'should' work

      Edit:
      One more thing, the initial value should also be changed:
      cheapestPrice=999.00
      =>
      cheapestPrice=0.00

  13. Voitko tarkentaa noita ohjeita hieman aloittelijalle sopivammaksi, eli

    Mihin nuo kaksi Apex Charts Card korttia lisätään?
    Mihin tuo sensor-scripti lisätään ja mitä valintoja siihen liittyen mahdollisesti täytyy tehdä?
    Mihin tuo automaatioscripti lisätään ja mitä valintoja siihen liittyen mahdollisesti täytyy tehdä?

    Kiitos!

    1. Apex char cards can be added directly from the Home Assistant UI: Edit dashboard -> Add card -> Apex

      For the sensor and automations scripts, see comment written 05/10/2022 at 05:28. There are details in that one 🙂
      You just need to change the entity id and number of hours you are looking for.

      Ps. I’m replying in English since most of the blog readers are outside Finland 🙂

  14. Thanks for sharing. I copied the card code to get the prices show up as bars, and it works great:). Do you know if it would be possible to show used power history on top of the prices? That would mean to show a line graph with a power sensor as source on the same card, on top of the bars.

    1. Hi!

      I think it should be possible with Apex, but haven’t tried that. Nice idea anyway 🙂

  15. Hi,

    I’m using the nordpool integration. Most of the time it works just fine. However, sometimes a part of data is missing. In the example below, only the data for the first our of tomorrow is available:

    —– quotation, start——
    Tomorrow
    12.272, , , , , , , , , , , , , , , , , , , , , , ,

    Raw tomorrow
    – start: ‘2022-11-02T00:00:00+02:00’
    end: ‘2022-11-02T01:00:00+02:00’
    value: 12.272
    – start: ‘2022-11-02T01:00:00+02:00’
    end: ‘2022-11-02T02:00:00+02:00’ value: null
    – start: ‘2022-11-02T02:00:00+02:00’
    end: ‘2022-11-02T03:00:00+02:00’
    value: null
    —– quotation, end——

    Even rebooting rasp doesn’t load the data.
    Does someone else experience the same issue?
    Do you know any workaround?

    1. I’ve noticed some issues with the nordpool integration as well so that the dat wont load properly, but reloading the integration has been done the trick always.
      Try to use ‘reload integration’ from the integrations for nordpool and see if it helps (I think rebooting should do the same though).

      If it helps, you can set up an automation that reloads the integration for example every day at 14:00

  16. Hi,
    First, thanks for the great work… I think it would be useful addition to have the hours ordered from cheapest to most expensive. Then one could for example choose 4 cheapest hours for the water heater. Or any other use case which does not require sequential hours… I don’t “speak” yaml/jinja2 very well, so I can’t do it… 🙁

    1. That’s a great addition as well. I haven’t myself (yet) seen a purpose for that in my environment, but I’m certain the time will come to utilise that kind of behaviour too.
      Let see if I can find a time slot from somewhere to implement that kind of behaviour.

      1. Hello Toni
        Thanks for your effort adding this feature. I still have a fixed price 0.73 sek until next year. But because of the situation I have started to prepare my home(house) to handle higher prices. I have bought Tado smart thermostat for handle the heating of my house and Telldus to switch on and of the light depending on where I am and the actual prices. I have also ordered a Ngenicic Tune that will help me to simulate the outside temperature and force my Nibe heating system to work more economic.

        I have now a Polestar 2 and a Easee charger that I can control from HA. I have tested your code and it works, but I also waiting for a rainy day 🙂 when you perhaps will have time for adding 48 hours support for your smart code :).
        Charging the car when it cheaper will really save money, of course I have a timer both in easee and in the car , but it will be much better if it will be automatic. I wish you Good day
        Regards Jonas

        1. Hi!

          Thanks for the feedback!
          Two day automation is on my TODO list and will get to that right after I’ve finalised next post about installing cheapest hours automation through packages 🙂

          1. Hi again
            Starting to understand jinja2 now and also your code.
            I have a ongoing loop in my head thinking about this. 🙂

            A Good solution would be to do the calculation 15 pm everyday an then add 15 to 24 from today and 00 to 15 from tomorrow nordpool data. Then we will always have 24 hour data to eork with.

            A question to you Toni. What will happend with the data if the HA is rebooted or s powerloss after the calculstion is done? Will the data in the helper remain?
            Have a Nice day

          2. Hi!

            Yes, a good solution would be to have more configurable timeframe (24h) between today and the next day. This is also in my expanding worklist 🙂
            …but the data will need to be max. 24h otherwise a date would needed to be kept inside the helpers and that brings up quite much complexity again.

            For your questions: helpers will retain their values through restart. (This was not the case a year or couple ago, but today it is :-))

  17. Hi
    I’m a total newbie on this.
    But anyone have a clue why even the first step failed.
    I installed Norpool
    I found the ID
    I Installed the apex
    but then when i tried to make the Grapf UI Card with the example code

    It gives error
    Custom element doesn’t exist: apexcharts-card.

    type: custom:apexcharts-card
    graph_span: 24h
    header:
    …..

    1. Looks like apex-charts is not properly loaded as a resources in your UI.

      Have you tried to restart Home Assistant and/or clear cache of the browser?

  18. Hi,
    I’m quite new to HA and this is i a really nice thing to have because of the rising electrical prices. Have got the two cards working correctly but i haven’t figured out where should i copy the template and trigger automation? Should i paste something to configuration.yaml to?

      1. Hi,
        Minutes after my comment i saw you had did a new post 🙂 Super!
        I already tested that but got the message :

        bad indentation of a mapping entry (17:11)

        14 | {%- set lastHour = 23 -%}
        15 | {%- set firstHour = 0 -%}
        16 | # CHANGE-ME: change entity to your own se …
        17 | {%- if state_attr(‘sensor.nordp …
        —————-^
        18 | {%- set ns = namespace(counte …

        1. Sorry that’s my bad, I forgot to add the indentations to the added #CHANGE-ME comment blocks.
          Thanks for pointing that out!

          The fixed version should be in GitHub now 🙂

  19. Is there possibility for some kind of failsafe ? Eg. if for some unknown reason you won’t get nordpool data at all for long time (maybe week or something) it would still turn water heater on 02.00 am -> 06.00 am.

    1. Yep, this automation has failsafe to run the device based on previous day.

      Could be easily converted to run on static time e.g. 02-06 by creating an ‘else’ branch/condition in the ‘Set device start time’ automation.

  20. This is absolutely great Toni !

    I set up this yesterday for my EV charger. I replaced power key with Sonoff Mini and installed your solution to turn charger on. Voila ! Now I can charge my vehicle during cheapest hours in the night. It just works 🙂
    Keep up the good work 🙂

  21. This is very good. Just a few notes.

    To get 24 hour times you can add “hours_12: false” in the card. No more am/pm sillyness.

    Also this is a slightly simpler way to get the series data:
    return entity.attributes.raw_today.map((it, index) => {
    return [it[“start”], it[“value”]];
    });

    Looking forward to the next post 🙂

  22. I think some update broke this awesome template. I’ve been using it to start my dishwasher and was planning to expand the usage in the future. Now im getting invalid timestamp error. For me it seems fine…
    sensor.cheapest_hours_energy_tomorrow rendered invalid timestamp: #2022-11-24 00:00:00+02:00
    sensor.cheapest_hours_energy_tomorrow rendered invalid timestamp:
    sensor.cheapest_hours_energy_tomorrow rendered invalid timestamp: ###2022-11-25 02:00:00+02:00

    1. That’s intentional warning when the tomorrow hours can’t be calculated (e.g. failure or not yet loaded nordpool tomorrow prices).
      Ensure that the Nord Pool integration has properly fetched the values for tomorrow.

  23. Is there possibility to add more options to this ?
    Now I am using this to my water heater for cheapest 4 hours.
    But I am going to integrate my electric floor heaters this too.
    Problem is, that 4 hours is not going to be enough.
    I would need eg. cheapest 8 or maybe 10 hours.
    I think that I don’t even need the sequential cheap hours but scattered ones are probably even cheaper for the heaters.

  24. I think I found solution. I added this template sensor to configuration.yaml. Now it is easy to create automations based on Ranks. Eg,, Turn on this when Rank is below X and turn of this when Rank is above Y.

    template:
    – sensor:
    – name: “NordpoolRank”
    state: >
    {{ (state_attr(‘sensor.nordpool_kwh_fi_eur_3_10_024’, ‘today’) | sort).index(state_attr(‘sensor.nordpool_kwh_fi_eur_3_10_024’, ‘current_price’))+1}}

Leave a Reply

Your email address will not be published.