Template Berechnung Anzahl der Stunden für den besten Tibberpreis Nachts

Hallo zusammen,

ich habe mir vor ein paar Wochen auch HA installiert und steige mehr und mehr in das Thema ein. Ich habe aktuell noch kaum bis keine Kenntnisse in YAML und hoffe, dass ihr mir weiterhelfen könnt. Ich würde ebenfalls gerne meine Batterie nachts laden, wenn der Tibber Preis günstig ist. Hierfür habe ich mir folgende Idee überlegt:

  1. Bestimme die 4 günstigsten Stunden von 23 Uhr bis 6 Uhr.
  2. Berechne den Durchschnittspreis der 4 günstigsten Stunden
  3. Berechne den Durchschnittspreis von 7 - 17 Uhr
  4. Prüfe, ob der Durchschnittspreis der 4 Ladestunden 15% günstiger ist als der Durchschnittspreis von 7-17 Uhr
  5. Wenn ja, dann laden

Ich scheitere aber schon daran den Durchschnittspreis für einen bestimmten Zeitraum zu berechnen. Ich habe mal folgenden Code erstellt. Wie müsster der korrigiert werden?

- sensor:       
   - name: "tibber average price nachts"
     unique_id: "tibber_avg_nachts"
     unit_of_measurement: "Euro/kWh"
     state: >-
        {% set tomorrow_prices = state_attr('sensor.tibber_prices', 'tomorrow') %}
        {% if tomorrow_prices is not none %}
          {% set m0 = tomorrow_prices[0].total %}
          {% set m1 = tomorrow_prices[1].total %}
          {% set m2 = tomorrow_prices[2].total %}
          {% set m3 = tomorrow_prices[3].total %}
          {% set m4 = tomorrow_prices[4].total %}
          {% set m5 = tomorrow_prices[5].total %}
          {% set m6 = tomorrow_prices[6].total %}
          {% set avg_period = [ ("0-7Uhr", (((m0 + m1 + m2 + m3 + m4 + m5 + m6) / 7)| float(0))|round(2)] %}      
          {{ avg_period }}
        {% else %}
             {{ 0 }}
        {% endif %}

Hallo @Sofia94
versuch mal diesen Code:

   - sensor:       
      - name: "tibber average price nachts"
        unique_id: "tibber_avg_nachts"
        unit_of_measurement: "Euro/kWh"
        state: >
          {% set liste = state_attr('sensor.tibber_prices','tomorrow')| map(attribute='total') %}
          {% set sortierte_liste = liste | list %}
          {% if ((state_attr('sensor.tibber_prices','tomorrow')| map(attribute='total')| sum )) >0.1 -%}
           {% set m0 = sortierte_liste[0] -%}
           {% set m1 = sortierte_liste[1] -%}
           {% set m2 = sortierte_liste[2] -%}
           {% set m3 = sortierte_liste[3] -%}
           {% set m4 = sortierte_liste[4] -%}
           {% set m5 = sortierte_liste[5] -%}
           {% set m6 = sortierte_liste[6] -%}
          {{(((m0 + m1 + m2 + m3 + m4 + m5 + m6)) /7)|float(0)|round(5)}}    
           {% else %}
          {{ 0 }}
           {% endif %}

Allerdings ist “tomorrow” um 0:01 Uhr schon “today”. Das macht eine Automatisierung nicht unbedingt leichter (oder man stellt sich den Wecker). Was den Yaml-Code angeht: da scheint Bacardi einen guten Plan zu haben. Vielleicht kann er ja noch mal über diesen Code schauen.
Übrigen lade ich gar nicht, wenn die Differenz Tibber-Max zu Tibber-Min weniger als 20 % ausmacht. Da sind die Ladeverluste und das evtl. unnötige Aufladen zu hoch:

{{(((state_attr('sensor.gutenbergstrasse_2b_strompreis','max_price')|float(0)*100) / state_attr('sensor.gutenbergstrasse_2b_strompreis','min_price')-100| float(0))|round(1)) >= 20 }}

Ich habe auch mal so angefangen und immer wieder versucht, die Lademimik zu optimieren. Macht Spaß, ist aber mit vielen Unzulänglichkeiten behaftet. Ich bin jetzt wieder am Anfang und sehe den “ganzen” Tag als Berechnungsgrundlage. Genauso wichtig empfinde ich die Entladeautomation (funktioniert gut und effektiv). Eine vernünftige Solarprognose entscheidet bei mir auch, wieviel Prozent ich überhaupt in der Nacht den Akku auflade, oder ob es auch am Tage Sinn macht. Mit einer PV-Anlage hat man ja auch nur immer bis Mitte April Zeit zum Optimieren. Danach kommt nix mehr von Tibber. Ab dann geht es darum, erst ab Mittag zu laden.
mfg
Rainer

Lieber Rainer,

besten Dank für deine Rückmeldung! Der Code funktioniert :slightly_smiling_face:

Jetzt kann ich erstmal weiter experimentieren :slight_smile:

Frage mich gerade nur, warum der Sensor nicht bei den Helfern angezeigt wird, sondern nur bei den Entitiäten, aber hauptsache dieser Teil funktioniert erstmal.

Ich glaube aus dem Thema des richtigen Ladens kann eine Wissenschaft betrieben werden. Ich werde definitiv noch weitere conditions einbauen, die du auch schon aufgezählt hast. Für mich ist gerade auch der Weg das Ziel, um besser in das große Thema rund um HA reinzukommen.

Hast du ggf. einen Link, der übersichtlich die YAML Syntax erklärt?

Nochmal ganz lieben Dank und viele Grüße,
Sofia

Hallo Sofia,
ist ja Prima.
Vielleicht wird es ohne Klassifikation kein Helfer:

        unique_id: "watt_haus"
        unit_of_measurement: "W"
        device_class: "power"
        state_class: "measurement"

Ist bei Euro/kWh irgendwie auch nicht sinnvoll.
Beim yaml-code muss ich nur immer auf die richtigen Einrückungen achten. Ich hätte aber gerne einen ultimativen Link für gute Templates. Gibt es wohl nicht gebündelt. So wie mein persönliches Lieblingstemplate, klein, effektiv und macht am 15.04. Schluss mit Lademimik. Davon hätte ich gerne mehr.

{{ (1,1) <= (now().month, now().day) <= (4,15) }}

Falls Du noch Fragen zu “meiner” Lade- und Entlade-Strategie hast, frag einfach.
mfg
Rainer

Hallo Rainer,

die “Ladelogik” funktioniert schon einmal. Noch einmal vielen Dank für deine Hilfe :slight_smile:

Jetzt würde ich gerne weiter die Entladelogik umsetzen. Hierfür würde ich den battery max discharge parameter meines Wechselrichters nutzen wollen: wenn Strom teuer → dann wenig A, wenn Strom teuer dann max A setzen.

Aktuell überlege ich noch, welche Umsetzungsmöglichkeit gut wäre. Hierbei kommen mir folgende in den Sinn:

  1. statisch: wenn ich mir die Preise anschaue, haben wir in der Regel bis mittags ein Peak und dann wieder am Nachmittag. Ich würde dann bspw. einfach einstellen, dass max A von bspw. 8-11 und von 14-17. Vorteil: für mich einfach umzusetzen. Nachteil: ungenau
  2. dynamisch: ich sortiere die Liste der Preise nach den 5-6 teuersten und für diese Zeiten entlade ich mit max A. Vorteil: ist genau, da es die teuren Zeiten trifft. Nachteil: schwierig umzusetzen für mich (da ich nicht weiß, wie ich die Liste sortieren kann und bspw. den 3. teursten Wert ausgeben kann → hier würde ich wieder Hilfe benötigen) Zusätzlich als Nachteil sehe ich, dass wenn die Spitzenzeit von bspw. 16.00-00.00 Uhr ist, würde ich die Batterie bis dahin fast auf 100% halten und würde ggf. Strom verkaufen, den ich bis 16:00 erzeuge. Deshalb müsste ich es eigentlich noch an den Forecast koppeln.

Was wären deine Ideen bzw. wie machst du es?

@Sofia94
Hallo Sofia,

zum besten Preis fürs Laden hat sich in diesem Winter tatsächlich diese Formel herausgestellt.
((((Tibber-Summe) - (Tibber-Max * 2))/22) * faktor 0,925). Also der Durchschnittspreis minus 2 Spitzenstunden mal 0,925.
Damit konnte ich bei mir die besten Ladestunden (und damit die Nicht-Entladung zu guten Preisen) abbilden.

Aber hier erstmal ein Template für den drittgünstigsten Preis:
(hier macht nur das Wörtchen “list” oder “sort” den Unterschied):

##drittbester Preis des Tages
      - name: "tibber optimal preis"
        unique_id: "tibber_optimal_preis"
        unit_of_measurement: "Euro"
        state: >
          {% set liste = state_attr('sensor.tibber_prices','today')| map(attribute='total') %}
          {% set sort_stunde = liste | sort %}
          {{ sort_stunde[2] }}

Da kannst Du Dir natürlich einen Preis aussuchen und je nachdem “drüber” oder “drunter” etwas auslösen.

Diese Ansätze habe ich wohl auch schon probiert. Wird aber, je mehr man darüber nachdenkt immer komplizierter und ineffektiver.
Im Moment fahre ich ganz einfach. Ich orientiere mich da am min/max/average/sum - Wert der Tibber-Tagespreise:

          {{ state_attr('sensor.tibber_prices','today')| map(attribute='total')| min | float(0)| round(4) }}
          {{ state_attr('sensor.tibber_prices','today')| map(attribute='total')| max | float(0)| round(4) }}
          {{ state_attr('sensor.tibber_prices','today')| map(attribute='total')| average | float(0)| round(4) }}
          {{ state_attr('sensor.tibber_prices','today')| map(attribute='total')| sum | float(0)| round(4) }}

Diese Templates nutze ich direkt in der Automatisierung. Also, wenn aktueller Preis x und über average, dann mache …
Wenn der Preis unter avg ist, dann entlade ich mit 300 Watt (ist so ungefähr der allgemeine Hausverbrauch,
durch die Wärmepume und die kalten Temperaturen passt das natürlich nicht, gleicht sich aber immer wieder aus.

{{ (states('sensor.gutenbergstrasse_2b_strompreis')| float(0)) 
>= (state_attr('sensor.gutenbergstrasse_2b_strompreis','avg_price')| float(0))|round(3) }}

Ist der aktuelle Tibberpreis aber über den Durchschnitt, dann entlädt er dynamisch nach Restkapazität des Akkus und den
restlichen Stunden des Tages (wird manchmal nicht ganz leer, aber dann muss er in der Nacht halt weniger laden):

alias: Entladeleistung dynamisch restliche Stunden des Tages
action: number.set_value
metadata: {}
data:
  value: >-
    {{ (((states('sensor.battery_state_of_capacity')|float(0)*100)) /
    ((today_at() + timedelta(days=1) - now()).total_seconds() | int(0) /
    3600))|round(0) }}
target:
  entity_id: number.battery_maximum_discharging_power

Ein paar weitere Automatisierungen zur Verfeinerung habe ich auch noch drin. Z.B.
Wenn der Akku noch über 50% hat und der Hausverbrauch auf über 2000 Watt
ansteigt, dann wird die Entladeleistung auf 3800 Watt erhöht.
Sollte der Tibber-Preis über 38 Cent sein wird auch auf 3800 Watt Entladeleistung
erhöht (hier denke ich noch über eine evtl. Änderung nach, vielleicht 30% über Durchschnitt oder so).
Auf jeden Fall muss man dann sehr gut darüber nachdenken, wie man dann einige Automatisierungen automatisch ein- oder ausschaltet.
Sonst überlappt sich da was.

Hardware:
Hier bei uns sind ca 10 kW auf dem Dach (leider 8 Platten in Südost und 20 Platten in Nordwest), Ein Huawei-Wechselrichter,
Ein Huawei 10 KW Akku, eine Daikin 8KW-Wärmepumpe. HA läuft auf einem Zotac-Mini-PC mit N100-Chip, SSD und 8 GB RAM.

Wenn Du noch eine goldene Idee hast, einfach raus damit.
Und vielleicht solltest Du mal darüber ein neues Thema erstellen.

Rainer

Hallo Rainer,

klasse, besten Dank für deine schnelle Rückmeldung und ausführlichen Erläuterungen! Ich werde in den nächsten Tagen mal rumprobieren.

Hallo Sofia,
habe ich noch vergessen:
In den Automatisierungen arbeite ich am liebsten mit Bausteinen:
Auslöser, wenn - dann - sonst

Rainer

Hallo Rainer,

danke für den Nachtrag. Ich versuche gerade die zweitteuerte Stunde in der Zeit zwischen 7 und 17 zu ermitteln auf Basis deines Codebeispiels. Allerdings bekomme ich nichts ausgegeben und falls was ausgegeben würde, wäre es ja der Preis pro kWh.

- sensor:
   - name: "Zweitteuerste Stunde zwischen 7-17"
     unique_id: "zweitteuerste_stunde_7-17"
     unit_of_measurement: "hh:mm"
     state: >
       {% set liste = state_attr('sensor.tibber_prices', 'tomorrow') | map(attribute='total') |   
list %}
         {% set stunden = liste[7:16] %}
         {% set teuerste_zwei = stunden | sort}
         {{ teuerste_zwei[1] }}

Könntest du mir noch einmal helfen?

Hallo @Sofia94
jetzt machst Du es aber schwierig. Du hast recht, es käme da nur der Preis pro KWh raus. Oder aber als filtered_prices die Anzahl im Zeitraum. Eine Hysterese in einer Automation (größer oder kleiner 1 Cent oder 5% oder so) vom gewünschten Wert wäre vielleicht auch möglich. Was wäre denn Dein Wunschergebnis? Wegen des eigenartigen Timestamp in den tibber_prices ist es schwer, Zeitpunkte festzulegen. Zeiträume sind schon schwer genug. Hier hast Du mal den Code inkl. Zeitschema-Anpassung den Du wohl für weitere Berechnungen benötigst:

{% set liste = state_attr('sensor.tibber_prices','today')| map(attribute='total') %}
{% set sort_stunde = liste | sort %}
{% set prices = state_attr('sensor.tibber_prices','today') |selectattr ('startsAt') |list %}
{% set starttime_from = today_at('07:00:00').strftime('%Y-%m-%dT%H:%M:%S.%f%z') -%}
{% set starttime_to = today_at('18:00:00').strftime('%Y-%m-%dT%H:%M:%S.%f%z') -%}
{% set price_limit = sort_stunde[7]|float(0) -%}
{% set filtered_prices = prices 
    | selectattr('startsAt', '>=', starttime_from | replace(', ', 'T') + ":00.000+01:00") 
    | selectattr('startsAt', '<=', starttime_to | replace(', ', 'T') + ":00.000+01:00") 
    | selectattr('total', '<', price_limit)
    | list
    | count
%}
{{ filtered_prices }}
{{sort_stunde}}
{{sort_stunde[7]}}

Die unteren 3 Ergebniszeilen sind der Preis, die Liste, Anzahl der Stunden über oder unter (je nach >< bei price_limit) Deines zweitbesten Preises innerhalb des o.g. Zeitraumes. Da solltest Du nur das drin lassen, was Dein Ergebnis ist. Ich muss aber zugeben, das ich Dein Gesamtschema wohl nicht verstanden habe.
Viel Spass mit dem Code

Rainer

Vielen Dank, Rainer! Ich schaue es mir an und überlege noch einmal, ob ich lieber deiner avg Logik folge (wenn unter avg preis, dann…; wenn über avg preis, dann…)