Any good ideas are welcome. Nordpool Energy Price per hour

Is it possible to make a sensor that shows the next hour’s electricity price?

I use the Nordpool HACS integration as a current price entity.

I get the Solar production from the Huawei Solar integration, the Grid consumption from an MQTT configured Tibber Pulse meter, as well as the Return to grid values.

As I have a fixed price for consumption, I’ve added a manual price/static rate (including net transfer fees and taxes), and the Nordpool spot prices (including VAT/moms, enabled) for the surplus being sold.

I’ve also made a template sensor that calculates live data for house power draw.

  - platform: template
    sensors:
      template_active_power_consumption:
        friendly_name: "Power consumption"
        device_class: energy
        unit_of_measurement: 'W'
        value_template: '{{ states ("sensor.inverter_active_power")|int(0) + states ("sensor.lgf_active_power_import") | int(0) - states ("sensor.lgf_active_power_export")|int(0) }}'

I used the solution from this thread and switched out the entity with mine and removed the *100 get kr instead of ore.

type: custom:apexcharts-card
hours_12: false
header:
  show: true
  title: Nordpool Prize -> 48 hours
  show_states: true
now:
  show: true
  color: '#ff0000'
  label: Now
graph_span: 2d
span:
  start: day
series:
  - entity: sensor.nordpool_kwh_oslo_nok_2_10_025
    name: Today
    unit: øre/kWh
    data_generator: |
      return entity.attributes.raw_today.map((entry) => {
        return [new Date(entry.start), entry.value * 100];
      });
    type: column
    show:
      legend_value: false
      in_header: false
    extend_to: end
  - entity: sensor.nordpool_kwh_oslo_nok_2_10_025
    name: Tomorrow
    unit: øre/kWh
    data_generator: |
      return entity.attributes.raw_tomorrow.map((entry) => {
        return [new Date(entry.start), entry.value * 100];
      });
    type: column
    show:
      legend_value: false
      in_header: false

hi maybe i misunderstood you but isn’t this a graph?
What I mean is that jas would like to have a sensor that shows the next hour like below.

That is a built-in graph, yes. The Apexcharts integration is a bit more powerful, however.

I cannot figure out how to extract the price for the next hour and make it into a sensor/an entity.

You could probably do it with a template, but my scripting skills are lacking/non-existent :roll_eyes:.

1 Like

I’ve tried all the great examples above of how to determine “low” prices, but I wanted to improve the algorithm without having to go stateful. To be truly optimal, each consumer would have to register when a need arises, and register how much energy is needed as well as maximum power. Determining needed energy might be quite tricky. For instance a hot water boiler, you would need to know the volume and have multiple temperature sensors to accurately determine at what level the hot water level is at. This is more than I wanted to tackle.

Instead I came up with this algorithm which does a pretty good job. It takes all available future prices into account, groups them by value proximity into 3 groups: low, medium and high. There are no hard coded limits so even if night prices are high, it will find the lowest hours.

To make automations and conditions easy I have three template sensors:

  • Upper limit for low prices
  • Lower limit for high prices
  • A bracket number where 1=low, 2=medium and 3=high

If you need a condition it’s easy to compare current price <= low price or >= high price
If you want different consumers enabled in different brackets, create automations on the bracket value which will be evaluated everytime current price moves to a different bracket. Then have 3 scenes (low, medium and high) where you set what consumers should be enabled.

This also avoids the shortcoming in HA where numeric action triggers only subscribes to 1 entity even if you use multiple entities.

I share my code for comments and for anyone to use. You need to adjust all “sensor.nordpool_kwh_se3_sek_3_10_025” for your own region, and it relies on the NordPool integration through HACS.

