Any good ideas are welcome. Nordpool Energy Price per hour

i also played with the code for this graph that was provided in this thread to fix the gap when raw_today and raw_tomorrow was provided.

data_generator was modified and if someone can rewrite it to be better go ahead!

type: custom:apexcharts-card
graph_span: 48h
span:
  start: day
  offset: +0H
header:
  title: Electricity Price
  show: true
  show_states: false
  colorize_states: true
hours_12: false
stacked: false
experimental:
  color_threshold: true
all_series_config:
  show:
    legend_value: false
    datalabels: false
    extremas: true
    in_brush: true
  float_precision: 3
  type: area
  invert: false
  fill_raw: last
  color_threshold:
    - value: -1
      color: 1E90FF
    - value: 0.5
      color: '008000'
    - value: 1
      color: DAA520
    - value: 2
      color: FF0000
now:
  show: true
  label: Now
  color: red
series:
  - entity: sensor.nordpool_kwh_se3_sek_3_10_025
    name: Current day
    opacity: 0.7
    extend_to: false
    data_generator: >
      var todayData = entity.attributes.raw_today.map((entry) => {
       return [new Date(entry.start).getTime(), entry.value];
      });


      var tomorrowData = entity.attributes.raw_tomorrow.slice(0, 1).map((entry)
      => {
        return [new Date(entry.start).getTime(), entry.value];
      });


      return todayData.concat(tomorrowData);
  - entity: sensor.nordpool_kwh_se3_sek_3_10_025
    name: Tomorrow
    opacity: 0.5
    data_generator: |
      return entity.attributes.raw_tomorrow.map((start, index) => {

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

      });
apex_config:
  chart:
    height: 400px
    animations:
      enabled: true
      easing: easeinout
      speed: 800
      animateGradually:
        enabled: true
        delay: 150
  zoom:
    enabled: true
    type: x
    autoScaleYaxis: true
    zoomedArea:
      fill:
        color: '#90CAF9'
        opacity: 0.4
      stroke:
        color: '#0D47A1'
        opacity: 0.4
        width: 1
  legend:
    show: false
    floating: true
    offsetY: 25
  yaxis:
    opposite: false
    reversed: false
    logarithmic: false
    decimalsInFloat: 2
    labels:
      show: true
    tooltip:
      enabled: true
    crosshairs:
      show: true
  xaxis:
    labels:
      show: true
      rotate: -45
      rotateAlways: true
    logarithmic: true
  stroke:
    show: true
    curve: stepline
    lineCap: butt
    colors: undefined
  plotOptions:
    candlestick:
      colors:
        upward: '#00B746'
        downward: '#EF403C'
      wick:
        useFillColor: true
  markers:
    size: 1
  grid:
    show: true
    strokeDashArray: 1
    position: front
    xaxis:
      lines:
        show: true

2 Likes

Here is mine with 48’ish hours.

Screenshot 2023-08-31 222904

type: custom:apexcharts-card
graph_span: 46h
header:
  title: Energy price
  show: true
  show_states: true
  colorize_states: true
span:
  start: day
now:
  show: true
  label: Now
  color: '#0074D9'
experimental:
  color_threshold: true
series:
  - entity: sensor.nordpool
    name: Price
    type: column
    color_threshold:
      - value: 0
        color: '#2ECC40'
      - value: 10
        color: '#FFDC00'
      - value: 20
        color: '#FF4136'
    show:
      extremas: true
      header_color_threshold: true
      name_in_header: false
      in_header: raw
    data_generator: >
      return [...entity.attributes.raw_today,
      ...entity.attributes.raw_tomorrow].map((item) =>
        [Date.parse(item.start), item.value]);
apex_config:
  chart:
    height: 300px
  tooltip:
    x:
      show: false
2 Likes

Heya! First winter with no fixed energy price, so 100% hourly price!
Is there a collection of all smart tools to use to give you the status of the current energy price? I guess this thread with its 458 pages have a lot of good tips, but going through it could take time.
I have one that sort the daily energy price into 5 parts giving me how cheap/expensive the price is. Is this one still valid? Is there some other like this that may be better?

