Any good ideas are welcome. Nordpool Energy Price per hour

Finding todays and tomorrows lowest…
…might give you some ideas on how to continue with finding the best hours to charge. However, for anything that takes several ours of engery consumption, the first lowest hour might not be the best, but nor the first x hours preceding the lowest - it all depends on the time delta between the hight and low. Considering that the Nordpool flucturates quite wildly nowit needs some more logic than merely the next lowest slot, or the next slot minus eg 2 hrs (giving 4-5 hours where at lease one is the cheapest).

From Developer Tool Templates, can most probalby be made more elegant, but it get the job done:

lowest today
{% set low=namespace(kr=100.0) -%}
{% set time=namespace(hr=0) -%}
{%- for kr in states.sensor.nordpool_kwh_se3_sek_3_095_025.attributes.today -%}
  {%- if loop.index > now().hour -%}

    {%- if kr < low.kr|float -%}
      {%- set low.kr=kr|float -%}
      {%- set time.hr=loop.index -%}
    {%- endif -%}
  {%- endif -%}
{% endfor -%}
{% set hr=time.hr -1 -%}
lowest {{ low.kr }} hr {{ time.hr }}
{{ states.sensor.nordpool_kwh_se3_sek_3_095_025.attributes.raw_today[hr] }}
{% set value_json=states.sensor.nordpool_kwh_se3_sek_3_095_025.attributes.raw_today[hr] %}
{{ value_json.start }}
{{ value_json.value }}
lowest tomorrow
{% set low=namespace(kr=100.0) -%}
{% set time=namespace(hr=0) -%}
{%- for kr in states.sensor.nordpool_kwh_se3_sek_3_095_025.attributes.tomorrow -%}
{%- if kr < low.kr|float -%}{%- set low.kr=kr|float -%}{%- set time.hr=loop.index -%}{%- endif -%}
{% endfor -%}
{% set hr=time.hr -1 -%}
lowest {{ low.kr }} hr {{ time.hr }}
{{ states.sensor.nordpool_kwh_se3_sek_3_095_025.attributes.raw_tomorrow[hr] }}
{% set value_json=states.sensor.nordpool_kwh_se3_sek_3_095_025.attributes.raw_tomorrow[hr] %}
{{ value_json.start }}
{{ value_json.value }}

3 Likes

Thank you!
I made some tweaks (could be cleaner, but I just couldn’t make it any better today).

        value_template: "{% set low=namespace(kr=100.0) -%}
{% set time=namespace(hr=0) -%}
{%- for kr in states.sensor.nordpool_kwh_oslo_nok_3_10_025.attributes.tomorrow -%}
{%- if kr < low.kr|float -%}{%- set low.kr=kr|float -%}{%- endif -%}
{% endfor -%}
{% set hr=time.hr -1 -%}
{{ low.kr }}"

Now I have started making some more templates using this (and a “high”-one).
If it all works, then this will be implemented over the next few days !

I will share all my templates and automations if this works as wanted !

1 Like

What I found is that you have to be carfull that the lowest hour found is within desirable limits. With todays rates the lowst price is tomorrows midnight, ie 30hours away - possible not what you wanted :open_mouth:
image

I will implement a limitation to the tomorrow-for-loop that stops when off-peak from my network provider ends.

Code snipet

  {%- for kr in states.sensor.nordpool_kwh_se3_sek_3_095_025.attributes.tomorrow -%}
    {%- if kr < low.kr|float and loop.index < 6 -%}{%- set low.kr=kr|float -%}{%- set time.hr=loop.index -%}{%- endif -%}

I think it will be fine.
I just need the lowest cost, and I’ll set the desired percentage above that depending on the remaining power in the batteries.

I just had a SD corruption last night, so today I reinstalled HA on a new Raspi.
I’ll have it up and running again tomorrow, with even better battery management !
Thank you again !

Great and looking forward to your setup.