template:
  - sensor:
      - name: "Electricity Band Low now today+tomorrow"
        unique_id: "sensor.electricity_band_low"
        unit_of_measurement: "SEK/kWh"
        state: "{% if states('sensor.nordpool_kwh_se3_sek_3_10_025') -%}
                {% if state_attr('sensor.nordpool_kwh_se3_sek_3_10_025', 'tomorrow_valid') == true and state_attr('sensor.nordpool_kwh_se3_sek_3_10_025', 'tomorrow')|string|length > 24  -%}
                   {% set prices=states.sensor.nordpool_kwh_se3_sek_3_10_025.attributes.raw_today|list + states.sensor.nordpool_kwh_se3_sek_3_10_025.attributes.raw_tomorrow|list -%}
                {% else -%}
                   {% set prices=states.sensor.nordpool_kwh_se3_sek_3_10_025.attributes.raw_today -%}
                {% endif -%}
                {% set cheapest = prices|selectattr('end','>',now()) | sort(attribute='value') -%}
                {% set deltas = namespace(deltas=[]) -%}
                {% set previous = namespace(value=0.0) -%}
                {% for cheap in cheapest -%}
                  {% if loop.index > 1 -%}
                    {% set delta = [({'value':cheap.value, 'delta':cheap.value - previous.value})] -%}
                    {% set deltas.deltas = deltas.deltas + delta -%}
                  {% endif -%}
                  {% set previous.value = cheap.value -%}
                {% endfor -%}
                {% set bands = deltas.deltas | sort(reverse=true,attribute='delta') -%}
                {{ cheapest|selectattr('value','<',min(bands[0].value,bands[1].value))|map(attribute='value')|list|last }}
                {% else -%}
                   {{  unknown }}               
                {% endif -%}"
  - sensor:
      - name: "Electricity Band High now today+tomorrow"
        unique_id: "sensor.electricity_band_high"
        unit_of_measurement: "SEK/kWh"
        state: "{% if states('sensor.nordpool_kwh_se3_sek_3_10_025') -%}
                {% if state_attr('sensor.nordpool_kwh_se3_sek_3_10_025', 'tomorrow_valid') == true and state_attr('sensor.nordpool_kwh_se3_sek_3_10_025', 'tomorrow')|string|length > 24  -%}
                   {% set prices=states.sensor.nordpool_kwh_se3_sek_3_10_025.attributes.raw_today|list + states.sensor.nordpool_kwh_se3_sek_3_10_025.attributes.raw_tomorrow|list -%}
                {% else -%}
                   {% set prices=states.sensor.nordpool_kwh_se3_sek_3_10_025.attributes.raw_today -%}
                {% endif -%}
                {% set cheapest = prices|selectattr('end','>',now()) | sort(attribute='value') -%}
                {% set deltas = namespace(deltas=[]) -%}
                {% set previous = namespace(value=0.0) -%}
                {% for cheap in cheapest -%}
                  {% if loop.index > 1 -%}
                    {% set delta = [({'value':cheap.value, 'delta':cheap.value - previous.value})] -%}
                    {% set deltas.deltas = deltas.deltas + delta -%}
                  {% endif -%}
                  {% set previous.value = cheap.value -%}
                {% endfor -%}
                {% set bands = deltas.deltas | sort(reverse=true,attribute='delta') -%}
                {{ max(bands[0].value,bands[1].value) }}
                {% else -%}
                   {{  unknown }}               
                {% endif -%}"
  - sensor:
      - name: "Electricity Price Bracket"
        unique_id: "sensor.electricity_bracket"
        state_class: "measurement"
        state: "{% if states('sensor.nordpool_kwh_se3_sek_3_10_025') and states('sensor.electricity_band_low') and states('sensor.electricity_band_high') -%}
                  {% set current_price = states('sensor.nordpool_kwh_se3_sek_3_10_025') -%}
                  {% set low = states('sensor.electricity_band_low_now_today_tomorrow') -%}
                  {% set high = states('sensor.electricity_band_high_now_today_tomorrow') -%}
                  {% if current_price <= low -%}
                    {% set bracket = 1 -%}
                  {% elif current_price >= high -%}
                    {% set bracket = 3 -%}
                  {% else -%}
                    {% set bracket = 2 -%}
                  {% endif -%}
                  {{ bracket }}
                {% endif -%}"