- sensor:
    - name: Daily Energy Price Status
      unique_id: XXXX
      state: >
        {% set yest_min_price = states('sensor.daily_min_price')  | float %}
        {% set yest_max_price = states('sensor.daily_max_price')  | float %}
        {% set current_price = states('sensor.daily_current_price')  | float %}
        {% set price_quantiles = {0: 'Very Cheap 1/5', 1: 'Cheap 2/5', 2: 'In Between 3/5', 3: 'Expensive 4/5', 4: 'Very Expensive 5/5'} %}
        {% if current_price < yest_min_price%}
          Very Cheap
        {% elif current_price > yest_max_price %}
          Very Expensive
        {% else %}
          {{ price_quantiles[(current_price - yest_min_price) / (yest_max_price - yest_min_price) // 0.2] }}
        {% endif %}

I think you might find this interesting. It’s not perfect but offers very easy way to take an advantage of thecheapest hours.

Home Assistant: Advanced Nord Pool Cheapest Hours automation with local calendar support – Creating Smart Home

1 Like

Wanted a breakdown showing that the Government gets most of the money, took some fiddling around but I’m happy with the result.

type: custom:apexcharts-card
graph_span: 48h
stacked: true
header:
  title: Energy price breakdown
  show: true
span:
  start: day
now:
  show: true
  label: Now
apex_config:
  legend:
    show: true
series:
  - entity: sensor.nordpool_kwh_se4_sek_3_10_025
    name: tax
    type: column
    float_precision: 2
    extend_to: false
    color: red
    unit: ' '
    show:
      legend_value: false
    data_generator: >
      return
      entity.attributes.raw_today.concat(entity.attributes.raw_tomorrow).map((start,
      index) => {
        return [new Date(start["start"]).getTime(), Math.min(0, entity.attributes.raw_today.concat(entity.attributes.raw_tomorrow)[index]["value"]) * 0.8 + 0.392];
      });
  - entity: sensor.nordpool_kwh_se4_sek_3_10_025
    name: transfer
    type: column
    float_precision: 2
    extend_to: false
    color: orange
    unit: ' '
    show:
      legend_value: false
    data_generator: >
      return
      entity.attributes.raw_today.concat(entity.attributes.raw_tomorrow).map((start,
      index) => {
        return [new Date(start["start"]).getTime(), 0.1104];
      });
  - entity: sensor.nordpool_kwh_se4_sek_3_10_025
    name: E.ON add
    type: column
    float_precision: 2
    extend_to: false
    color: yellow
    unit: ' '
    show:
      legend_value: false
    data_generator: >
      return
      entity.attributes.raw_today.concat(entity.attributes.raw_tomorrow).map((start,
      index) => {
        return [new Date(start["start"]).getTime(), 0.1041];
      });
  - entity: sensor.nordpool_kwh_se4_sek_3_10_025
    name: VAT
    type: column
    float_precision: 2
    extend_to: false
    color: blue
    unit: ' '
    show:
      legend_value: false
    data_generator: >
      return
      entity.attributes.raw_today.concat(entity.attributes.raw_tomorrow).map((start,
      index) => {
        return [new Date(start["start"]).getTime(), entity.attributes.raw_today.concat(entity.attributes.raw_tomorrow)[index]["value"] *0.2 + 0.151625 ];
      });
  - entity: sensor.nordpool_kwh_se4_sek_3_10_025
    name: spot
    type: column
    float_precision: 2
    extend_to: false
    color: green
    unit: ' '
    show:
      legend_value: false
    data_generator: >
      return
      entity.attributes.raw_today.concat(entity.attributes.raw_tomorrow).map((start,
      index) => {
        return [new Date(start["start"]).getTime(), entity.attributes.raw_today.concat(entity.attributes.raw_tomorrow)[index]["value"] * 0.8];
      });
yaxis:
  - min: ~0
    max: ~2

This is my very first post here, so please be kind if I did something wrong :wink:

Best regards,

6 Likes

I just combined the raw data for today and tomorrow and display it with apexchart:

2023-09-25_13-02-16

Just want to thank all of you for sharing code. Its priceless for us who only have a master’s degree in Cut and Paste.

My thermostat uses Nordpool for two saving modes (color blue price under 0, green price up to 0,8 NOK, etc. Black color tomorrow):

  1. Mode Cost: I can set a cost value (slider) and then the thermostat is on when cost is like or under slider value.
    The normal schedule day/weekend schedule works except that heat is not adjusted down at “Day heat down” hours.
  2. I can set a number of hours in a day, so the thermostat only heats (temp. normal) these hours, and the” temp.min” for the rest of the day.

Normal schedule day/weekend schedule - follows the time settings. In the weekends and national holidays, the heat is not adjusted down at “Day heat down” hours. When house is in Holliday- or Away-mode, temp. min is set 24-hours.

4 Likes

Hey! I want a sensor showing my the cheapest (or most expensive) (lets say) 3 hours of energy today.
I have one that I got from someon else online that shows exactly this but tomorrow.
Is there a way to change this to show the 3 cheapest (and/or most expensive) hours today? Or is there some easier way to make a template-sensor showing this?

- sensor:
    - name: XXXX
      unique_id: XXXX
      state: >
        {%- set numberOfSequentialHours =  states('input_number.elprisverktyg_antal_timmar') | int -%}
        {%- set lastHour = states('input_number.elprisverktyg_last_hour') | int -%}
        {%- set firstHour = states('input_number.elprisverktyg_first_hour') | int -%}
​
        {%- if state_attr('sensor.nordpool_kwh_se3_sek_3_10_025_med_moms', 'tomorrow_valid') == true -%}
          {%- set ns = namespace(counter=0, list=[], cheapestHour=today_at("00:00") + timedelta( hours = (24)), cheapestPrice=999.00) -%}
          {%- for i in range(firstHour + numberOfSequentialHours, lastHour+1) -%}
            {%- set ns.counter = 0.0 -%}
            {%- for j in range(i-numberOfSequentialHours, i) -%}
              {%- set ns.counter = ns.counter + state_attr('sensor.nordpool_kwh_se3_sek_3_10_025_med_moms', 'tomorrow')[j] -%}
            {%- endfor -%}
            {%- set ns.list = ns.list + [ns.counter] -%}
            {%- if ns.counter < ns.cheapestPrice -%}
              {%- set ns.cheapestPrice = ns.counter -%}
              {%- set ns.cheapestHour = today_at("00:00") + timedelta( hours = (24 + i - numberOfSequentialHours)) -%}
            {%- endif -%}
          {%- endfor -%}
          {{ ns.cheapestHour }}
          {%- set ns.cheapestPrice = ns.cheapestPrice / numberOfSequentialHours -%}
        {%- endif -%}

Here is a working code for the one you found and pasted in your post. Just change “sensor.nordpool” to your own one

- sensor:
    - name: Daily Energy Price Status
      unique_id: XXXX
      state: >
        {% 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: 'Very Cheap 1/5', 1: 'Cheap 2/5', 2: 'In Between 3/5', 3: 'Expensive 4/5', 4: '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 %}
1 Like

Yes, here is some code that does that and more. Every line that starts with " - type: markdown" is a new window with new info. Just change “sensor.nordpool” to your own one

type: vertical-stack
cards:
  - type: markdown
    alignment: justify
    title: null
    content: |-
      Nu: {{ '%.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'  %}
       Imorgon:
       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 %}
       Elpriserna för imorgon är inte tillgängliga förrän kl.13           
       {% 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') %}
      Billigaste priset idag är {{ minPrice }} Öre/kWh och startar kl {{
      minDateTime.hour }}:00

  - type: markdown
    alignment: justify
    content: "{% set iterativesum = namespace(iter=[]) %}\n      {% set lowestiter = namespace(kr=2) %}\n      {% set timelowest = namespace(hr=2) %}\n      {% set highestiter = namespace(kr=0) %}\n      {% set timehighest = namespace(hr=0) %}\n      {% set num_hours = 4 | int %}\n      {% set nordpoolentity = 'sensor.nordpool' %}\n      {% set timemapper = { \n      0: '00:00', 1 : '01:00', 2 : '02:00', 3 : '03:00',\n      4 : '04:00', 5 : '05:00', 6 : '06:00', 7 : '07:00',\n      8 : '08:00', 9 : '09:00', 10 : '10:00', 11 : '11:00',\n      12 : '12:00', 13 : '13:00', 14 : '14:00', 15 : '15:00',\n      16 : '16:00', 17 : '17:00', 18 : '18:00', 19 : '19:00',\n      20 : '20:00', 21 : '21:00', 22 : '22:00', 23 : '23:00',\n      24 : '00:00', 25 : '01:00', 26 : '02:00', 27 : '03:00',\n      28 : '04:00', 29 : '05:00', 30 : '06:00', 31 : '07:00',\n      32 : '08:00', 33 : '09:00', 34 : '10:00', 35 : '11:00',\n      36 : '12:00', 37 : '13:00', 38 : '14:00', 39 : '15:00',\n      40 : '16:00', 41 : '17:00', 42 : '18:00', 43 : '19:00',\n      44 : '20:00', 45 : '21:00', 46 : '22:00', 47 : '23:00',\n      48 : '0:00', } %}\n      {% set prices = namespace(price=[]) %}\n      {% set prices.price = prices.price + state_attr(nordpoolentity, 'today') %}\n      {%- if state_attr(nordpoolentity,'tomorrow') | length == 1 -%}\n      Morgondagens priser ej släppta\n      {% else %}\n      {% set prices.price = prices.price + state_attr(nordpoolentity,\t'tomorrow') %}\n      {% endif %}\n      {%- for n in range(prices.price|length -num_hours +1) -%}\n      {%- set tempsum= namespace(temp=0) -%}\n      {%- for i in range(num_hours) -%}\n      {%- set tempsum.temp = tempsum.temp + prices.price[n+i] -%}\n      {% endfor -%}\n      {% set iterativesum.iter = iterativesum.iter + [tempsum.temp] -%}\n      {% endfor -%}\n      {% for iter in iterativesum.iter -%}\n      {%- if loop.index > now().hour -%}\n      {%- if iter < lowestiter.kr | float -%}\n      {%- set lowestiter.kr = iter | float -%}\n      {%- set timelowest.hr = loop.index -1 -%}\n      {%- endif -%}\n      {%- if iter > highestiter.kr | float -%}\n      {%- set highestiter.kr = iter | float -%}\n      {%- set timehighest.hr = loop.index -1 -%}\n      {%- endif -%}\n      {%- endif -%}\n      {% endfor -%}\n      De billigaste fyra ({{num_hours}}) timmarna startar {% if (timelowest.hr < 24) %}idag{% else %}imorgon{% endif %} kl {{timemapper[timelowest.hr]}}, då snittpriset är {{\"%.2f\"|format(lowestiter.kr/num_hours)}} Öre/kWh. "

  - type: markdown
    alignment: justify
    content: "{% set iterativesum = namespace(iter=[]) %}\n      {% set lowestiter = namespace(kr=2) %}\n      {% set timelowest = namespace(hr=2) %}\n      {% set highestiter = namespace(kr=0) %}\n      {% set timehighest = namespace(hr=0) %}\n      {% set num_hours = 4 | int %}\n      {% set nordpoolentity = 'sensor.nordpool' %}\n      {% set timemapper = { \n      0: '00:00', 1 : '01:00', 2 : '02:00', 3 : '03:00',\n      4 : '04:00', 5 : '05:00', 6 : '06:00', 7 : '07:00',\n      8 : '08:00', 9 : '09:00', 10 : '10:00', 11 : '11:00',\n      12 : '12:00', 13 : '13:00', 14 : '14:00', 15 : '15:00',\n      16 : '16:00', 17 : '17:00', 18 : '18:00', 19 : '19:00',\n      20 : '20:00', 21 : '21:00', 22 : '22:00', 23 : '23:00',\n      24 : '00:00', 25 : '01:00', 26 : '02:00', 27 : '03:00',\n      28 : '04:00', 29 : '05:00', 30 : '06:00', 31 : '07:00',\n      32 : '08:00', 33 : '09:00', 34 : '10:00', 35 : '11:00',\n      36 : '12:00', 37 : '13:00', 38 : '14:00', 39 : '15:00',\n      40 : '16:00', 41 : '17:00', 42 : '18:00', 43 : '19:00',\n      44 : '20:00', 45 : '21:00', 46 : '22:00', 47 : '23:00',\n      48 : '0:00', } %}\n      {% set prices = namespace(price=[]) %}\n      {% set prices.price = prices.price + state_attr(nordpoolentity, 'today') %}\n      {%- if state_attr(nordpoolentity,'tomorrow') | length == 1 -%}\n      Morgondagens priser ej släppta\n      {% else %}\n      {% set prices.price = prices.price + state_attr(nordpoolentity,\t'tomorrow') %}\n      {% endif %}\n      {%- for n in range(prices.price|length -num_hours +1) -%}\n      {%- set tempsum= namespace(temp=0) -%}\n      {%- for i in range(num_hours) -%}\n      {%- set tempsum.temp = tempsum.temp + prices.price[n+i] -%}\n      {% endfor -%}\n      {% set iterativesum.iter = iterativesum.iter + [tempsum.temp] -%}\n      {% endfor -%}\n      {% for iter in iterativesum.iter -%}\n      {%- if loop.index > now().hour -%}\n      {%- if iter < lowestiter.kr | float -%}\n      {%- set lowestiter.kr = iter | float -%}\n      {%- set timelowest.hr = loop.index -1 -%}\n      {%- endif -%}\n      {%- if iter > highestiter.kr | float -%}\n      {%- set highestiter.kr = iter | float -%}\n      {%- set timehighest.hr = loop.index -1 -%}\n      {%- endif -%}\n      {%- endif -%}\n      {% endfor -%}\n      De dyraste fyra ({{num_hours}}) timmarna startar {% if (timehighest.hr < 24) %}idag{% else %}imorgon{% endif %} kl {{timemapper[timehighest.hr]}}, då snittpriset är {{\"%.2f\"|format(highestiter.kr/num_hours)}} Öre/kWh"

  - type: markdown
    alignment: justify
    content: >-
      {% 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') %} Billigaste priset
      imorgon är {{ minPrice }} Öre/kWh och startar kl {{ minDateTime.hour }}:00

2 Likes

Wow thank you! This was what I was looking for! :slight_smile:

Wanna share the code?

Thanks @Tibbie86 , great work. I added those two codes together and did some minor adjustments:

  1. Translated to english and used €
  2. If the time has passed it will say like this: The cheapest price today started at 4:00 and was 0.093 €/kWh.
  3. Added a number selector so you can change how many cheapest hours you want to see. Made number helper. In my case input_number.cheapest_hours_needed and changed your code, that will use it.

Result:

Lovelace Code. Note that I used custom card: numberbox-card:

type: vertical-stack
cards:
  - type: markdown
    alignment: justify
    content: >-
      {% set min_price = state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'min')
      | float %} {% set max_price =
      state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'max') | float %} {% set
      current_price = state_attr('sensor.nordpool_kwh_ee_eur_3_10_0',
      '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_kwh_ee_eur_3_10_0',
      'today')[00:23] %} {% set dateList =
      state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', '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.cheapest_hours_needed
  - 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_kwh_ee_eur_3_10_0' %}
      {% 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_kwh_ee_eur_3_10_0',
           'current_price')|float / 0.05) | round() * 0.05) }}
      Average: {{ '%.2f' |
      format((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0',
           'average')|float / 0.05) | round() * 0.05) }}  
      Median: {{ '%.2f' |
      format((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0',
           'mean')|float / 0.05) | round() * 0.05) }}  
      Max: {{ '%.2f' | format((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0',
           'max')|float / 0.05) | round() * 0.05) }}  
      Min: {{ '%.2f' | format((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0',
           'min')|float / 0.05) | round() * 0.05) }}
       
      {% if (now().strftime('%T')) > '13:01:00'  %}

      Tomorrow:

      Average: {{state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 

      'tomorrow')|average|round(1)}}

      Min: {{state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 

      'tomorrow')|min|round(1)}}

      Max: {{state_attr('sensor.nordpool_kwh_ee_eur_3_10_0',

      'tomorrow')|max|round(1)}}


      {%- else %}

      Electricity prices for tomorrow are not available until 13:00.

      {% endif -%}

