Any good ideas are welcome. Nordpool Energy Price per hour

state_class: total
average: 109.41033333333334
off_peak_1: 79.453625
off_peak_2: 106.902
peak: 130.21758333333332
min: 76.304
max: 154.739
mean: 113.6275
unit: kWh
currency: SEK
country: Sweden
region: SE4
low_price: false
price_percent_to_average: 1.1082042829592573
today:
  - 79.264
  - 78.662
  - 77.653
  - 76.621
  - 76.338
  - 76.304
  - 80.126
  - 90.661
  - 108.138
  - 116.667
  - 121.249
  - 122.099
  - 129.358
  - 133.735
  - 133.792
  - 138.158
  - 142.037
  - 154.739
  - 136.797
  - 125.842
  - 120.908
  - 110.588
  - 103.613
  - 92.499
tomorrow: []
tomorrow_valid: false
raw_today:
  - start: "2024-01-17T00:00:00+01:00"
    end: "2024-01-17T01:00:00+01:00"
    value: 79.264
  - start: "2024-01-17T01:00:00+01:00"
    end: "2024-01-17T02:00:00+01:00"
    value: 78.662
  - start: "2024-01-17T02:00:00+01:00"
    end: "2024-01-17T03:00:00+01:00"
    value: 77.653
  - start: "2024-01-17T03:00:00+01:00"
    end: "2024-01-17T04:00:00+01:00"
    value: 76.621
  - start: "2024-01-17T04:00:00+01:00"
    end: "2024-01-17T05:00:00+01:00"
    value: 76.338
  - start: "2024-01-17T05:00:00+01:00"
    end: "2024-01-17T06:00:00+01:00"
    value: 76.304
  - start: "2024-01-17T06:00:00+01:00"
    end: "2024-01-17T07:00:00+01:00"
    value: 80.126
  - start: "2024-01-17T07:00:00+01:00"
    end: "2024-01-17T08:00:00+01:00"
    value: 90.661
  - start: "2024-01-17T08:00:00+01:00"
    end: "2024-01-17T09:00:00+01:00"
    value: 108.138
  - start: "2024-01-17T09:00:00+01:00"
    end: "2024-01-17T10:00:00+01:00"
    value: 116.667
  - start: "2024-01-17T10:00:00+01:00"
    end: "2024-01-17T11:00:00+01:00"
    value: 121.249
  - start: "2024-01-17T11:00:00+01:00"
    end: "2024-01-17T12:00:00+01:00"
    value: 122.099
  - start: "2024-01-17T12:00:00+01:00"
    end: "2024-01-17T13:00:00+01:00"
    value: 129.358
  - start: "2024-01-17T13:00:00+01:00"
    end: "2024-01-17T14:00:00+01:00"
    value: 133.735
  - start: "2024-01-17T14:00:00+01:00"
    end: "2024-01-17T15:00:00+01:00"
    value: 133.792
  - start: "2024-01-17T15:00:00+01:00"
    end: "2024-01-17T16:00:00+01:00"
    value: 138.158
  - start: "2024-01-17T16:00:00+01:00"
    end: "2024-01-17T17:00:00+01:00"
    value: 142.037
  - start: "2024-01-17T17:00:00+01:00"
    end: "2024-01-17T18:00:00+01:00"
    value: 154.739
  - start: "2024-01-17T18:00:00+01:00"
    end: "2024-01-17T19:00:00+01:00"
    value: 136.797
  - start: "2024-01-17T19:00:00+01:00"
    end: "2024-01-17T20:00:00+01:00"
    value: 125.842
  - start: "2024-01-17T20:00:00+01:00"
    end: "2024-01-17T21:00:00+01:00"
    value: 120.908
  - start: "2024-01-17T21:00:00+01:00"
    end: "2024-01-17T22:00:00+01:00"
    value: 110.588
  - start: "2024-01-17T22:00:00+01:00"
    end: "2024-01-17T23:00:00+01:00"
    value: 103.613
  - start: "2024-01-17T23:00:00+01:00"
    end: "2024-01-18T00:00:00+01:00"
    value: 92.499
raw_tomorrow: []
current_price: 121.249
additional_costs_current_hour: 0
price_in_cents: true
unit_of_measurement: Ɩre/kWh
device_class: monetary
icon: mdi:flash
friendly_name: nordpool