My small excercise targeted the delayed start of the dishwasher - HA now detects that it is powered on, turns off a socket switch and delays power on until lowest hour (lucklily the dishwasher just continous where it was interupted, as opposed to the washing machine that expects human operation in terms of pushing the power button once again :sob:

1 Like

I’m trying to understand what the low_price_cutoff do?

I have finally got this setup back up online again after the SD-corruption and the problems around daylight savings.
Lets see if I can manage to explain.

First off all. I have a batterypack without solar, wind or water. I have a charger/inverter and a grid-tie inverter. The intension is to charge the batteries with cheap power, and use that power when its more expensive. The way I have setup this to work the best is to adjust when to charge/discharge based on how much power I have stored. I also adjust the temperature of the waterheater to store more energy that way. It uses an external temp sensor, so when I set it to 60degrees, the water is in reality a bit warmer. Its based on trial and error during a lot of showers monitoring the temp sensor. I never want it too cold, but when the batteries is low on charge, I don’t want to use power on heating the water warmer then needed for a short shower.

I made this chart with the numbers I have set today. (this will most likely change based on use)


“Prosent” is the state of charge.
“Lav” is the percentage from the lowest price the batteries will charge.
“Høy” is the percentage from the highest price the grid-tie will activate if the usage is above 1600w (Inverter is 1000w).
“Temp” is the temperature setting for the waterheater.

The first thing to do then is to find out what the lowest and highest price is (today and tomorrow).

Finding tomorrows low/high:

  - platform: template
    sensors: 
      norpool_values_tomorrow_max:
        friendly_name: "Norpool tomorrow max"
        value_template: "{% set high=namespace(kr=-100.0) -%}
{% set time=namespace(hr=0) -%}
{%- for kr in states.sensor.nordpool_kwh_oslo_nok_3_10_025.attributes.tomorrow -%}
{%- if kr > high.kr|float -%}{%- set high.kr=kr|float -%}{%- endif -%}
{% endfor -%}
{% set hr=time.hr -1 -%}
{{ high.kr }}"
       
      norpool_values_tomorrow_min:
        friendly_name: "Norpool tomorrow min"
        value_template: "{% set low=namespace(kr=100.0) -%}
{% set time=namespace(hr=0) -%}
{%- for kr in states.sensor.nordpool_kwh_oslo_nok_3_10_025.attributes.tomorrow -%}
{%- if kr < low.kr|float -%}{%- set low.kr=kr|float -%}{%- endif -%}
{% endfor -%}
{% set hr=time.hr -1 -%}
{{ low.kr }}"

Then figuring out what the lowest/highest numbers are combining both today and tomorrow:

  - platform: template
    sensors:
      min_pris:
        value_template: >-
          {% set sensors = [ 
            state_attr('sensor.nordpool_kwh_oslo_nok_3_10_025', 'min')|float,
            states('sensor.norpool_values_tomorrow_min')|float,
            ]
          %}
  
          {{ sensors|min }}
        unit_of_measurement: 'kr'
        
  - platform: template
    sensors:
      max_pris:
        value_template: >-
          {% set sensors = [ 
            state_attr('sensor.nordpool_kwh_oslo_nok_3_10_025', 'max')|float,
            states('sensor.norpool_values_tomorrow_max')|float,
            ]
          %}
  
          {{ sensors|max }}
        unit_of_measurement: 'kr'

Then we need to figure out when to charge and discharge.
High price - Low price * percentage (one for the low, and one for the high):

  - platform: template
    sensors:
     prosent_lav:
       friendly_name: “prosentlav”
       value_template: "{{ ((states('sensor.max_pris') |float - (states('sensor.min_pris') |float)) * (states('input_number.lavprosent') |float))  }}"
  - platform: template
    sensors:
     prosent_hoy:
       friendly_name: “prosenthoy”
       value_template: "{{ ((states('sensor.max_pris') |float - (states('sensor.min_pris') |float)) * (states('input_number.hoyprosent') |float))  }}"

We now know how much to add and subtract from the lowest and highest price :

  - platform: template
    sensors:
      prosent_ned:
        friendly_name: “Prosentned”
        value_template: "{{ (states('sensor.max_pris') |float - states('sensor.prosent_hoy') |float) }}"        
        
  - platform: template
    sensors:
      prosent_opp:
        friendly_name: “Prosentopp”
        value_template: "{{ (states('sensor.min_pris') |float + states('sensor.prosent_lav') |float) }}"

Then its just another automation activating “cheap” and “expensive” if the current price is under or above the set “low” and “high” limits.
The automations activate a couple of boolean inputs, the charger or the grid-tie inverter.

This is also visually shown in a chart where the green line shows the “low” limit and the red line shows the “high” limit. When the price has been above or under the limits, it lights up in green og red:

Sorry for the long an confusing post. Feel free to ask, and Ill try to explain in better words :stuck_out_tongue: .
The next step will be to use “average price” . Now if we have 1 hour with extreme high or low price, the whole days limits will be based from that price. I would like to find a way to incorporate the avg price to get better use of the battery.

5 Likes

Today is a perfect example of why it would be great to figure out the best way to incorporate the average price into the equation.

Tomorrow has a few really expensive hours, but its not necessary to charge the batteries all other hours…

Hopefully not too off topic, but here’s my take on a binary sensor that is on during the cheapest three hour periods in the night/morning (starting from 00:00 to 06:00) and day (starting from 09:00 to 14:00). You can obviously change it to suit your needs. I use this to automate my water heater. Probably not the most elegant way to get this done, but it works :slight_smile:

template:
  - binary_sensor:
      - name: Lowest price period
        unique_id: electricty_lowest_price
        state: >-
          {% set interval_night_1 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').0 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').1 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').2) %}
          {% set interval_night_2 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').1 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').2 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').3) %}
          {% set interval_night_3 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').2 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').3 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').4) %}
          {% set interval_night_4 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').3 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').4 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').5) %}
          {% set interval_night_5 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').4 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').5 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').6) %}
          {% set interval_night_6 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').5 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').6 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').7) %}
          {% set interval_night_7 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').6 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').7 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').8) %}
          {% set lowest_price_night = [interval_night_1,interval_night_2,interval_night_3,interval_night_4,interval_night_5,interval_night_6,interval_night_7] | min %}
          {% if lowest_price_night == interval_night_1 %}
          {% set start_time_night = 0 %}
          {% elif lowest_price_night == interval_night_2 %}
          {% set start_time_night = 1 %}
          {% elif lowest_price_night == interval_night_3 %}
          {% set start_time_night = 2 %}
          {% elif lowest_price_night == interval_night_4 %}
          {% set start_time_night = 3 %}
          {% elif lowest_price_night == interval_night_5 %}
          {% set start_time_night = 4 %}
          {% elif lowest_price_night == interval_night_6 %}
          {% set start_time_night = 5 %}
          {% elif lowest_price_night == interval_night_7 %}
          {% set start_time_night = 6 %}
          {% endif %}
          {% set end_time_night = start_time_night | int + 3 %}
          {% set interval_day_1 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').9 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').10 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').11) %}
          {% set interval_day_2 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').10 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').11 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').12) %}
          {% set interval_day_3 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').11 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').12 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').13) %}
          {% set interval_day_4 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').12 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').13 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').14) %}
          {% set interval_day_5 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').13 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').14 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').15) %}
          {% set interval_day_6 = (state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').14 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').15 + state_attr('sensor.nordpool_kwh_krsand_nok_3_10_025', 'today').16) %}
          {% set lowest_price_day = [interval_day_1,interval_day_2,interval_day_3,interval_day_4,interval_day_5,interval_day_6] | min %}
          {% if lowest_price_day == interval_day_1 %}
          {% set start_time_day = 9 %}
          {% elif lowest_price_day == interval_day_2 %}
          {% set start_time_day = 10 %}
          {% elif lowest_price_day == interval_day_3 %}
          {% set start_time_day = 11 %}
          {% elif lowest_price_day == interval_day_4 %}
          {% set start_time_day = 12 %}
          {% elif lowest_price_day == interval_day_5 %}
          {% set start_time_day = 13 %}
          {% elif lowest_price_day == interval_day_6 %}
          {% set start_time_day = 14 %}
          {% endif %}
          {% set end_time_day = start_time_day | int + 3 %}
          {{ (now().hour | int >= start_time_night | int and now().hour | int < end_time_night) 
          or (now().hour | int >= start_time_day | int and now().hour | int < end_time_day) }}