1 Like

Did you have any luck solving it? I’m trying to solve the same problem, but really stuck.

Now I want to find a way how to calculate the money i have earned from selling the energy to grid (Nordpool without VAT) and how much i have saved using the solar energy (nordpool with VAT + tariffs). Probably something similar to the Energy Dashboard logic.

So what i have:

Prices.

  1. Nordpool hourly price (current price) excluding VAT: sensor.nordpool_kwh_ee_eur_3_10_0
  2. Nordpool hourly price (current price) including VAT: sensor.nordpool_kwh_ee_eur_3_05_02
  3. Network fee, or Tariff: sensor.el_tariff
    *Actually i have the sensor.total_el_price, which sums the 1. and 3. and which i’m using in Energy Dashboard

Returned electricity to the grid

  1. Phase 1: sensor.phase_1_energy_returned
  2. Phase 2: sensor.phase_2_energy_returned
  3. Phase 3: sensor.phase_3_energy_returned

PV production:
Only one sensor that sums the three Phases: sensor.inverter_total_yield. Usually it produces equal amount on all three phases.

I have managed to make template sensors to calculate “sold to grid” and “used by myself” energy:

  - platform: template
    sensors:
      sold_to_grid_energy:
        friendly_name: "Sold to Grid energy"
        unit_of_measurement: "kWh"
        value_template: >-
          {{ (states('sensor.phase_1_energy_returned') | float + 
               states('sensor.phase_2_energy_returned') | float + 
               states('sensor.phase_3_energy_returned') | float) }}
  - platform: template
    sensors:
      used_self_pv_energy:
        friendly_name: "Used Self PV Energy"
        unit_of_measurement: "kWh"
        value_template: >-
          {% set pv_production = states('sensor.inverter_total_yield') | float %}
          {% set energy_returned = states('sensor.phase_1_energy_returned') | float + 
                                   states('sensor.phase_2_energy_returned') | float + 
                                   states('sensor.phase_3_energy_returned') | float %}
          {% set used_self_pv = pv_production - energy_returned %}
          {{ used_self_pv }}