iā€™m clueless. I copied again your code and put in my nordpool and input number and everything works.

Here is a code that worked for me:

- type: markdown
  alignment: justify
  content: >-
    {% set iterativesum = namespace(iter=[]) %}
    {% set lowestiter = namespace(kr=2) %}
    {% set timelowest = namespace(hr=2) %}
    {% set highestiter = namespace(kr=0) %}
    {% set timehighest = namespace(hr=0) %}
    {% set num_hours = states('input_number.cheapest_hours_needed') | int %}
    {% set nordpoolentity = 'sensor.nordpool_with_vat_and_tarifss' %}
    {% set timemapper = {
        0: '00:00', 1: '01:00', 2: '02:00', 3: '03:00', 4: '04:00', 5: '05:00', 
        6: '06:00', 7: '07:00', 8: '08:00', 9: '09:00', 10: '10:00', 11: '11:00', 
        12: '12:00', 13: '13:00', 14: '14:00', 15: '15:00', 16: '16:00', 
        17: '17:00', 18: '18:00', 19: '19:00', 20: '20:00', 21: '21:00', 
        22: '22:00', 23: '23:00', 24: '00:00', 25: '01:00', 26: '02:00', 
        27: '03:00', 28: '04:00', 29: '05:00', 30: '06:00', 31: '07:00', 
        32: '08:00', 33: '09:00', 34: '10:00', 35: '11:00', 36: '12:00', 
        37: '13:00', 38: '14:00', 39: '15:00', 40: '16:00', 41: '17:00', 
        42: '18:00', 43: '19:00', 44: '20:00', 45: '21:00', 46: '22:00', 
        47: '23:00', 48: '0:00', 
    } %}
    {% set prices = namespace(price=[]) %}
    {% set prices.price = prices.price + state_attr(nordpoolentity, 'today') %}
    {%- if state_attr(nordpoolentity,'tomorrow') | length == 1 -%}
      Electricity prices for tomorrow are not available.
    {%- else -%}
      {% set prices.price = prices.price + state_attr(nordpoolentity, 'tomorrow') %}
    {%- endif -%}
    {%- for n in range(prices.price|length - num_hours + 1) -%}
      {%- set tempsum = namespace(temp=0) -%}
      {%- for i in range(num_hours) -%}
        {%- set tempsum.temp = tempsum.temp + prices.price[n+i] -%}
      {%- endfor -%}
      {% set iterativesum.iter = iterativesum.iter + [tempsum.temp] -%}
    {%- endfor -%}
    {% for iter in iterativesum.iter -%}
      {%- if loop.index > now().hour -%}
        {%- if iter < lowestiter.kr | float -%}
          {%- set lowestiter.kr = iter | float -%}
          {%- set timelowest.hr = loop.index -1 -%}
        {%- endif -%}
        {%- if iter > highestiter.kr | float -%}
          {%- set highestiter.kr = iter | float -%}
          {%- set timehighest.hr = loop.index -1 -%}
        {%- endif -%}
      {%- endif -%}
    {%- endfor -%}
    The cheapest {{ num_hours }} {{ 'hour' if num_hours == 1 else 'hours' }} start
    {% if (timelowest.hr < 24) %}today{% else %}tomorrow{% endif %}
    at {{ timemapper[timelowest.hr] }}, with an average price of
    {{ "%.2f"|format(lowestiter.kr/num_hours) }} ā‚¬/kWh.

As of your log files ChatGPT answer:

  1. TypeError: can only concatenate list (not ā€œNoneTypeā€) to list This error arises when you try to concatenate a None value to a list. In your template, when you concatenate state_attr(nordpoolentity, 'today') and state_attr(nordpoolentity, 'tomorrow') with prices.price, if either of these attributes is None, you will encounter this error.
  2. TypeError: ā€˜NoneTypeā€™ object is not subscriptable This error occurs when you attempt to access an index or a key in a None object. For example, accessing state_attr('sensor.nordpool', 'today')[00:23] assumes that state_attr('sensor.nordpool', 'today') returns a list. If it returns None, the operation fails.

So something still regarding your nordpool sensor and code cant get data from it. But iā€™m clueless