2 Likes

I use this
> Blockquote

It could be done with less code if you sort the table with prices

unique_id: billigste_timer_1_3
name: billigste_timer_1_3
state: >-
  {% set l=state_attr('sensor.nordpool', 'raw_today')|sort(attribute='value') %}
  {% set t = now() %}
  {{  (t >= l[0].start and t <= l[0].end)
    or (t >= l[1].start and t <= l[1].end)
    or (t >= l[2].start and t <= l[2].end) }}

And if you want time intervals you could use selectattr

unique_id: billigere_etter_midnatt
name: billigere_etter_midnatt
state: >-
  {% set l1=state_attr('sensor.nordpool', 'raw_today')|selectattr('start', '>=', now().replace(hour=18,minute=0,second=0,microsecond=0))|sort(attribute='value') %}
  {% set l2=state_attr('sensor.nordpool', 'raw_tomorrow')|selectattr('start', '<', (now()+timedelta(days=1)).replace(hour=6,minute=0,second=0,microsecond=0))|sort(attribute='value') %}
  {% set l3=state_attr('sensor.nordpool', 'raw_tomorrow')|selectattr('start', '>=', (now()+timedelta(days=1)).replace(hour=6,minute=0,second=0,microsecond=0))|sort(attribute='value') %}
  {% if now().hour>=18 and l3|length>0 and l2|length>0 and l1|length>0 %}
  {{ float(l2[0].value)<float(l1[0].value) and float(l2[0].value)<float(l3[0].value)}}
  {% else %}
  false
  {% endif %}