Now next step would be to calculate the costs based on usage during specific hours and then cumulatively. This actually excaclty what Energy Dashboard is doing, and actually I have at least the energy sold numbers from there, but not used PV energy numbers and because of that i would like to replicate it outside of Energy Dashboard. Seems like a simple task as it has been already done in Energy Dasboard, but i’m out of ideas how to move on.


Would be extremely nice if Energy Dashboard could calculate this out of the box.

In the end I would like to see:

  1. Daily PV energy sold - kwh and €
  2. Daily PV energy self used - kwh and €
  3. Daily total PV earning - kwh and €
  4. Monhtly PV energy sold - kwh and €
  5. Monhtly PV energy self used - kwh and €
  6. Monthly total PV earning - kwh and €
  7. Yearly PV energy sold - kwh and €
  8. Yearly PV energy self used - kwh and €
  9. Yearly total PV earning - kwh and €
  10. All Time PV energy sold - kwh and €
  11. All Time PV energy self used - kwh and €
  12. All Time total PV earning - kwh and €

Hello arva

so i tried your method but got stuck here

Missing:‘input_number.cheapest_hours_needed’

and the bar of where it says the cheapest 4 hours start

is empty. i only changed the lines with updated version
nordpool_kwh_nl_eur_3_10_021.

type: vertical-stack
cards:

  • type: markdown
    alignment: justify
    content: >-
    {% set min_price = state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’,
    ‘min’) | float %} {% set max_price =
    state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’, ‘max’) | float %} {% set
    current_price = state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’,
    ‘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_kwh_nl_eur_3_10_021’,
    ‘today’)[00:23] %} {% set dateList =
    state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’, ‘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.cheapest_hours_needed

  • 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_kwh_nl_eur_3_10_021’ %} {% 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_kwh_nl_eur_3_10_021’,
    ‘current_price’)|float / 0.05) | round() * 0.05) }}
    Average: {{ ‘%.2f’ |
    format((state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’,
    ‘average’)|float / 0.05) | round() * 0.05) }}
    Median: {{ ‘%.2f’ |
    format((state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’,
    ‘mean’)|float / 0.05) | round() * 0.05) }}
    Max: {{ ‘%.2f’ | format((state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’,
    ‘max’)|float / 0.05) | round() * 0.05) }}
    Min: {{ ‘%.2f’ | format((state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’,
    ‘min’)|float / 0.05) | round() * 0.05) }}

    {% if (now().strftime(‘%T’)) > ‘13:01:00’ %}

    Tomorrow:

    Average: {{state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’,

    ‘tomorrow’)|average|round(1)}}

    Min: {{state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’,

    ‘tomorrow’)|min|round(1)}}

    Max: {{state_attr(‘sensor.nordpool_kwh_nl_eur_3_10_021’,

    ‘tomorrow’)|max|round(1)}}

    {%- else %}

    Electricity prices for tomorrow are not available until 13:00.

    {% endif -%}

You have to make one input number helper where you can choose how many hours you need. helper

The preferred way to configure an input number is via the user interface at Settings > Devices & Services > Helpers . Click the add button and then choose the Number option.

OK i am sorry i am kinda new to this and still learning
this is what i got do you have an example what to put there


1 Like

Thank you very much

1 Like

Hi arva, any luck in getting this to work? Looking for exactly the same thing with one addition. I also want a ticker showing total earning (self used Solar + sold Solar) deducted from the total investment of the solar plant.