Tibber - Schedul prices upcoming 24 hours prices!

Hello Ingo and all the other
In the view “Tibber Einstellungen” from Ingo are some sensor with the unit “W”:

  • Überschuss
  • Laden wenn Überschuss kleiner als

I did not find it in any automation. And I ask myself, is it good to charge the battery with this fine level? The automation can say allways on and off…

Or what is the reason for this sensor?

Very nice card, only using prices for now, but surely will update to the full shananigan

image

Thx @ingo.niehues !

Hi guys, i’ve been using the Tibber nodes for quite some time but now i would like to schedule the runinng of my vacuum, based on the lowest prices of the day. Is there a way to start the cycle 1 hor before the lowest hour, so that after the cycle of vacuuming, the robot gets charged within the cheapest timeframe??

Tibber Price Preview Sensor and Card (Update)

My Sensor stopped working a few days ago, so i decided to spend some time to fix it today. Luckily i was able to do it.

Here is the updated code for the multiscrape-sensor:

multiscrape:
  - name: HA scraper
    resource: https://tibber.com/de/strompreisentwicklung
    scan_interval: 3600
    sensor:
      - unique_id: tibber_strompreisentwicklung_website_text
        name: tibber_strompreisentwicklung_website_text
        select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.no-padding > div > div > div > div > div > div > div > h2 > span"
        attributes:
          - name: tibber_price_preview_full_text
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.Blocks.py-xl > div > div"
          - name: tibber_price_preview_week_number
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.no-padding > div > div > div > div > div > div > div > h2 > span"
          - name: tibber_price_preview_week_short_state
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.no-padding > div > div > div > div > div > p"
          - name: tibber_price_preview_header_country
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.Blocks.py-xl > div > div > div > h2 > div > h2 > span"
          - name: tibber_price_preview_text_prices
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.Blocks.py-xl > div > div > div > p:nth-child(2)"
          - name: tibber_price_preview_text_background_1
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.Blocks.py-xl > div > div > div > p:nth-child(3)"
          - name: tibber_price_preview_text_background_2
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.Blocks.py-xl > div > div > div > p:nth-child(4)"
          - name: tibber_price_preview_text_background_3
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.Blocks.py-xl > div > div > div > p:nth-child(5)"
          - name: tibber_price_preview_text_background_4
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.Blocks.py-xl > div > div > div > p:nth-child(6)"
          - name: tibber_price_preview_text_summary
            select: "#app-root > div.jsx-850a60188453b536.app-container > div > section > div > div:nth-child(3) > div > div > div > div.Blocks.py-xl > div > div > div > p:nth-child(7)"

… and the updated code for the card:

type: markdown
content: >-
  ## {{
  state_attr("sensor.tibber_strompreisentwicklung_website_text","tibber_price_preview_header_country")
  }}

  ### {{
  state_attr("sensor.tibber_strompreisentwicklung_website_text","tibber_price_preview_text_prices")
  }}

  ### {{
  state_attr("sensor.tibber_strompreisentwicklung_website_text","tibber_price_preview_text_background_1")
  }}


  {{
  state_attr("sensor.tibber_strompreisentwicklung_website_text","tibber_price_preview_text_background_2")
  }}


  {{
  state_attr("sensor.tibber_strompreisentwicklung_website_text","tibber_price_preview_text_background_3")
  }}


  {{
  state_attr("sensor.tibber_strompreisentwicklung_website_text","tibber_price_preview_text_background_4")
  }}      


  ## {{
  state_attr("sensor.tibber_strompreisentwicklung_website_text","tibber_price_preview_text_summary")
  }}



  Quelle:
  [**https://tibber.com/de/strompreisentwicklung**](https://tibber.com/de/strompreisentwicklung)
2 Likes

Yes, i switched to tibber completly since 01/2024 and i´m totally happy with it.

This is what my dashboards for that now look like:


2 Likes

Yery nice!

Possible to share dashboard code? :wink:

Thank you for the update

Sure, no Problem.

i use the following sensors for these dashboards:
Tibber-Rest-API-Sensors
Tibber-Template-Sensors (via Configuration.yaml)
Tibber-Template-Sensors (via UI)

image
Column 1
Column 2
Column 3

image
Column 1
Column 2
Column 3

If there´s a missing sensor, please tell me. That are a lot of sensors on this two views :slight_smile:

6 Likes

Hi,

I wanted to ask what logic you use to charge your battery when the solar forecast is bad and the price range at Tibber is high?

…in order to then charge the battery at a certain speed at the most favorable time.

I´ve created a template-switch with the following code to tell my system if it should charge from grid or not:

{% set min_price = state_attr("sensor.electricity_price_wester_esch_26b","min_price") | float(default=0) %}
{% set max_price = state_attr("sensor.electricity_price_wester_esch_26b","max_price") | float(default=0) %}
{% set price = states("sensor.electricity_price_wester_esch_26b") | float(default=0) %}
{% set price_range = max_price - min_price %}
{% set price_above_min = price - min_price %}
{% set price_below_max = max_price - price %}
{% set price_level = (price_above_min / price_range) * 100 %}
{% set price_difference_to_max = (price_below_max / price_range) * 100 %}
{% set price_min_tomorrow = (states("sensor.template_tibber_price_min_tomorrow") | float(default=0.3) * 1.2) | float(default=0) %}

{% set house_power = states("sensor.senec_house_power") | int(default=0) %}
{% set solar_power = states("sensor.senec_solar_generated_power") | int(default=0) %}

{% set solar_energy_expected = states("sensor.solar_restproduktion_heute") | float(default=0) %}
{% set charge_from_grid_below_expected_energy = states("input_number.laden_bei_restproduktion_unter") | float(default=0) %}

{% if solar_power < house_power and price_difference_to_max > 50 and solar_energy_expected < charge_from_grid_below_expected_energy and price < price_min_tomorrow %}
  true
{% else %}
  false
{% endif %}

The logic behind this is:

IF i get less power from solar then my house uses (so no energy would be fed into battery)
AND on a scale from min_today_price to max_to_price the current price is more then 50% away from the max_price
AND the expected solar energy for today is below an input_number-value (for me: 15 kWh)
AND the current price is lower then the lowest price tomorrow

With an automation i control my “load from grid”-switch for my battery. Sadly i have no option to control the speed that the battery charges with.

1 Like

Mh…wasn´t happy with the sensor. Did some changes. Here is the updated code (i will have to see, if that works better for me)

{% set min_price = state_attr("sensor.electricity_price_wester_esch_26b","min_price") | float(default=0) %}
{% set max_price = state_attr("sensor.electricity_price_wester_esch_26b","max_price") | float(default=0) %}
{% set price = states("sensor.electricity_price_wester_esch_26b") | float(default=0) %}
{% set price_range = max_price - min_price %}
{% set price_above_min = price - min_price %}
{% set price_below_max = max_price - price %}
{% set price_level = (price_above_min / price_range) * 100 %}
{% set price_difference_to_max = (price_below_max / price_range) * 100 %}
{% set price_min_tomorrow = states("sensor.template_tibber_price_min_tomorrow") | float(default=0) + 0.05 %}

{% set house_power = states("sensor.senec_house_power") | int(default=0) %}
{% set solar_power = states("sensor.senec_solar_generated_power") | int(default=0) %}

{% set solar_energy_expected = states("sensor.solar_restproduktion_heute") | float(default=0) %}
{% set charge_from_grid_below_expected_energy = states("input_number.laden_bei_restproduktion_unter") | float(default=0) %}

{% set battery_state = states("sensor.senec_system_state") %}

{% if solar_power < house_power and price_difference_to_max > 50 and solar_energy_expected < charge_from_grid_below_expected_energy and price <= (min_price + 0.02) and price < price_min_tomorrow and battery_state != "AKKU VOLL" %}
  true
{% else %}
  false
{% endif %}
1 Like

Thank you for your feedback, that helps me a lot :slight_smile:

Because in my case I “work” with a small balcony power plant, I have to act a little differently :wink:

For this I would like to determine the number of hours in which the price is above a certain limit

But I’m not really making any progress with the code. Does anyone have an idea about this?

Well, I already have the max value…

{{ ((state_attr('sensor.tibber_prices', 'today') | map(attribute='total') | max | default(0.0)) * 100) | float | round(2) }}

EDIT1:
Ok, counting prices over x value in future time works: :slight_smile:

  {{ ((state_attr('sensor.tibber_prices', 'today') | selectattr('startsAt', 'ge', now().strftime('%Y-%m-%dT%H:00:00.000+02:00')) | selectattr('total', 'ge', 0.30) | map(attribute='total') | list | count )) }}
1 Like

Maybe this is the right thing for your needs => GitHub - TheFes/cheapest-energy-hours: Jinja macro to find the cheapest energy prices

After you´ve installed that via Hacs, you will need to setup a trigger-template-sensor like this

template:
  - trigger:
      - platform: time_pattern
        hours: "/1"
      - platform: homeassistant
        event: start
    action:
      - service: tibber.get_prices
        data:
          start: "{{ (today_at() - timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S') }}"
          end: "{{ (today_at() + timedelta(days=2)).strftime('%Y-%m-%d %H:%M:%S') }}"
        response_variable: prices
    sensor:
      - unique_id: tibber_cheap_energy_hours
        name: tibber_cheap_energy_hours
        state: "{{ prices.prices.values() | first | selectattr('start_time', '<=', now()) | map(attribute='price') | list | last }}"
        attributes:
          prices: >
            {% set ns = namespace(prices=[]) %}
            {% for i in prices.prices.values() | first %}
              {% set n = dict(start_time = i.start_time.isoformat(), price = i.price) %}
              {% set ns.prices = ns.prices + [n] %}
            {% endfor %}
            {{ ns.prices }}

and could then use the templates to get the best hours to charge from grid - for expample like this

{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours %}
{% set output = cheapest_energy_hours(sensor='sensor.tibber_cheap_energy_hours', hours=2.25, start='12:00', end=today_at('19:00') + timedelta(days=1), look_ahead=true) %}
{{ output }}

i haven´t really looked much into this, but it seems very useful.

2 Likes

Become an error in the template editor :frowning:

TypeError: '>' not supported between instances of 'str' and 'datetime.datetime'

I don´t get this error in my instance. Maybe you could take a look at Issues · TheFes/cheapest-energy-hours · GitHub ?

image

My solution seems to work fine for me. It charged my battery from 02:00 to 05:00 while the price was (relativly) cheap before the peak in the morning. :slight_smile:

2 Likes

Now it works with

  {% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours %}
  {% set output = cheapest_energy_hours (sensor='sensor.tibber_cheap_energy_hours', hours=2.25, start='12:00', end=today_at('19:00') + timedelta(days=1), look_ahead=true) %}
  {{ output }}

this result

2024-10-22T21:45:00+02:00

Looks good, can you share Apex-Code :wink:
image

Sure. Here it is :slight_smile:

type: custom:apexcharts-card
card_mod:
  style: |
    #state__value > #state {
      font-size: 1.2em !important;
    }
    .apexcharts-tooltip-series-group {
      padding-top: 0px !important;
      padding-bottom: 0px !important;
      margin-top: 0px !important;
      margin-bottom: 0px !important;
      display: none;
      text-align: left;
      justify-content: left;
      align-items: center;
    }
    #header {
        padding: 1rem !important;
    }  