Hey all
Iā€™m trying to create a chart that can visualize this data (see attached image) but donā€™t really know where to start. Can someone help me get started, please.

SkaĢˆrmavbild 2024-01-20 kl. 11.13.03

Try apex charts. Many examples on this forum.

Believe me, I really tried

Ok. If you share what you have tried then I am sure we can help you debug the issue.

Price works fine but I want to be able to see when it intends to charge vs. discharge

series:
  - entity: sensor.optimized_battery_schedule
    name: Schedule
    color: '#00FF00'
    yaxis_id: charge/discharge
    data_generator: |
      return entity.attributes.price.map((start, index) => {
        return [new Date(start["start"]).getTime(), entity.attributes.price[index]["value"]];
      });
  - entity: sensor.optimized_battery_schedule
    name: Elpris
    color: blue
    yaxis_id: price
    data_generator: |
      return entity.attributes.price.map((start, index) => {
        return [new Date(start["start"]).getTime(), entity.attributes.price[index]["value"]];
      });

Attributes

schedule: 
- start: '2024-01-21T12:00:00.000Z'
  activity: 0
  name: none
- start: '2024-01-21T12:11:00.000Z'
  activity: 1
  duration: 40
  name: charging
- start: '2024-01-21T12:51:00.000Z'
  activity: 0
  name: none
- start: '2024-01-21T14:52:00.000Z'
  activity: -1
  duration: 311
  name: discharging
- start: '2024-01-21T20:03:00.000Z'
  activity: 0
  name: none
- start: '2024-01-22T01:07:00.000Z'
  activity: 1
  duration: 293
  name: charging
- start: '2024-01-22T06:00:00.000Z'
  activity: 0
  name: none
- start: '2024-01-22T06:00:00.000Z'
  activity: -1
  duration: 421
  name: discharging
- start: '2024-01-22T13:01:00.000Z'
  activity: 0
  name: none

price: 
- value: 0.969
  start: '2024-01-21T00:00:00.000+01:00'
- value: 0.9186
  start: '2024-01-21T01:00:00.000+01:00'
- value: 0.6676
  start: '2024-01-21T02:00:00.000+01:00'
- value: 0.6081
  start: '2024-01-21T03:00:00.000+01:00'
- value: 0.6064
  start: '2024-01-21T04:00:00.000+01:00'
- value: 0.6111
  start: '2024-01-21T05:00:00.000+01:00'
- value: 0.6067
  start: '2024-01-21T06:00:00.000+01:00'
- value: 0.6164
  start: '2024-01-21T07:00:00.000+01:00'
- value: 0.6143
  start: '2024-01-21T08:00:00.000+01:00'
- value: 0.625
  start: '2024-01-21T09:00:00.000+01:00'
- value: 0.6435
  start: '2024-01-21T10:00:00.000+01:00'
- value: 0.6566
  start: '2024-01-21T11:00:00.000+01:00'
- value: 0.6496
  start: '2024-01-21T12:00:00.000+01:00'
- value: 0.6421
  start: '2024-01-21T13:00:00.000+01:00'
- value: 0.6458
  start: '2024-01-21T14:00:00.000+01:00'
- value: 0.6528
  start: '2024-01-21T15:00:00.000+01:00'
- value: 0.8111
  start: '2024-01-21T16:00:00.000+01:00'
- value: 0.9061
  start: '2024-01-21T17:00:00.000+01:00'
- value: 0.9728
  start: '2024-01-21T18:00:00.000+01:00'
- value: 0.9297
  start: '2024-01-21T19:00:00.000+01:00'
- value: 0.6175
  start: '2024-01-21T20:00:00.000+01:00'
- value: 0.6103
  start: '2024-01-21T21:00:00.000+01:00'
- value: 0.6143
  start: '2024-01-21T22:00:00.000+01:00'
- value: 0.5315
  start: '2024-01-21T23:00:00.000+01:00'
- value: 0.5069
  start: '2024-01-22T00:00:00.000+01:00'
- value: 0.4347
  start: '2024-01-22T01:00:00.000+01:00'
- value: 0.3831
  start: '2024-01-22T02:00:00.000+01:00'
- value: 0.1894
  start: '2024-01-22T03:00:00.000+01:00'
