Any good ideas are welcome. Nordpool Energy Price per hour

I added steps 6 and 7. Now should be complete

1 Like

One last question. There isn’t any problem using instant power multiplied with a price per energy? kW * Price/kWh = Price/h, not Price. Am I thinking wrong?

Correct you get current price/h and Reiman Sum will calculate the cumulative cost.

It’s like Reiman sum calculates energy (kWh) from power (w)

Stuff mostly makes sense in my head but I’m not that good explaining it :grinning:. Anyways result is what is expected.

2 Likes

Sorry for the blog being in Norwegian, but i still think it might be of interest.

Another take on the use of Nordpool with a Node-Red and apex chart angle.

Based on ideas from around different forums and www.powersaver.no

1 Like

@arva Fantastic! Thanks a lot

1 Like

Vattenfall Elnät calls it T4 so it is very much relevant but not if you have solar since they pays less for peak hours for feed in with that metering scheme.

I would be intersted this also if someone have solution for this? I would imagine only nordpool and energy consumption sensors are needed. The rest is unclear :smiley:
This would be helpful to see if electricity consumption optimizations have actually helped to save money.

Fantastic work Arva! I have made use of your code with some minor modifications. It all works well apart from the final step where there are no sensors available for the Apex chart. I’m not familiar with utility meters so perhaps I’ve misunderstood how to configure these? As far as I can see there are no sensors generated from the utility meter, e.g. sensor.pv_own_usage_benefit_daily and so forth which the Apex chart requires. Are you able to see what I’m missing or misconfigured please?

I have the following in my configuration.yaml :

utility_meter:
  pv_own_usage_benefit_daily:
    source: sensor.solpaneler_fortjanst_egen_konsumtion
    name: Förtjänst från användning av solpaneler
    cycle: daily
  pv_to_grid_benefit_daily:
    source: sensor.solpaneler_forsaljning
    name: Förtjänst från försäljning av solenergi
    cycle: daily
  pv_own_usage_benefit_monthly:
    source: sensor.solpaneler_fortjanst_egen_konsumtion
    name: Förtjänst från användning av solpaneler
    cycle: monthly
  pv_to_grid_benefit_monthly:
    source: sensor.solpaneler_forsaljning
    name: Förtjänst från försäljning av solenergi
    cycle: monthly
  pv_own_usage_benefit_yearly:
    source: sensor.solpaneler_fortjanst_egen_konsumtion
    name: Förtjänst från användning av solpaneler
    cycle: yearly
  pv_to_grid_benefit_yearly:
    source: sensor.solpaneler_forsaljning
    name: Förtjänst från försäljning av solenergi
    cycle: yearly
  - platform: template
    sensors:
      solpaneler_egen_konsumtion:
        friendly_name: "Egen konsumtion från solpaneler"
        unit_of_measurement: "kW"
        value_template: >
          {% set energy_produced = states('sensor.inverter_daily_yield') | float %}
          {% set energy_back_to_grid = states('sensor.electricity_meter_energiproduktion') | float %}      
          {{ (energy_produced - energy_back_to_grid)| round(2) }}