experimental:
  color_threshold: true
apex_config:
  grid:
    show: true
    borderColor: "#E0E0E0"
  chart:
    height: 375px
    offsetY: 0
  legend:
    show: true
  tooltip:
    enabled: true
    followCursor: false
    x:
      show: true
    fixed:
      enabled: false
header:
  show: true
  show_states: true
  colorize_states: true
  standard_format: false
graph_span: 48h
now:
  show: true
  color: 9E9E9E
  label: jetzt
span:
  end: day
  offset: +12h
yaxis:
  - id: Preis
    apex_config:
      tickAmount: 10
      forceNiceScale: true
      decimalsInFloat: 0
  - id: Netzladen
    min: 0
    max: 100
    show: false
series:
  - entity: sensor.tibber_prices
    yaxis_id: Preis
    show:
      in_header: before_now
      name_in_header: true
      header_color_threshold: true
      legend_value: false
    name: Preis
    color_threshold:
      - value: 0
        color: lime
      - value: 15
        color: green
      - value: 20
        color: Khaki
      - value: 25
        color: Gold
      - value: 30
        color: darkorange
      - value: 35
        color: orangered
      - value: 40
        color: red
    type: line
    curve: stepline
    extend_to: false
    stroke_width: 2
    float_precision: 2
    data_generator: |
      const noon = new Date()
      noon.setHours(0, 0, 0, 0)
      const prices = entity.attributes.today.concat(entity.attributes.tomorrow);
      const data = [];
      for(let i = 0; i < prices.length; i++) {
        data.push([noon.getTime() + i * 1000 * 3600, prices[i].total * 100])
      }
      return data;
  - entity: sensor.tibber_prices
    transform: return x * 100
    name: Preis je kWh
    yaxis_id: Preis
    show:
      in_header: false
      name_in_header: false
      header_color_threshold: false
      legend_value: false
      in_legend: false
    color_threshold:
      - value: 0
        color: lime
      - value: 15
        color: green
      - value: 20
        color: Khaki
      - value: 25
        color: Gold
      - value: 30
        color: darkorange
      - value: 35
        color: orangered
      - value: 40
        color: red
    type: line
    curve: stepline
    extend_to: false
    stroke_width: 2
    float_precision: 2
  - entity: binary_sensor.akku_aus_dem_netz_laden
    color: var(--energy-grid-consumption-color)
    yaxis_id: Netzladen
    name: Netzladen
    transform: "return x === 'on' ? 100 : 0;"
    type: area
    curve: stepline
    stroke_width: 0
    opacity: 0.3
    extend_to: now
    show:
      in_header: false
      legend_value: false
  - entity: sensor.senec_battery_charge_percent
    color: teal
    name: Speicher
    yaxis_id: Netzladen
    type: area
    curve: stepline
    stroke_width: 1
    opacity: 0.1
    show:
      legend_value: false
    extend_to: now

1 Like

Thanks for the code :slight_smile:

I also built something similar :wink:
image

1 Like

Hi Ingo, wow that is perfect but one Question what cards you are using? It doesn’t look like that for me? everything is mixed up.