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 18:00, because we can’t be following ‘tomorrow’ state after midnights since it obviously is not ‘tomorrow’ anymore after that 🙂
  • 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: '18:00: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.

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.

13 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 🙂

  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?

Leave a Reply

Your email address will not be published.