Tibber sensor for future price (tomorrow)

No, not sure about this. HA is not good at visualizing data for future…

I did this for displaying some information in the GUI:
NorpolBadge

Badge code:

    badges:
      - entity: binary_sensor.nordpool_kwh_cheapest_4_hours
        card_mod: null
        style: |
          @keyframes pulse { 70% { opacity: 0; } }
          :host {
            --card-mod-icon-color: yellow;
            animation: pulse 3s infinite;
            display: 
              {% if is_state('binary_sensor.nordpool_kwh_cheapest_4_hours', 'off')  %}
                none;
              {% endif %}
          }

Sensor code:

 - platform: template
    sensors:
      nordpool_kwh_cheapest_4_hours:
        friendly_name: Strømpris
        icon_template: >- 
          mdi:lightning-bolt
        value_template: >-
          {% set l=state_attr('sensor.nordpool_kwh_oslo', 'raw_today')|sort(attribute='value') %}
          {{ (now() >= l[0].start and now() <= l[0].end)
            or (now() >= l[1].start and now() <= l[1].end)
            or (now() >= l[2].start and now() <= l[2].end)
            or (now() >= l[3].start and now() <= l[3].end) }}
        attribute_templates:
          cost1: >-
            {% set l=state_attr('sensor.nordpool_kwh_oslo', 'raw_today')|sort(attribute='value') %}
            {{l[0].value}} / {{l[0].start.strftime("%H:%M")}} - {{ l[0].end.strftime("%H:%M")}}
          cost2: >-
            {% set l=state_attr('sensor.nordpool_kwh_oslo', 'raw_today')|sort(attribute='value') %}
            {{l[1].value}} / {{l[1].start.strftime("%H:%M")}} - {{ l[1].end.strftime("%H:%M")}}
          cost3: >-
            {% set l=state_attr('sensor.nordpool_kwh_oslo', 'raw_today')|sort(attribute='value') %}
            {{l[2].value}} / {{l[2].start.strftime("%H:%M")}} - {{ l[2].end.strftime("%H:%M")}}
          cost4: >-
            {% set l=state_attr('sensor.nordpool_kwh_oslo', 'raw_today')|sort(attribute='value') %}
            {{l[3].value}} / {{l[3].start.strftime("%H:%M")}} - {{ l[3].end.strftime("%H:%M")}}

The sensor status for displaying in the GUI is “on” (not “off”, - but had to get it to show in the GUI for gif making)

1 Like

If anybody is interested in native HA solution using rest api, tibber sensor and apex charts, below is the code:

REST Sensor:
You need to replace [YOUR AUTH CODE FROM TIBBER DEVELOPER PROFILE] with your access token from tibber dev profile

- platform: rest
  name: Tibber prices
  resource: https://api.tibber.com/v1-beta/gql
  method: POST
  scan_interval: 60
  payload: '{ "query": "{ viewer { homes { currentSubscription { priceInfo { today { total startsAt } tomorrow { total startsAt }}}}}}" }'
  json_attributes_path: "$.data.viewer.homes[0].currentSubscription.priceInfo"
  json_attributes:
    - today
    - tomorrow
  value_template: Ok
  headers:
    Authorization: "**[YOUR AUTH CODE FROM TIBBER DEVELOPER PROFILE]**"
    Content-Type: application/json
    User-Agent: REST

Apex charts YAML

type: custom:apexcharts-card
apex_config:
  chart:
    height: 500px
header:
  show: true
  title: Energy stats
  show_states: true
  colorize_states: true
now:
  show: true
  color: white
  label: NOW
hours_12: false
graph_span: 36h
span:
  start: day
yaxis:
  - id: kWh
    decimals: 0
    opposite: true
    max: 500
    apex_config:
      tickAmount: 4
  - id: EUR