- value: 0.1897
  start: '2024-01-22T04:00:00.000+01:00'
- value: 0.4028
  start: '2024-01-22T05:00:00.000+01:00'
- value: 0.489
  start: '2024-01-22T06:00:00.000+01:00'
- value: 0.591
  start: '2024-01-22T07:00:00.000+01:00'
- value: 0.5893
  start: '2024-01-22T08:00:00.000+01:00'
- value: 0.5863
  start: '2024-01-22T09:00:00.000+01:00'
- value: 0.5695
  start: '2024-01-22T10:00:00.000+01:00'
- value: 0.5578
  start: '2024-01-22T11:00:00.000+01:00'
- value: 0.5539
  start: '2024-01-22T12:00:00.000+01:00'
- value: 0.5352
  start: '2024-01-22T13:00:00.000+01:00'
- value: 0.5251
  start: '2024-01-22T14:00:00.000+01:00'
- value: 0.5499
  start: '2024-01-22T15:00:00.000+01:00'
- value: 0.5685
  start: '2024-01-22T16:00:00.000+01:00'
- value: 0.586
  start: '2024-01-22T17:00:00.000+01:00'
- value: 0.5802
  start: '2024-01-22T18:00:00.000+01:00'
- value: 0.5703
  start: '2024-01-22T19:00:00.000+01:00'
- value: 0.5655
  start: '2024-01-22T20:00:00.000+01:00'
- value: 0.5288
  start: '2024-01-22T21:00:00.000+01:00'
- value: 0.4893
  start: '2024-01-22T22:00:00.000+01:00'
- value: 0.446
  start: '2024-01-22T23:00:00.000+01:00'

friendly_name: Optimized Battery Schedule

Hi. I am looking for a way to compare the current price to the following ~8 hours to come. Not comparing the current price to the daily average, but always looking ahead with a moving average window of about 8 hours. This would give the cheapest hour just before a steep price increase and the most expensive hour just before price decrease. I think this would be smart for heating home because it is most important to heat most (buffer up heat) just before the increase and heat less just before decrease. Maybe someone have an algorithm for this already?

Really late reply.
However i use a markdown card with the following code to display the upcoming 3h.
Hope this can help someone atlest.

The same method could be used to make both sensors for X hours, and a sensor for any specific hour ahead or specific time.

 {% set enow = states('sensor.nordpool_kwh_se3_sek_2_10_025')|int | round(0) %}
{% set list_values = state_attr('sensor.nordpool_kwh_se3_sek_2_10_025', 'today') %}
{% set list_values_tomorrow = state_attr('sensor.nordpool_kwh_se3_sek_2_10_025', 'tomorrow') %}
{% set current_hour = now().strftime('%-H') | int %}
{% set enexth = current_hour + 1 if current_hour + 1 <= 23 else current_hour + 1 - 23 %}
{% set enext2h = current_hour + 2 if current_hour + 2 <= 23 else current_hour + 2 - 24 %}
{% set enext3h = current_hour + 3 if current_hour + 3 <= 23 else current_hour + 3 - 24 %}
{% set next_hour_index = enexth %}
{% set next_hour_value = list_values[next_hour_index] if current_hour + 1 <= 23 else list_values_tomorrow[next_hour_index] %}
{% set next2_hour_index = enext2h %}
{% set next2_hour_value = list_values[next2_hour_index] if current_hour + 2 <= 23 else list_values_tomorrow[next2_hour_index] %}
{% set next3_hour_index = enext3h %}
{% set next3_hour_value = list_values[next3_hour_index] if current_hour + 3 <= 23 else list_values_tomorrow[next3_hour_index] %}
{% set enext = next_hour_value | round(0) %}
{% set enext2 = next2_hour_value | round(0) %}
{% set enext3 = next3_hour_value | round(0) %}
{% set enexticon = 'mdi:arrow-bottom-right-bold-outline' if enow > enext else 'mdi:arrow-top-right-bold-outline' if enow < enext else 'mdi:arrow-right-bold-outline' %}
{% set enexticoncolor = 'green' if enow > enext else 'red' if enow < enext else 'yellow' %}
{% set enexticon2 = 'mdi:arrow-bottom-right-bold-outline' if enext > enext2 else 'mdi:arrow-top-right-bold-outline' if enext < enext2 else 'mdi:arrow-right-bold-outline' %}
{% set enexticoncolor2 = 'green' if enext > enext2 else 'red' if enext < enext2 else 'yellow' %}
{% set enexticon3 = 'mdi:arrow-bottom-right-bold-outline' if enext2 > enext3 else 'mdi:arrow-top-right-bold-outline' if enext2 < enext3 else 'mdi:arrow-right-bold-outline' %}
{% set enexticoncolor3 = 'green' if enext2 > enext3 else 'red' if enext2 < enext3 else 'yellow' %}
Kl&nbsp;{%if enexth < 10 %}0{%endif%}{{enexth}}:&nbsp;<font color="{{enexticoncolor}}"><ha-icon icon="{{enexticon}}"></ha-icon>{{enext}}</font>&nbsp;ƶre/kWh
Kl&nbsp;{%if enext2h < 10 %}0{%endif%}{{enext2h}}:&nbsp;<font color="{{enexticoncolor2}}"><ha-icon icon="{{enexticon2}}"></ha-icon>{{enext2}}</font>&nbsp;ƶre/kWh
Kl&nbsp;{%if enext3h < 10 %}0{%endif%}{{enext3h}}:&nbsp;<font color="{{enexticoncolor3}}"><ha-icon icon="{{enexticon3}}"></ha-icon>{{enext3}}</font>&nbsp;ƶre/kWh