sensor:
  - platform: template
    sensors:
      solpaneler_forsaljning:
        friendly_name: "Försäljning av el från solpaneler"
        unit_of_measurement: "SEK"
        value_template: "{{ states('sensor.nordpool') | float * states('sensor.electricity_meter_energiproduktion') | float / 1000 }}"

  - platform: template
    sensors:
      elpris_totalt:
        friendly_name: "Total energikostnad vid inköp"
        unit_of_measurement: "SEK"
        value_template: >
          {% set spotpris = states('sensor.nordpool') | float %}
          {% set energiskatt = 0.535 | float %}     
          {% set elbolagspaslag = 0.04 | float %}   
          {% set elnatsavgift = 0.289 | float %}     
          {{ (spotpris + energiskatt + elbolagspaslag + elnatsavgift)| round(2) }}

  - platform: template
    sensors:
      solpaneler_fortjanst_egen_konsumtion:
        friendly_name: "Förtjänst ur egen konsumtion från solpaneler"
        unit_of_measurement: "SEK"
        value_template: "{{ states('sensor.elpris_totalt') | float * states('sensor.solpaneler_egen_konsumtion') | float / 1000 }}"

  - platform: template
    sensors:
      solpaneler_total_fortjanst:
        friendly_name: "Total förtjänst från användning och försäljning från solpaneler"
        unit_of_measurement: "SEK"
        value_template: >
          {% set pv_own_usage = states('sensor.solpaneler_fortjanst_egen_konsumtion') %}
          {% set pv_to_grid = states('sensor.solpaneler_forsaljning') %}
          {% set pv_own_value = 0 if pv_own_usage == "unknown" else pv_own_usage | float %}
          {% set pv_to_grid_value = 0 if pv_to_grid == "unknown" else pv_to_grid | float %}
          {{ (pv_own_value + pv_to_grid_value) | round(2) }}

  - platform: template
    sensors:
      total_pv_daily_benefit:
        friendly_name: "Daglig förtjänst från solpaneler"
        unit_of_measurement: "SEK"
        value_template: >
          {% set pv_own_usage = states('sensor.pv_own_usage_benefit_daily') %}
          {% set pv_to_grid = states('sensor.pv_to_grid_benefit_daily') %}
          {% set pv_own_value = 0 if pv_own_usage == "unknown" else pv_own_usage | float %}
          {% set pv_to_grid_value = 0 if pv_to_grid == "unknown" else pv_to_grid | float %}
          {{ (pv_own_value + pv_to_grid_value) | round(2) }}

  - platform: template
    sensors:
      total_pv_monthly_benefit:
        friendly_name: "Månatlig förtjänst från solpaneler"
        unit_of_measurement: "SEK"
        value_template: >
          {% set pv_own_usage = states('sensor.pv_own_usage_benefit_monthly') %}
          {% set pv_to_grid = states('sensor.pv_to_grid_benefit_monthly') %}
          {% set pv_own_value = 0 if pv_own_usage == "unknown" else pv_own_usage | float %}
          {% set pv_to_grid_value = 0 if pv_to_grid == "unknown" else pv_to_grid | float %}
          {{ (pv_own_value + pv_to_grid_value) | round(2) }}

  - platform: template
    sensors:
      total_pv_yearly_benefit:
        friendly_name: "Årlig förtjänst från solpaneler"
        unit_of_measurement: "SEK"
        value_template: >
          {% set pv_own_usage = states('sensor.pv_own_usage_benefit_yearly') %}
          {% set pv_to_grid = states('sensor.pv_to_grid_benefit_yearly') %}
          {% set pv_own_value = 0 if pv_own_usage == "unknown" else pv_own_usage | float %}
          {% set pv_to_grid_value = 0 if pv_to_grid == "unknown" else pv_to_grid | float %}
          {{ (pv_own_value + pv_to_grid_value) | round(2) }}

1 Like

Everything looks good. Did it pass the “check configuration” before restart?

  1. Check if the source sensors (like sensor.solpaneler_fortjanst_egen_konsumtion and sensor.solpaneler_forsaljning ) are available and providing data. I guess you are in sweden and maybe it’s just that there is no sun or panels under snow and therefore no solar production? Also it might be that it takes a little time for utility meter to start counting.
  2. Look at the Home Assistant logs for any errors related to your utility_meter configuration. This can provide clues if something is wrong with the setup.

Thanks for the quick reply!

Yep, it did pass the “check configuration” before restart. I checked the source sensors you’ve mentioned and for sensor.solpaneler_fortjanst_egen_konsumtion it did return a value (1,76). For the other, sensor.solpaneler_forsaljning, it only returned 0,00 (which ought to be correct as I had no power back to grid that day… The small amount power generated was consumed by my house. So your guess in terms of Sweden and snow are indeed correct :)).