series:
  - entity: sensor.**[YOUR TIBBER ENERGY USAGE SENSOR]**
    type: column
    show:
      extremas: true
    name: Usage
    stroke_width: 2
    color: '#64511c'
    opacity: 0.3
    yaxis_id: kWh
    group_by:
      func: avg
      duration: 15min
  - entity: sensor.tibber_prices
    stroke_width: 2
    color: blue
    curve: smooth
    show:
      legend_value: false
      extremas: true
      in_header: false
    extend_to: now
    yaxis_id: EUR
    name: Predicted all
    data_generator: |
      return entity.attributes.today.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      });
      return entity.attributes.tomorrow.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      });
  - entity: sensor.**[YOUR TIBBER PRICE SENSOR]**
    extend_to: now
    show:
      extremas: true
    color: pink
    stroke_width: 5
    yaxis_id: EUR
    name: price
  - entity: sensor.**[YOUR TIBBER PRICE SENSOR]**
    stroke_width: 2
    show:
      legend_value: false
      extremas: true
    curve: smooth
    attribute: min_price
    name: MIN
    color: green
    yaxis_id: EUR
    type: line
    group_by:
      duration: 24hours
      func: min
  - entity: sensor.**[YOUR TIBBER PRICE SENSOR]**
    stroke_width: 2
    yaxis_id: EUR
    name: AVG
    attribute: avg_price
    color: violet
    curve: smooth
    type: line
    show:
      legend_value: false
      extremas: true
    group_by:
      duration: 24hours
      func: avg
  - entity: sensor.**[YOUR TIBBER PRICE SENSOR]**
    attribute: max_price
    stroke_width: 2
    curve: smooth
    show:
      legend_value: false
      extremas: true
    name: MAX
    color: red
    yaxis_id: EUR
    type: line
    group_by:
      duration: 24hours
      func: max

You need to replace following sensors above:

  • [YOUR TIBBER ENERGY USAGE SENSOR] - any sensor really showing your consumption
  • [YOUR TIBBER PRICE SENSOR] - regular tibber sensor giving you the price (with mix, max, avg attributes)
8 Likes

Nice work! But mine only shows past prices not up coming. Any idea why?

It’s javascript code in data_generator that has not reachable code in it. It returns before it hits tomorrow data.

Try this:

  data_generator: |
      var a = entity.attributes.today.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      }); 
      var b= entity.attributes.tomorrow.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      });
      return a.concat(b);
1 Like

I like this solution. How would one make a similar entity that gives the average price and/or Future_Price_Level for the following hour, 3 hours, and 6 hours?
Price_Level is a Tibber value based on the trailing price average over the past 3 days but Future_Price_level should be the time price average of the time period (next 1, 3, or 6 hours) in comparison with the current day’s price (or following 24-hour average price if after 14:00).

The hope with this is to be able to make more intelligent heating automation that will produce heat based on the future price rather than relying only on the current price and Tibber’s Price_Level.

Cool!!!
This rest sensor worked as a charm.
Thank you very much for sharing.

I’m also interested on future price statistics to schedule my dishwasher, so I will invest some time on this and will share here when I get something.

1 Like

This is working very well!
Thanks for sharing!

If you use Node-Red I can also suggest looking at this: https://powersaver.no/

I have recently started using this for my floor thermostats and waterheater and I can confirm it works very well. This can use data from Nordpool and Tibber. Just a suggestion :slight_smile:

Also on the future pricing of power I have installed apexcharts from HACS (https://github.com/RomRider/apexcharts-card) and use this config to get the pricing for today and tomorrow:

type: custom:apexcharts-card
graph_span: 24h
experimental:
  color_threshold: true
header:
  title: Powerprice
  show: true
apex_config:
  yaxis:
    min: 0
hours_12: false
span:
  start: hour
  offset: '-3h'
now:
  show: true
  label: Now
series:
  - entity: sensor.nordpool_kwh_oslo_nok_2_10_025
    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: 0
        color: var(--warning-color)
      - value: 1
        color: var(--warning-color)
      - value: 3
        color: var(--success-color)
      - value: 5
        color: var(--warning-color)

When the powerprice for tomorrow is not published the graphs are just empty (like in the image above). At around 13:00 the prices gets updated and will be added to the graph. I now prefer this over Tibbers own graph as its easier to compare the price from one day to another.

2 Likes

I had the same issue as @WattageGuy (here) and used the code that @KalleL suggested (here), that solved the issue with missing future price graph.

I also found out that MIN, AVG and MAX price calculation didn’t work correctly, it didn’t calculated on future prices. To fix that I used the REST sensor and the data_generator that @KalleL came up with. With that you get correctly calculated values for Min, Avg, and Max prices.

My chart:

Thank you @p1ranha for this chart, it’s very useful these days!
Thank you @KalleL for fixing data generator!

My final code:

type: custom:apexcharts-card
apex_config:
  chart:
    height: 600px
header:
  show: true
  title: Tibber El-pris
  show_states: true
  colorize_states: true
now:
  show: true
  color: white
  label: NU
hours_12: false
graph_span: 36h
span:
  start: day
yaxis:
  - id: kW
    decimals: 1
    opposite: true
    apex_config:
      tickAmount: 6
  - id: EUR
series:
  - entity: sensor.total_anvand_effekt_nu
    show:
      legend_value: false
      extremas: true
    stroke_width: 5
    curve: smooth
    color: '#64511c'
    opacity: 0.8
    yaxis_id: kW
    extend_to: now
    type: column
    group_by:
      func: avg
      duration: 30min
  - entity: sensor.tibber_prices
    stroke_width: 2
    color: blue
    curve: stepline
    show:
      legend_value: false
      extremas: true
      in_header: false
    extend_to: now
    yaxis_id: EUR
    name: Elpriset
    data_generator: |
      var a = entity.attributes.today.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      }); 
      var b= entity.attributes.tomorrow.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      });
      return a.concat(b);
  - entity: sensor.electricity_price_xxxxxxxx
    extend_to: now
    show:
      legend_value: false
      extremas: true
    curve: stepline
    color: '#ffa500'
    stroke_width: 5
    yaxis_id: EUR
    name: Pris nu
  - entity: sensor.tibber_prices
    stroke_width: 2
    show:
      legend_value: false
      extremas: true
    data_generator: |
      var a = entity.attributes.today.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      }); 
      var b= entity.attributes.tomorrow.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      });
      return a.concat(b);
    curve: smooth
    attribute: min_price
    name: Minsta pris
    color: green
    yaxis_id: EUR
    type: line
    group_by:
      duration: 36h
      func: min
  - entity: sensor.tibber_prices
    stroke_width: 2
    show:
      legend_value: false
      extremas: true
    data_generator: |
      var a = entity.attributes.today.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      }); 
      var b= entity.attributes.tomorrow.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      });
      return a.concat(b);
    curve: smooth
    attribute: avg_price
    name: Medel pris
    color: violet
    yaxis_id: EUR
    type: line
    group_by:
      duration: 36h
      func: avg
  - entity: sensor.tibber_prices
    stroke_width: 2
    show:
      legend_value: false
      extremas: true
    data_generator: |
      var a = entity.attributes.today.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      }); 
      var b= entity.attributes.tomorrow.map((entry) => {
        return [new Date(entry.startsAt), entry.total];
      });
      return a.concat(b);
    curve: smooth
    attribute: max_price
    name: Max pris
    color: red
    yaxis_id: EUR
    type: line
    group_by:
      duration: 36h
      func: max

6 Likes

That power saver node red node looks like a great idea but I would really like to try to get HA to be able to do this by creating an entity that gives the price level over the next 1-3 hours using the tibber price_level.

One could use this to set a NOT condition to prevent changing a control if the price will be lower during the chosen period. Or use it to change a control now if the price will rise after x hours.

Wow. This works great.
How can I set current price to header? It shows now last price of the series.

See the picture:
image

So, I’ve finally started working on this, but I’ve started a new topic to avoid confusion:

Tibber future (tomorrow) prices statistics - Share your Projects! - Home Assistant Community (home-assistant.io)

Hello, nice work. Thanks for the code.
I tried to build it for my setting. How do you make that the blue line is not visible on the left side of “now”?
My goal is to have the past line ending at “now” and the forecast line start at “now” . Do you know if this is possible? And how?
Thanks in advance.

Just tried your rest sensor out but it conflicts with the normal Tibber integration at start up and results in my HA takes 10min or so to fully load but the Tibber integration fails to initialize which leads to the Energy dashboard not working etc.

Do you have any idea what might be causing it?

Hi, they really don’t have anything in common, so the only thing I would suggest is to reduce refresh rate and see if next day it improves:

In the rest sensor change this:
scan_interval: 60

to maybe
scan_interval: 3600

which will make 1 query every 1 hour.

1 Like

Just tried that and it worked, one reboot but that’s 100% better than before :slight_smile:

I’ve stopped using the “normal Tibber integration”, not because I have a conflict, but because that is not needed after a couple of modifications on @p1ranha’s REST sensor in order to add the current price on its state (instead of an “OK”):

sensor:
    # https://community.home-assistant.io/t/tibber-sensor-for-future-price-tomorrow/253818/23
    - platform: rest
      name: Tibber Electricity Price
      resource: https://api.tibber.com/v1-beta/gql
      method: POST
      scan_interval: 900
      payload: '{ "query": "{ viewer { homes { currentSubscription { priceInfo { current { total currency level } today { total startsAt level } tomorrow { total startsAt level }}}}}}" }'
      json_attributes_path: "$.data.viewer.homes[0].currentSubscription.priceInfo"
      json_attributes:
        - current
        - today
        - tomorrow
      value_template: '{{ value_json["data"]["viewer"]["homes"][0]["currentSubscription"]["priceInfo"]["current"]["total"] }}'
      headers:
        Authorization: !secret tibber_api_token
        Content-Type: application/json
        User-Agent: REST

This doesn’t have the consumption statistics as the “official” integration and also doesn’t have the price level (for witch I have a template sensor to calculate, but also would be easy to add in this sensor if you don’t wanna have another sensor).

PS: Note I’m using 900 sec (15min) as scan interval, which is working fine for me and prevents taking too long to fetching for the new price when a new hour starts (this could be easily solved by a template sensor).

This is the other template sensor I’ve mentioned. It probably needs a review/clean up as I’m sure I’m not using half of those attributes available.
The result of this sensor is what I use for my energy dashboard, as if updates the current rate faster than the REST sensor (thanks to the longer scan interval I’ve used there):