I used to have two apex chart: one for today and one for tomorrow, but needed a more compact way to show the information, so i put today and tomorrow in one chart. However it was quite annoying that the chart was half empty before 13:00 when tomorrowā€™s prices came available, so I was seeking how to make the graph_span dynamic. Sadly you cannot have a template in apex chart code, so have to come up with a different approach.

First I made a input number helper input_number.total_nordpool_hours_available

Then made automation that will write available hours to the input number helper:

alias: Total Nordpool Hours Available
description: ""
trigger:
  - platform: time_pattern
    seconds: "5"
condition: []
action:
  - service: input_number.set_value
    metadata: {}
    data:
      value: >-
        {{ (((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_today') |
        map(attribute='value') | list) +
        (state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_tomorrow') |
        map(attribute='value') | list)) | list | length ) }}
    target:
      entity_id: input_number.total_nordpool_hours_available
mode: single

Then used config-template-card (GitHub - iantrich/config-template-card: šŸ“ Templatable Lovelace Configurations) and inside Apex chart as normal.

type: custom:config-template-card
variables:
  hours: '`${states[''input_number.total_nordpool_hours_available''].state}h`'
entities:
  - input_number.total_nordpool_hours_available
card:
  type: custom:apexcharts-card
  graph_span: ${hours}
  yaxis:
    - id: y1
      min: 0
  apex_config:
    chart:
      height: 340px
  show:
    last_updated: true
  experimental:
    color_threshold: true
  header:
    title: Electricity prices today
    show: true
    show_states: true
    colorize_states: true
  span:
    start: day
  now:
    show: true
    label: Now
  series:
    - entity: sensor.nordpool_kwh_ee_eur_3_10_0
      float_precision: 3
      show:
        extremas: true
        in_header: raw
        header_color_threshold: true
      type: column
      data_generator: >
        return (entity.attributes.raw_today.map((start, index) => {
          return [new Date(start["start"]).getTime(), entity.attributes.raw_today[index]["value"]];
        })).concat(entity.attributes.raw_tomorrow.map((start, index) => {

        return [new Date(start["start"]).getTime(),
        entity.attributes.raw_tomorrow[index]["value"]];

        }));
      color_threshold:
        - value: -1
          color: '#007bff'
          opacity: 1
        - value: 0
          color: '#28a745'
          opacity: 1
        - value: 0.05
          color: '#ffed4a'
          opacity: 1
        - value: 0.1
          color: '#fd7e14'
        - value: 0.2
          color: '#dc3545'
    - entity: sensor.nordpool_with_vat_and_tarifss
      float_precision: 3
      show:
        extremas: true
        in_header: raw
        header_color_threshold: true
      type: line
      stroke_width: 2
      data_generator: >
        return (entity.attributes.raw_today.map((start, index) => {
          return [new Date(start["start"]).getTime(), entity.attributes.raw_today[index]["value"]];
        })).concat(entity.attributes.raw_tomorrow.map((start, index) => {

        return [new Date(start["start"]).getTime(),
        entity.attributes.raw_tomorrow[index]["value"]];

        }));