2 Likes

If there are Estonian users, I share the tariffs and total electricity price including VAT.

Tariffs:

  - platform: template
    sensors:
      el_tariff:
        friendly_name: "Electricity Tariffs"
        unit_of_measurement: '€/kWh'
        value_template: >-
          {% macro calc(v) -%}
            {%set d = {"operator_margin": 0.001,
                      "electricity_excise": 0.001,
                      "renewable_tariff": 0.0113,
                      "nw_fee_night": 0.0162,
                      "nw_fee_day": 0.0283

           } %}
          {%set day_price = v + ((d.operator_margin + d.renewable_tariff + d.electricity_excise + d.nw_fee_day) * 1.2 | float ) | round(4)%}
          {%set night_price = v + ((d.operator_margin + d.renewable_tariff + d.electricity_excise + d.nw_fee_night) * 1.2 | float ) | round(4)%}
          {% if now().weekday() in (5,6) %}
           {{night_price}}
          {% else %}
            {% if now().hour >= 7 and now().hour < 22%}
              {{day_price}}
            {% else %}
              {{night_price}}
            {% endif %}
          {% endif %}
          {%- endmacro %}

          {{calc(0)}}

Total electorcity price

  - platform: template
    sensors:
      total_el_price:
        friendly_name: "Total Electicity Price"
        unit_of_measurement: '€/kWh'
        value_template: "{{ (states('sensor.nordpool_kwh_ee_eur_3_05_02')  | float
                            + states('sensor.el_tariff') | float) | round (2) }}"

Nordpool integration conf as well

  - platform: nordpool
    VAT: True
    currency: "EUR"
    low_price_cutoff: 0.5
    region: "EE"
    precision: 3
    price_type: kWh
6 Likes

Do you happen to have the code for retrieving the current price from nordpool? Seems useful for the energy monitoring tab.

I’m using the “Total Electicity Price” in energy management, because this is what te exact cost is.

1 Like

And intervals could be easier like this:

unique_id: billigere_etter_midnatt
name: billigere_etter_midnatt
state: >-
  {% set l1=state_attr('sensor.nordpool', 'raw_today')[18:]|sort(attribute='value') %}
  {% set l2=state_attr('sensor.nordpool', 'raw_tomorrow')[:6]|sort(attribute='value') %}
  {% set l3=state_attr('sensor.nordpool', 'raw_tomorrow')[6:]|sort(attribute='value') %}
  {% if now().hour>=18 and l3|length>0 and l2|length>0 and l1|length>0 %}
  {{ float(l2[0].value)<float(l1[0].value) and float(l2[0].value)<float(l3[0].value)}}
  {% else %}
  false
  {% endif %}

This requires that the values for tomorrow are already available, and will give an error if not.
With that said, I really like your approach!

I dont get any data. Just copy and paste into configuration.yaml? Changed sensor to sensor.nordpool_kwh_se3_sek_3_095_025 according to my sensor. Where in your yaml do you add the code?

Does anyone know a way to create a copy of the nordpool sensor with tariff added to the values in the raw_today and raw_tomorrow attributes? The tariff varies during the day.

I want to make an automation which triggers at midnight and 2pm to create (update) a new sensor with nordpool values + tariff. The format of the sensor should be equal to the nordpool sensor.

The script works fully.

1 Like