4 Likes

Hey! I got this from another forum. It will show true if the current hour is one of 5 cheapest hour during the day. That way you could turn on something you want to be on during the cheapest hour.

        {% set x = states("sensor.time") %}
        {% set l=state_attr('sensor.nordpool_kwh_se3_sek_3_10_025_med_moms', 'raw_today')|sort(attribute='value') %}
        {{ (now() >= l[0].start and now() <= l[0].end)
        or (now() >= l[1].start and now() <= l[1].end)
        or (now() >= l[2].start and now() <= l[2].end)
        or (now() >= l[3].start and now() <= l[3].end)
        or (now() >= l[4].start and now() <= l[4].end) }}

But I would also like to display the cheapest 5 hours somehow so I clearly see what hours that is. How would I do that in a good visual way?

Thanks!

1 Like

Thanks for good input!

However, could you open up what this helper actually does? What is the effect of choosing 2 or 4 in helper and how should the effect be seen?

It’s used in the value template:

        value_template: >
          {{average((state_attr('sensor.nordpool_kwh_se4_sek_3_095_025', 'today') | sort(reverse=true))[int(states('input_select.poolpump_avstangd'))-1],
                    (state_attr('sensor.nordpool_kwh_se4_sek_3_095_025', 'today') | sort(reverse=true))[int(states('input_select.poolpump_avstangd'))]) | 
            round(3) }}

If set to 12: The device will run the 12 cheapest hours (24-12), ie. median
If set to 6: The device will run the 18 cheapest hours (24-6)
If set to 4: The device will run the 20 cheapest hours (24-4)
If set to 2: The device will run the 22 cheapest hours (24-2)

My pool needs at minimum 12 hrs circulation.

You can obviously set your helper to your needs. I do recommend to use even values between 2 and 22, else you may need to change the template.

HTH/Marcus

3 Likes

Hello
If I want to use this, should I enter it as a template?

I copied your code to my configuration.yaml and replaced sensor.nordpool_kwh_se3_sek_3_10_025 with my sensor.nordpool_kwh_fi, however, template sensors remain unvailable, i.e. do not produce any value. My sensor.nordpool_kwh_fi is working and showing correct values.

What I am missing?

Isn’t the Nordpool sensor for Finland called sensor.nordpool_kwh_fi_eur_3_10_024?

I’ve changed that to shorter format for easier use. As I said, it shows correct values. I’ll try to change that back to default and will report the outcome.

EDIT: Changing the sensor name to default did not solve the problem. Unfortunately HA does not give any information why the sensors are unavailable…

I tried using the FI region and it works, but when trying that I noticed that there are two line break errors in my posted code. I updated my script here, but if you want to fix directly in your config file, look around line 10-11 and you’ll see that the lines break in the middle of the Nordpool sensor name.

Yes, I noticed those line breaks and fixed them when tried your code first time.

Interestingly your code works now, it seems like it started to produce values when Nordpool released prices for tomorrow…

Sure I use all templates outside config in templates.yaml and use this code:

- sensor:
  - name: Dagen Timpris SE3 fem billigaste timmarna
    state: >
        {% set x = states("sensor.time") %}
        {% set l=state_attr('sensor.nordpool_kwh_se3_sek_3_10_025_med_moms', 'raw_today')|sort(attribute='value') %}
        {{ (now() >= l[0].start and now() <= l[0].end)
        or (now() >= l[1].start and now() <= l[1].end)
        or (now() >= l[2].start and now() <= l[2].end)
        or (now() >= l[3].start and now() <= l[3].end)
        or (now() >= l[4].start and now() <= l[4].end) }}
1 Like

Hi and thanks
Do you know if it is possible to show the next hour price in a sensor?

Hm no sorry!

1 Like

It seems like the code works only when both today’s and tomorrow’s prices are available. I wonder what the heck is wrong with the code.

How would I do if I want the montly average price?