The utility_meter has unfortunately still not created any sensors. I also had a look in the logs for this but did not find anything. However after a restart today I noticed below log entries which perhaps might be the issue? I’m not a programmer but I’m guessing it has to do with the invalid input ‘unavailable’ that appears for each of the entries?

TemplateError('ValueError: Template error: float got invalid input 'unavailable' when rendering template '{% set energy_produced = states('sensor.inverter_daily_yield') | float %} {% set energy_back_to_grid = states('sensor.electricity_meter_energiproduktion') | float %} {{ (energy_produced - energy_back_to_grid)| round(2) }}' but no default was specified') while processing template 'Template<template=({% set energy_produced = states('sensor.inverter_daily_yield') | float %} {% set energy_back_to_grid = states('sensor.electricity_meter_energiproduktion') | float %} {{ (energy_produced - energy_back_to_grid)| round(2) }}) renders=4>' for attribute '_attr_native_value' in entity 'sensor.solpaneler_egen_konsumtion'
TemplateError('ValueError: Template error: float got invalid input 'unavailable' when rendering template '{{ states('sensor.nordpool') | float * states('sensor.electricity_meter_energiproduktion') | float / 1000 }}' but no default was specified') while processing template 'Template<template=({{ states('sensor.nordpool') | float * states('sensor.electricity_meter_energiproduktion') | float / 1000 }}) renders=4>' for attribute '_attr_native_value' in entity 'sensor.solpaneler_forsaljning'
TemplateError('ValueError: Template error: float got invalid input 'unavailable' when rendering template '{{ states('sensor.elpris_totalt') | float * states('sensor.solpaneler_egen_konsumtion') | float / 1000 }}' but no default was specified') while processing template 'Template<template=({{ states('sensor.elpris_totalt') | float * states('sensor.solpaneler_egen_konsumtion') | float / 1000 }}) renders=4>' for attribute '_attr_native_value' in entity 'sensor.solpaneler_fortjanst_egen_konsumtion'
TemplateError('ValueError: Template error: float got invalid input 'unavailable' when rendering template '{% set pv_own_usage = states('sensor.solpaneler_fortjanst_egen_konsumtion') %} {% set pv_to_grid = states('sensor.solpaneler_forsaljning') %} {% set pv_own_value = 0 if pv_own_usage == "unknown" else pv_own_usage | float %} {% set pv_to_grid_value = 0 if pv_to_grid == "unknown" else pv_to_grid | float %} {{ (pv_own_value + pv_to_grid_value) | round(2) }}' but no default was specified') while processing template 'Template<template=({% set pv_own_usage = states('sensor.solpaneler_fortjanst_egen_konsumtion') %} {% set pv_to_grid = states('sensor.solpaneler_forsaljning') %} {% set pv_own_value = 0 if pv_own_usage == "unknown" else pv_own_usage | float %} {% set pv_to_grid_value = 0 if pv_to_grid == "unknown" else pv_to_grid | float %} {{ (pv_own_value + pv_to_grid_value) | round(2) }}) renders=4>' for attribute '_attr_native_value' in entity 'sensor.solpaneler_total_fortjanst'```

Hi. Sorry for being lazy and used ChatGPT but here is the aswer:

The error messages you’re encountering in your Home Assistant configuration are due to the float filter receiving ‘unavailable’ as input. When a sensor’s state is ‘unavailable’, ‘unknown’, or any non-numeric string, attempting to convert it directly to a float will result in a ValueError. To address this, you need to modify your template sensors to handle such cases gracefully.

Here’s how you can update your templates to handle ‘unavailable’ or ‘unknown’ states:

  1. For sensor.solpaneler_egen_konsumtion:
value_template: >
  {% set energy_produced = states('sensor.inverter_daily_yield') | float(default=0) %}
  {% set energy_back_to_grid = states('sensor.electricity_meter_energiproduktion') | float(default=0) %}      
  {{ (energy_produced - energy_back_to_grid) | round(2) }}

  1. or sensor.solpaneler_forsaljning:
value_template: >
  {% set nordpool_price = states('sensor.nordpool') | float(default=0) %}
  {% set energy_back_to_grid = states('sensor.electricity_meter_energiproduktion') | float(default=0) %}
  {{ nordpool_price * energy_back_to_grid / 1000 }}

  1. For sensor.solpaneler_fortjanst_egen_konsumtion:
value_template: >
  {% set total_price = states('sensor.elpris_totalt') | float(default=0) %}
  {% set own_consumption = states('sensor.solpaneler_egen_konsumtion') | float(default=0) %}
  {{ total_price * own_consumption / 1000 }}

  1. For sensor.solpaneler_total_fortjanst:
value_template: >
  {% set pv_own_usage = states('sensor.solpaneler_fortjanst_egen_konsumtion') | float(default=0) %}
  {% set pv_to_grid = states('sensor.solpaneler_forsaljning') | float(default=0) %}
  {{ (pv_own_usage + pv_to_grid) | round(2) }}

In these templates, I used | float(default=0) which converts the state to a float, but if the state is ‘unavailable’, ‘unknown’, or any non-numeric string, it defaults to 0. This way, your calculations won’t break if a sensor is temporarily unavailable or returns an unexpected value.

After making these changes, ensure to check the configuration and restart Home Assistant for the changes to take effect.

However this does not explain why Utility Meter entities are not created. Could it be that you have utility_meter: twice in your configuration.yaml? If you use utility_meter: twice or more in your configuration.yaml, it will take acocunt only the last one. Same apllies when you use sensor:

Wow, thanks a lot for providing a solution to this Arva! I checked my configuration.yaml but not mentioned twice. I then thought that maybe I’ve overlooked something simple so I checked whether I needed to add some sort of utility meter as an integration. Apparently there is an integration for this. I gave it a go and was able to configure the meters via UI and that did the trick.

Many thanks again for your tremendous support and an awesome effort in creating the whole setup! :grinning:

1 Like

Actually you can create Utility Meter in UI as well, even without the integration.

  • Browse to your Home Assistant instance.
  • Go to Settings > Devices & Services.
  • At the top of the screen, select the tab: Helpers.
  • In the bottom right corner, select the Create helper button.
  • From the list, select Utility Meter.
  • Follow the instructions on screen to complete the setup.

Even better, thanks for the tip!

Now being a fan of your work I also discovered a very useful card by Tibbie86 and you. I have implemented your lovelace code and the custom numberbox-card. The only thing I have changed is the nordpool.sensor.

It works great apart from the actual calculation for the cheapest X hours. I can select number of hours in the slider and the markdown card picks up the number of hours correctly. However the price is stuck at €2 and then it’s divided with the number oh hours; e.g. €2/1 hour, €2/2 hours, €2/3 hours and so on. Am I missing something or does the card not work work as intended?

The code I am using:

type: vertical-stack
cards:
  - type: markdown
    alignment: justify
    content: >-
      {% set min_price = state_attr('sensor.nordpool', 'min') | float %} {% set
      max_price = state_attr('sensor.nordpool', 'max') | float %} {% set
      current_price = state_attr('sensor.nordpool', 'current_price') | float %}
      {% set price_quantiles = {0: 'Price is currently Very Cheap 1/5', 1:
      'Price is currently Cheap 2/5', 2: 'Price is currently In Between 3/5', 3:
      'Price is currently Expensive 4/5', 4: 'Price is currently Very Expensive
      5/5'} %} {% if current_price < min_price %}
        Very Cheap
      {% elif current_price > max_price %}
        Very Expensive
      {% else %}
        {{ price_quantiles[(current_price - min_price) / (max_price - min_price) // 0.2] }}
      {% endif %}
  - type: markdown
    alignment: justify
    content: >-
      {% set priceList = state_attr('sensor.nordpool', 'today')[00:23] %} {% set
      dateList = state_attr('sensor.nordpool', 'raw_today')[00:23] %} {% set
      minPrice = min(priceList) %} {% set minIndex = priceList.index(minPrice)
      %} {% set minDateTimeStr = dateList[minIndex].start | string %} {% set
      minDateTime = strptime(minDateTimeStr[0:19], '%Y-%m-%d %H:%M:%S') %} {%
      set currentHour = now().hour %} {% if currentHour < minDateTime.hour %}
        The cheapest price today is {{ minPrice }} €/kWh and starts at {{ minDateTime.hour }}:00.
      {% else %}
        The cheapest price today started at {{ minDateTime.hour }}:00 and was {{ minPrice }} €/kWh.
      {% endif %}
  - type: custom:numberbox-card
    border: true
    entity: input_number.antal_billiga_timmar_som_behovs
  - 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.antal_billiga_timmar_som_behovs')
      | int %} {% set nordpoolentity = 'sensor.nordpool' %} {% 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.
  - type: markdown
    alignment: justify
    title: null
    content: |-
      Now: {{ '%.2f' | format((state_attr('sensor.nordpool',
           'current_price')|float / 0.05) | round() * 0.05) }}
      Average: {{ '%.2f' | format((state_attr('sensor.nordpool',
           'average')|float / 0.05) | round() * 0.05) }}  
      Median: {{ '%.2f' | format((state_attr('sensor.nordpool',
           'mean')|float / 0.05) | round() * 0.05) }}  
      Max: {{ '%.2f' | format((state_attr('sensor.nordpool',
           'max')|float / 0.05) | round() * 0.05) }}  
      Min: {{ '%.2f' | format((state_attr('sensor.nordpool',
           'min')|float / 0.05) | round() * 0.05) }}
       
      {% if (now().strftime('%T')) > '13:01:00'  %}
      Tomorrow:
      Average: {{state_attr('sensor.nordpool', 
      'tomorrow')|average|round(1)}}
      Min: {{state_attr('sensor.nordpool', 
      'tomorrow')|min|round(1)}}
      Max: {{state_attr('sensor.nordpool',
      'tomorrow')|max|round(1)}}

      {%- else %}
      Electricity prices for tomorrow are not available until 13:00.
      {% endif -%}

This is te part of the code you have issue:

  - 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.antal_billiga_timmar_som_behovs')
      | int %} {% set nordpoolentity = 'sensor.nordpool' %} {% 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.
  • The variable lowestiter.kr is initialized with a value of 2 (€2). This variable should be updated during the calculation to reflect the actual lowest sum of prices for the specified number of hours. If this variable isn’t being updated correctly due to some reason (like a logic error or data issue), it would default to its initial value, resulting in the constant €2 output.

  • If the prices.price array, which is supposed to contain the electricity prices, is not being updated or populated correctly, the calculations would default to using the initialized value of lowestiter.kr. You should verify that the sensor.nordpool entity is providing the correct data and that the data is being correctly added to the prices.price list.

Check is sensor.nordpool has hourly attributes:

Code uses the attributes to get hourly values for the calculation.

I did use your code and changed the nordpool entity and input entity and everything worked for me. So focus on sensor.nordpool

I also fine tuned the last markdown block. For some reason nordpool does not update every day on 13.00 and then there is an error.

What i did:

  1. Dynamic Data Availability Check:
  • Modified the code to check for the actual availability of ‘tomorrow’s’ electricity prices from the sensor.nordpool_with_vat_and_tarifss sensor, instead of relying solely on the time being past 13:00.
  1. Improved Time-Based Messages:
  • Updated the messaging logic to provide clearer information based on the current time and the data’s availability.
  • Before 13:00, the dashboard now displays: “Electricity prices for tomorrow will be available after 13:00.”
  • After 13:00, if the data is not available, it shows: “Electricity prices for tomorrow are typically updated by 13:00, but they have not been updated yet.”

Code:

type: markdown
alignment: justify
title: null
content: >-
  Now: {{ '%.2f' | format((state_attr('sensor.nordpool_with_vat_and_tarifss',
  'current_price')|float / 0.05) | round(2) * 0.05) }} €/kWh

  Average: {{ '%.2f' |
  format((state_attr('sensor.nordpool_with_vat_and_tarifss', 'average')|float /
  0.05) | round(2) * 0.05) }} €/kWh

  Median: {{ '%.2f' | format((state_attr('sensor.nordpool_with_vat_and_tarifss',
  'mean')|float / 0.05) | round(2) * 0.05) }} €/kWh 

  Max: {{ '%.2f' | format((state_attr('sensor.nordpool_with_vat_and_tarifss',
  'max')|float / 0.05) | round(2) * 0.05) }} €/kWh 

  Min: {{ '%.2f' | format((state_attr('sensor.nordpool_with_vat_and_tarifss',
  'min')|float / 0.05) | round(2) * 0.05) }} €/kWh

  {% set current_time = now().strftime('%H:%M') %} {% if current_time < '13:00'
  %} Electricity prices for tomorrow will be available after 13:00. {% else %}
    {% if state_attr('sensor.nordpool_with_vat_and_tarifss', 'tomorrow') %}
      Tomorrow:
      Average: {{ state_attr('sensor.nordpool_with_vat_and_tarifss', 'tomorrow')|average|round(2) }}
      Min: {{ state_attr('sensor.nordpool_with_vat_and_tarifss', 'tomorrow')|min|round(2) }}
      Max: {{ state_attr('sensor.nordpool_with_vat_and_tarifss', 'tomorrow')|max|round(2) }}
    {% else %}
    Electricity prices for tomorrow are typically updated by 13:00, but they have not been updated yet.
    {% endif %}
  {% endif %}

That’s strange. I checked sensor.nordpool as you suggested and it does indeed get hourly values. Also had a look in the logs but nothing there as far as I could see.

There is one suggestion left which I haven’t checked yet; prices.price list. Where do I find this and how do I verify that the data has been correctly added to the prices.price list please?

It’s in the same code. It extracts data from the attributes of sensor.nordpool and does some calculations from it.

Alright, as I really want to get this to work and the fact that you got it to work using the code I posted I decided to restart from scratch. This time I only copied the markdown card and the associated numberbox-card. I then changed to sensor.nordpool in one place. I also configured a new input.number helper with the same name as yours. Well… that did not turn out as planned. Unfortunately it still defaults to €2.

The weird part is that I also have the card with the 4 most expensive hours in a a different vertical stack and that one works. Since that work I then also tried to copy that code and replace the 2 timehighest.hr and the highestiter.kr at the end with timelowest.hr and lowestiter.kr… Well yet another failure, the default value persists.

As a last resort I had another look in the logs. There are now a couple of entries related to the energy calculation cards which hopefully might be of interest. However I fail to understand what the log entries refer to and perhaps more importantly, how to fix the error.

Now you have already helped me tremendously and I’m extremely grateful for all your guidance in order to get my setup to work. I hate to ask for your help again. Yet, desperate as I currently am I still turn once again to you Arva; Does the log entry/entries by any chance make any sense to you?

2024-01-16 21:49:41.177 ERROR (MainThread) [homeassistant.helpers.event] Error while processing template: Template<template=({% 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' %} {% 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.) renders=2>
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 567, in async_render
render_result = _render_with_context(self.template, compiled, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2305, in _render_with_context
return template.render(**kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
TypeError: can only concatenate list (not "NoneType") to list
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 693, in async_render_to_info
render_info._result = self.async_render(
^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 569, in async_render
raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: TypeError: can only concatenate list (not "NoneType") to list
2024-01-16 21:49:41.222 ERROR (MainThread) [homeassistant.helpers.event] Error while processing template: Template<template=(<ha-alert title=Billigast alert-type="success"> {% set priceList = state_attr('sensor.nordpool', 'today')[00:23] %} {% set dateList = state_attr('sensor.nordpool', 'raw_today')[00:23] %} {% set minPrice = min(priceList) %} {% set minIndex = priceList.index(minPrice) %} {% set minDateTimeStr = dateList[minIndex].start | string %} {% set minDateTime = strptime(minDateTimeStr[0:19], '%Y-%m-%d %H:%M:%S') %} {% set currentHour = now().hour %} {% if currentHour < minDateTime.hour %}
Dagens lägsta pris, {{ minPrice }} öre/kWh, infaller klockan {{ minDateTime.hour }}:00.
{% else %}
Det lägsta priset startade redan klockan {{ minDateTime.hour }}:00 tidigare idag och låg då på {{ minPrice }} öre/kWh.
{% endif %} </ha-alert>) renders=2>
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 567, in async_render
render_result = _render_with_context(self.template, compiled, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2305, in _render_with_context
return template.render(**kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
TypeError: 'NoneType' object is not subscriptable
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 693, in async_render_to_info
render_info._result = self.async_render(
^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 569, in async_render
raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: TypeError: 'NoneType' object is not subscriptable
2024-01-16 21:49:41.393 ERROR (MainThread) [homeassistant.helpers.event] Error while processing template: Template<template=({% 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.antal_billiga_timmar_som_behovs') | int %} {% set nordpoolentity = 'sensor.nordpool' %} {% 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 -%} Billligaste {{ num_hours }} {{ 'timmen' if num_hours == 1 else 'timmarna' }} börjar {% if (timelowest.hr < 24) %}idag{% else %}tomorrow{% endif %} klockan {{ timemapper[timelowest.hr] }}, med en genomsnittslig kostnad på {{ "%.2f"|format(lowestiter.kr/num_hours) }} öre/kWh.) renders=2>
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 567, in async_render
render_result = _render_with_context(self.template, compiled, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2305, in _render_with_context
return template.render(**kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
TypeError: can only concatenate list (not "NoneType") to list
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 693, in async_render_to_info
render_info._result = self.async_render(
^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 569, in async_render
raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: TypeError: can only concatenate list (not "NoneType") to list
2024-01-16 21:49:41.461 ERROR (MainThread) [homeassistant.helpers.event] Error while processing template: Template<template=(<ha-alert title=Dyrast alert-type="error"> {% 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.antal_billiga_timmar_som_behovs') | int %} {% set nordpoolentity = 'sensor.nordpool' %} {% 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 -%} **Dyraste** {{ num_hours }} {{ 'timmen' if num_hours == 1 else 'timmarna' }} börjar {% if (timehighest.hr < 24) %}idag{% else %}imorgon{% endif %} klockan {{ timemapper[timehighest.hr] }}, med en genomsnittslig kostnad på **{{ "%.2f"|format(highestiter.kr/num_hours) }} öre/kWh**. </ha-alert>) renders=2>
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 567, in async_render
render_result = _render_with_context(self.template, compiled, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2305, in _render_with_context
return template.render(**kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
TypeError: can only concatenate list (not "NoneType") to list
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 693, in async_render_to_info
render_info._result = self.async_render(
^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 569, in async_render
raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: TypeError: can only concatenate list (not "NoneType") to list
2024-01-16 21:49:41.490 ERROR (MainThread) [homeassistant.helpers.event] Error while processing template: Template<template=(<ha-alert title="Nästa dag" alert-type="info"> {% set priceList = state_attr('sensor.nordpool', 'tomorrow')[00:23] %} {% set dateList = state_attr('sensor.nordpool', 'raw_tomorrow')[00:23] %} {% set minPrice = min(priceList) %} {% set minIndex = priceList.index(minPrice) %} {% set minDateTimeStr= dateList[minIndex].start | string %} {% set minDateTime = strptime(minDateTimeStr[0:19], '%Y-%m-%d %H:%M:%S') %} Lägsta pris imorgon är **{{ minPrice }} öre/kWh** och startar **kl {{ minDateTime.hour }}:00** </ha-alert>) renders=2>
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 567, in async_render
render_result = _render_with_context(self.template, compiled, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2305, in _render_with_context
return template.render(**kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
TypeError: 'NoneType' object is not subscriptable
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 693, in async_render_to_info
render_info._result = self.async_render(
^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 569, in async_render
raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: TypeError: 'NoneType' object is not subscriptable

Can you copy the sensor.nordpool attributes here?