In my case i have plotted two data series - Nordpool without VAT and Nordpool with VAT and Tariffs, so i can see import and export prices, but you can just copy your existing apex chart code there.

Result:
Screenshot 2024-02-22 at 09.09.35
Note that itā€™s 9 AM, and only 24h is shown.

It would look like this when 48h is available. (No data at the moment however)
Screenshot 2024-02-22 at 09.10.35

1 Like

Hi @papaste, I have been super pleased with this template snippet for my nordpool integratino for a while, but have recently changed to Energi Data Service In that context I hoped getting this nice template to work with a glance, almost similiar data-sets, but it fails :frowning:

{% set delta = [({'value':n.value, 'delta':n.value - previous.value})] -%}
{% set deltas.deltas = deltas.deltas + delta -%} 

with a ā€˜UndefinedError: ā€˜dict objectā€™ has no attribute ā€˜valueā€™ā€™

Any ideas why what that is causing?

Thanks!

Really nice, thanks!!

1 Like

Found out a simpler way how to do it without the input helper and automation using nordpool attribute tomorrow_valid

type: custom:config-template-card
variables:
  span: |
    tv => {
      if (tv == true) {
        return '`48h`';
      } 
      return '`24h`';
    }
  tomorrow_valid: states['sensor.nordpool_kwh_ee_eur_3_10_0'].attributes.tomorrow_valid
entities:
  - sensor.nordpool_kwh_ee_eur_3_10_0
card:
  type: custom:apexcharts-card
  graph_span: ${span(tomorrow_valid)}

@TheLordVader :point_up:

1 Like

HI, any ideas how to create an automation.
I would like an automated announcement from my smart speaker every night at the same time. The announcement would tell me when is the cheapest 3hour slot during the night before 5am, and how many hours until that time starts.
i want to know when the electricity is cheapest to set my dishwasher turn on with the delay announced,

Iā€™ve been using @dala318 's nordpool_planner for about a year to increase/decrease the heat pump setpoint but Iā€™d like to further optimize it by setting an offset as my heat pump takes a little while to begin its cycle. I was thinking maybe there is a helper I could create based on the Starts at attribute? I would like to make it so I could have the automation start eg. 1 hour before the low price starts.

Iā€™m excited to share the first version of my custom Home Assistant integration, designed to seamlessly calculate energy costs based on your deviceā€™s power consumption and dynamic electricity rates like Nordpool.

Features

  • Real-time Energy Cost: Tracks the cost of energy consumption in real-time (ā‚¬/h).
  • Cumulative/Total Cost: Accumulates the total cost over time.
  • Daily, Monthly, & Yearly Costs: Breaks down energy costs into daily, monthly, and yearly totals.

Screenshots

Real-time Energy Cost
Cumulative Cost Overview

Getting Started

To start using this integration, simply add the power entity of your device and the electricity price entity to the configuration. The integration handles the rest, calculating various cost metrics based on your inputs.

Repository

You can find the code and more details on how to install and use this integration on GitHub:
Dynamic Energy Cost Integration

Note

This project is currently in its early beta phase. We encourage early adopters to use it cautiously and share feedback for further improvements.


6 Likes

UPDATE:

Version 0.2.0 (still very early stage) is up.

Now you can input energy (kwh) sensor and electricity price sensot to the integration like you do with energy dashboard, and get daily, monthly, and yearly cost sensors.

I left the possibility to calculate cost from power sensor, but itā€™s not that precise as fom energy sensor. Only if you donā€™t have energy sensor for the device you want to calculate cost, use power sensor.

As said, itā€™s a early beta and its my first custom integration, first python development and probably my first ever proper development project.

7 Likes

edit found answer myself :slight_smile:

Nice work!

Is this also suitable for gas (m3) and water (m3) sensors?
Or can it be?

Gas is also daily dynamically priced (pricing sensor available). Water price is a static sensor.

For gas and water I reccomend to use Energy Dashboard default functionality.