Tibber - Schedul prices upcoming 24 hours prices!

Hi,
I have given some thought to the battery charging script and
would like to put the following functions & code up for discussion…

  1. Alternative to input_number.tibber_cheap_energy_min_price_difference template sensor with the name sensor.strompreis_min_diff_ber
{{ (float(states('sensor.tibber_prices_complete_rest_min')) / 100 * ( 100 - float(states('input_number.bkw_bat_price_effi_limit'))) / 100 ) | round (4) }}

Takes the minimum electricity price sensor.tibber_prices_complete_rest_min
and calculates the minimum required difference from the charging efficiency input_number.bkw_bat_price_effi_limit.
The input_number.bkw_bat_price_effi_limit must be created as a helper.

  1. Calculate the currently available energy content of a battery in sensor.delta_2_max_energieinhalt_nutzbar_akt
{{ (float(states('input_number.delta_2_max_energieinhalt')) / 100 * (float(states('sensor.delta_2_max_battery_level')) - float(states('sensor.delta_2_max_min_discharge_level_offset')))) | round (3) }}
  1. Use your average power consumption and the previously calculated energy content to derive your maximum running time for a feed-in
{{ (float(states('sensor.delta_2_max_energieinhalt_nutzbar_akt')) / float(states('sensor.tibber_verbrauch_erzeugung_avg')) * 1000) | round (1) }}
  1. Dynamically calculate the maximum price at which feed-in can take place based on the available battery hours.
{% set x = float(states('sensor.delta_2_max_energieinhalt_nutzbar_max_stunden')) | round | int | default(0) %}
{{ ((state_attr('sensor.tibber_prices', 'today') | selectattr('startsAt', 'ge', now().strftime('%Y-%m-%dT%H')) | selectattr('total', 'ge',  float(states('input_number.strompreis_einspeisegrenze'))) | map(attribute='total') | list | sort (reverse=true)) [x]) * 100 }}

Maybe one of you has additional ideas about the functions… :wink:

@Neewieedo Hmm… this is very interesting and I am thinking about that, too. Maybe start a new thread for that?