template:
  - sensor:
    - name: Electricity price
      unique_id: d4c04abf-c258-4f0f-a61d-cc0170225081
      unit_of_measurement: "SEK/kWh"
      icon: mdi:currency-usd
      state: >-
        {% if this.attributes.future_prices | default('unknown') in ['unknown', 'unavailable'] or (this.attributes.future_prices | default([]) | map(attribute='total') | list | count) < 1 %}
          unknown
        {% else %}
          {{ this.attributes.future_prices |  default([]) | map(attribute='total') | list | first | float(0) }}
        {% endif %}
      attributes:
        current: >-
          {% if state_attr('sensor.tibber_electricity_price', 'current') %}
            {{ state_attr('sensor.tibber_electricity_price', 'current') }}
          {% else %}
            [ ]
          {% endif %}
        today: >-
          {% if state_attr('sensor.tibber_electricity_price', 'today') %}
            {{ state_attr('sensor.tibber_electricity_price', 'today') }}
          {% else %}
            [ ]
          {% endif %}
        tomorrow: >-
          {% if state_attr('sensor.tibber_electricity_price', 'tomorrow') %}
            {{ state_attr('sensor.tibber_electricity_price', 'tomorrow') }}
          {% else %}
            [ ]
          {% endif %}
        all_prices: "{{ this.attributes.today | default([]) + this.attributes.tomorrow | default([]) }}"
        #today_count: "{{ this.attributes.today | default([]) | map(attribute='total') | list | count }}"
        #tomorrow_count: "{{ this.attributes.tomorrow | default([]) | map(attribute='total') | list | count }}"
        #all_prices_count: "{{ this.attributes.all_prices | default([]) | map(attribute='total') | list | count }}"
        min_price: >-
          {% if this.attributes.today | default('unknown') in ['unknown','unavailable','none'] or (this.attributes.today | default([]) | map(attribute='total') | list | count) < 1 %}
            unknown
          {% else %}
            {{ this.attributes.today | default([0]) | map(attribute='total') | list | min | float(0) | round(4) }}
          {% endif %}
        max_price: >-
          {% if this.attributes.today | default('unknown') in ['unknown','unavailable','none'] or (this.attributes.today | default([]) | map(attribute='total') | list | count) < 1 %}
            unknown
          {% else %}
            {{ this.attributes.today | default([0]) | map(attribute='total') | list | max | float(0) | round(4) }}
          {% endif %}
        avg_price: >-
          {% if this.attributes.today | default('unknown') in ['unknown','unavailable','none'] or (this.attributes.today | default([]) | map(attribute='total') | list | count) < 1 %}
            unknown
          {% elif (this.attributes.today | default([]) | map(attribute='total') | list | count) < 2 %}
            {{ this.attributes.today | default([0]) | map(attribute='total') | list | max | float(0) | round(4) }}
          {% else %}
            {{ this.attributes.today | default([0]) | map(attribute='total') | list | average(0) | float(0) | round(4) }}
          {% endif %}
        price_level: >-
          {% if (this.attributes.current | default('unknown')) in ['unknown','unavailable','none'] %}
            unknown
          {% else %}
            {{ this.attributes.current.level | default('unknown') | replace('_', ' ') | capitalize }}
          {% endif %}
        price_level_1d: >-
          {% set price_cur = this.state | default(0) | float(0) %}
          {% set price_avg = this.attributes.avg_price | default(0) | float(0) %}
          {% if price_cur == 0 or price_avg == 0 %}
            unknown
          {% else %}
            {% set price_ratio = (price_cur / price_avg) %}
            {% if price_ratio >= 1.4 %}
              Very expensive
            {% elif price_ratio >= 1.15 %}
              Expensive
            {% elif price_ratio <= 0.6 %}
              Very cheap
            {% elif price_ratio <= 0.9 %}
              Cheap
            {% else %}
              Normal
            {% endif %}
          {% endif %}
        price_level_combined: >-
          {% set level1 = this.attributes.price_level_1d | default('unknown') %}
          {% set level3 = this.attributes.price_level | default('unknown') %}
          {% if level1 == level3 %}
            {{ level1 }}
          {% elif level1 in ['unknown','unavailable','none'] or level3 in ['unknown','unavailable','none'] %}
            unknown
          {% elif level1 == "Very cheap" %}
            {{ level3 }}
          {% elif level3 == "Very cheap" %}
            {{ level1 }}
          {% elif level1 == "Cheap" %}
            {{ level3 }}
          {% elif level3 == "Cheap" %}
            {{ level1 }}
          {% elif level1 == "Normal" %}
            {{ level3 }}
          {% elif level3 == "Normal" %}
            {{ level1 }}
          {% elif level1 == "Expensive" %}
            {{ level3 }}
          {% else %}
            {{ level1 }}
          {% endif %}
        is_below_average: >-
          {% if is_number(this.state) and is_number(this.attributes.avg_price) %}
            {{ (this.state | float(0) < this.attributes.avg_price | float(0)) | lower }}
          {% else %}
            unknown
          {% endif %}
        is_above_average: >-
          {% if is_number(this.state) and is_number(this.attributes.avg_price) %}
            {{ (this.state | float(0) > this.attributes.avg_price | float(0)) | lower}}
          {% else %}
            unknown
          {% endif %}
        is_at_min: >-
          {% if is_number(this.state) and is_number(this.attributes.min_price) %}
            {{ (this.state | float(0) <= this.attributes.min_price | float(0)) | lower }}
          {% else %}
            unknown
          {% endif %}
        is_at_max: >-
          {% if is_number(this.state) and is_number(this.attributes.max_price) %}
            {{ (this.state | float(0) >= this.attributes.max_price | float(0)) | lower }}
          {% else %}
            unknown
          {% endif %}
        is_close_to_min: >-
          {% if is_number(this.state) and is_number(this.attributes.min_price) %}
            {{ (this.state | float(0) <= (1.15 * this.attributes.min_price | float(0))) | lower }}
          {% else %}
            unknown
          {% endif %}
        future_prices: >-
          {% if (this.attributes.all_prices | default('unknown')) in ['unknown','unavailable','none'] %}
            unknown
          {% else %}
            {{ (this.attributes.all_prices | default([])) | selectattr('startsAt', 'gt', (now() - timedelta(hours=1)) | string | replace(' ','T')) | list }}
          {% endif %}
        future_prices_totals: >-
          {% if (this.attributes.future_prices | default('unknown')) in ['unknown','unavailable','none'] %}
            unknown
          {% else %}
            {{ (this.attributes.future_prices | default([])) | map(attribute='total') | list }}
          {% endif %}
        #future_prices_count: "{{ (this.attributes.future_prices_totals | default([])) | count }}"
        future_prices_min: |-
          {% if this.attributes.future_prices_totals | default([0]) | count > 0 %}
            {{  this.attributes.future_prices_totals | default([0]) | min | float(0) | round(4) }}
          {% else %}
            unknown
          {% endif %}
        future_prices_max: |-
          {% if this.attributes.future_prices_totals | default([0]) | count > 0 %}
            {{ (this.attributes.future_prices_totals | default([0])) | max | float(0) | round(4) }}
          {% else %}
            unknown
          {% endif %}
        future_prices_avg: >-
          {% if this.attributes.future_prices_totals | default([0]) | count > 0 %}
            {{ (this.attributes.future_prices_totals | default([0])) | average(0) | float(0) | round(4) }}
          {% else %}
            unknown
          {% endif %}
        future_prices_curr_price_level: >-
          {% set price_cur = this.state | default(0) | float(0) %}
          {% set price_avg = this.attributes.future_prices_avg | default(0) | float(0) %}
          {% if price_cur == 0 or price_avg == 0 %}
            unknown
          {% else %}
            {% set price_ratio = (price_cur / price_avg) %}
            {% if price_ratio >= 1.4 %}
              Very expensive
            {% elif price_ratio >= 1.15 %}
              Expensive
            {% elif price_ratio <= 0.6 %}
              Very cheap
            {% elif price_ratio <= 0.9 %}
              Cheap
            {% else %}
              Normal
            {% endif %}
          {% endif %}
        future_prices_16h: >-
          {% if (this.attributes.future_prices | default('unknown')) in ['unknown','unavailable','none'] %}
            unknown
          {% else %}
            {{ (this.attributes.future_prices | default([]) | list)[0:16]}}
          {% endif %}
        future_prices_16h_totals: >-
          {% if (this.attributes.future_prices_16h | default('unknown')) in ['unknown','unavailable','none'] %}
            unknown
          {% else %}
            {{ (this.attributes.future_prices_16h | default([])) | map(attribute='total') | list }}
          {% endif %}
        #future_prices_16h_count: "{{ (this.attributes.future_prices_16h_totals | default([])) | count }}"
        future_prices_16h_min: |-
          {% if this.attributes.future_prices_16h_totals | default([0]) | count > 0 %}
            {{ (this.attributes.future_prices_16h_totals | default([0])) | min | float(0) | round(4) }}
          {% else %}
            unknown
          {% endif %}
        future_prices_16h_max: |-
          {% if this.attributes.future_prices_16h_totals | default([0]) | count > 0 %}
            {{ (this.attributes.future_prices_16h_totals | default([0])) | max | float(0) | round(4) }}
          {% else %}
            unknown
          {% endif %}
        future_prices_16h_avg: >-
          {% if this.attributes.future_prices_16h_totals | default([0]) | count > 0 %}
            {{ (this.attributes.future_prices_16h_totals | default([0])) | average(0) | float(0) | round(4) }}
          {% else %}
            unknown
          {% endif %}
        future_prices_16h_current_price_level: >-
          {% set price_cur = this.state | default(0) | float(0) %}
          {% set price_avg = this.attributes.future_prices_16h_avg | default(0) | float(0) %}
          {% if price_cur == 0 or price_avg == 0 %}
            unknown
          {% else %}
            {% set price_ratio = (price_cur / price_avg) %}
            {% if price_ratio >= 1.4 %}
              Very expensive
            {% elif price_ratio >= 1.15 %}
              Expensive
            {% elif price_ratio <= 0.6 %}
              Very cheap
            {% elif price_ratio <= 0.9 %}
              Cheap
            {% else %}
              Normal
            {% endif %}
          {% endif %}
        future_prices_16h_current_price_is_close_to_min: >-
          {% if is_number(this.state) and is_number(this.attributes.future_prices_16h_min) %}
            {{ (this.state | float(0) <= (1.15 * this.attributes.future_prices_16h_min | default(0) | float(0))) | lower }}
          {% else %}
            unknown
          {% endif %}
        future_prices_16h_current_price_is_at_min: >-
          {% if this.state | default(0) | float(0) > 0 and this.attributes.future_prices_16h_min | default(0) | float(0) > 0 %}
            {{ (this.state | default(0) | float(0) <= this.attributes.future_prices_16h_min | default(0) | float(0)) | lower }}
          {% else %}
            unknown
          {% endif %}
3 Likes

What is the sensor : sensor.electricity_price_xxxxxxxx ??