Suggestions:
-make a prognosis on how much electricity you need (mean of last week’s consumption? or better last month?) for today and tomorrow
-add a switch to account for planned additional consumtion (e.g. running washing machine/dishwaher)
-keep track of cost of energy in battery (important if you charege from the grid! account for solar power with 8ct/kWh (if you are in Germany), do not forget to add 20% for charging/discharging losses
-get prognosis for PV production today&tomorrow; added to energy in battery that is energy to distribute
-with the prognosis for consumption and the “Standardlastprofil H0” calculate how much energy will be used for each hour of the day (array for today and tomorrow; containing hour, price, calculated consumption, planned production)
-sort this array by price, with the highest price first
-go through that array and check if price is > price of stored energy, if true set “planned production” to “calculated consumption”, and subtract “planned production” from “energy to distribute”
-repeat until “energy to distribute” is zero (i.e. battery empty)
→ This algorithm optimizes for money.
→ An alorithm for charging ftom the grid is needed, too. This requires a prognosis of the energy prices…

I think calculating the average for a week or month is too slow, because otherwise an absence (holiday) is included too late in the calculation. Perhaps you could also work with a switch for the absence :wink:

I think that’s getting too complicated at the moment…

I have not yet found a solution to dynamically calculate the current costs for the energy content of the battery.

Yes, there is already a solution for this:

{{ ((float(states('input_number.delta_2_max_energieinhalt')) * float(states('sensor.delta_2_max_max_charge_level_offset')) / 100) - float(states('sensor.delta_2_max_energieinhalt_akt')) - float(states('sensor.solarvorhersage_heute_rest_akt')) + float(states('sensor.delta_2_max_ladung_benotigt'))) | round (3) }}

Ok, now it gets challenging :wink:

Here, the feed-in limit is calculated based on the battery content, but the solar forecast is not yet taken into account here.

{% set x = float(states('sensor.delta_2_max_energieinhalt_nutzbar_max_stunden')) | round | int | default(0) %}
{% if x<0 %}{% set x=0 %}{%endif%}
{{ ((((state_attr('sensor.tibber_prices', 'today') | selectattr('startsAt', 'ge', now().strftime('%Y-%m-%dT%H')) | selectattr('total', 'ge',  0.0) | map(attribute='total') | list) +
(state_attr('sensor.tibber_prices', 'tomorrow') | selectattr('total', 'ge',  0.0) | map(attribute='total') | list)) | sort (reverse=true)) [x]) * 100 }}

So there is still a lot to do… :slight_smile:

Suggestions:
-make a prognosis on how much electricity you need (mean of last week’s consumption? or better last month?) for today and tomorrow
-add a switch to account for planned additional consumtion (e.g. running washing machine/dishwaher)

Ein neuer Thread wäre interessant. Ich arbeite an einigen der erwähnten Punkten und berechne z.B. meinen individuellen Tagesgrundverbrauch und gleiche es mit dem PV-Forecast ab, um eine Batterieladung zu steuern. Dabei beachte ich immer die Zeiten zw. 8:00 und 18:00 bzw. 18:00 und 8:00, um eine Batterieladung vor den Spitzenstunden zu steuern. Eine Berechnung der Kosten “sofort laden” oder “Netzbezug bis zur gewünschten Uhrzeit” ist damit auch möglich. Alles noch “work-in-progress”, aber vielleicht besser in einem neuem Thread.

image

Hier mal einer meiner Sensoren, der des Restverbrauch anhand von Wochentagen und 24h-Arrays mit den kWh-Verbräuchen ermöglicht, jeweils immer bis nächster Tag 8:00 (und als Attribut ‘tomorrow’ übernächster Tag bis 8:00).

(bin Amateur, habe es zusammen gegoogelt und ChatGPT arbeiten lassen.
Ggf. stelle ich mein ganzes Skript mal hier rein, muss aber erst etwas aufräumen)

template:
  - sensor:
      - name: batteryload_required_energy
        unique_id: batteryload_required_energy
        unit_of_measurement: "kWh"
        icon: mdi:home-lightning-bolt
        state: >-
            {% set werte_montag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_dienstag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_mittwoch = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_donnerstag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_freitag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_samstag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_sonntag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            
            {# Bestimme den aktuellen Wochentag: 0 = Montag, 6 = Sonntag #}
            {% set tag = now().weekday() %}
            {% set naechster_tag = (tag + 1) % 7 %}
            
            {# Wähle das richtige Array basierend auf dem Wochentag #}
            {% set werte_aktuell = {
              0: werte_montag,
              1: werte_dienstag,
              2: werte_mittwoch,
              3: werte_donnerstag,
              4: werte_freitag,
              5: werte_samstag,
              6: werte_sonntag
            }[tag] %}
            
            {# Wähle das Array für den nächsten Tag #}
            {% set werte_naechster = {
              0: werte_montag,
              1: werte_dienstag,
              2: werte_mittwoch,
              3: werte_donnerstag,
              4: werte_freitag,
              5: werte_samstag,
              6: werte_sonntag
            }[naechster_tag] %}
            
            {# Aktuelle Zeit in timestamp #}
            {% set aktuelle_zeit = as_timestamp(now()) %}
            {% set aktuelle_stunde = now().hour %}
            {% set aktuelle_minute = now().minute %}
            
            {% set ziel_stunde = 8 | int %}
            {% set ziel_minute = 0| int %}
                      
             
            {# Berechne den anteiligen Verbrauch der aktuellen Stunde #}
            {% set anteil_aktuell = werte_aktuell[aktuelle_stunde] * (1 - (aktuelle_minute / 60)) %}
            
            {# Berechne den Verbrauch von jetzt bis zur Zielzeit #}
            {% if (aktuelle_stunde == ziel_stunde and aktuelle_minute == ziel_minute) %}
              {% set gesamtverbrauch = 0 %}
            {% elif aktuelle_stunde == ziel_stunde and aktuelle_minute < ziel_minute %}              
              {% set anteil_aktuell = werte_aktuell[aktuelle_stunde] * (((ziel_minute-aktuelle_minute) / 60)) %}
              {% set gesamtverbrauch = anteil_aktuell %}
            {% elif aktuelle_stunde < ziel_stunde %}
              {# Summiere von aktueller Stunde bis zur Zielstunde innerhalb des gleichen Tages #}
              {% set summe = werte_aktuell[aktuelle_stunde + 1:ziel_stunde] | sum %}
              {# Addiere den anteiligen Verbrauch der aktuellen Stunde #}
              {% set gesamtverbrauch = anteil_aktuell + summe %}
              {# Addiere den anteiligen Verbrauch der Zielminute #}
              {% set gesamtverbrauch = gesamtverbrauch + (werte_aktuell[ziel_stunde] * (ziel_minute / 60)) %}
            {% else %}
              {# Summiere von aktueller Stunde bis Ende des aktuellen Tages #}
              {% set summe_heute = werte_aktuell[aktuelle_stunde + 1:24] | sum %}
              {# Summiere von 0 Uhr bis zur Zielstunde des nächsten Tages #}
              {% set summe_morgen = werte_naechster[0:ziel_stunde] | sum %}
              {# Addiere beide Summen #}
              {% set gesamtverbrauch = anteil_aktuell + summe_heute + summe_morgen %}
            {% endif %}
            
            {% set puffer = (states("input_number.batteryload_buffer_energy") | float(0)) %}  {# Puffer kWh #}
            {{ gesamtverbrauch + puffer }}
        
        attributes:
          tomorrow: >
            {% set werte_montag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_dienstag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_mittwoch = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_donnerstag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_freitag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_samstag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            {% set werte_sonntag = [0.6, 0.6, 0.6, 0.2, 0.2, 0.2, 0.2, 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.2, 0.2, 0.2, 0.6] %}
            
            {% if now().hour>=8 -%}                         
               {% set von = (now().replace(hour=8, minute=0, second=0, microsecond=0) + timedelta(days=1)) %}
            {%- elif now().hour<8 -%}                            
               {% set von = (now().replace(hour=8, minute=0, second=0, microsecond=0) + timedelta(days=0)) %}
            {%- endif %}
          
            {# Bestimme den aktuellen Wochentag: 0 = Montag, 6 = Sonntag #}
            {% set tag = von.weekday() %}
            {% set naechster_tag = (tag + 1) % 7 %}

            {# Wähle das richtige Array basierend auf dem Wochentag #}
            {% set werte_aktuell = {
              0: werte_montag,
              1: werte_dienstag,
              2: werte_mittwoch,
              3: werte_donnerstag,
              4: werte_freitag,
              5: werte_samstag,
              6: werte_sonntag
            }[tag] %}
            
            {# Wähle das Array für den nächsten Tag #}
            {% set werte_naechster = {
              0: werte_montag,
              1: werte_dienstag,
              2: werte_mittwoch,
              3: werte_donnerstag,
              4: werte_freitag,
              5: werte_samstag,
              6: werte_sonntag
            }[naechster_tag] %}
                                    
            {# Stunde und Minute gleich bei von/bis#}
            {% set stunde = von.hour  %}
            {% set minute = von.minute %}                           
            
            {# Berechne den anteiligen Verbrauch der aktuellen Stunde #}
            {% set anteil1 = werte_aktuell[stunde] * (1 - (minute / 60)) %}
            {% set summe1 = werte_aktuell[stunde + 1:24] | sum %}
            {% set summe2 = werte_naechster[0:stunde] | sum %}
            {% set anteil2 = werte_naechster[stunde] * ((minute / 60)) %} 
            {% set gesamtverbrauch = anteil1 + summe1+ summe2 + anteil2 %}   
            
            {{ gesamtverbrauch }}

input_number:
  batteryload_buffer_load:
    name: "Batterieladung: Zusatzenergie Laden"
    min: 0
    max: 10
    step: 0.5
    unit_of_measurement: "kWh"  
    icon: mdi:battery-plus
2 Likes

Hi, First of all thanks for this awesome Dashboard. But i have 2 Bugs.

  1. In the actual month the price sensor is Sometime dipping to 0.
  2. The average Sensors have also wrong number and i dont know how to calculate this numbers.