Die offizielle Tibber-Integration in Home Assistant hat ein bekanntes Problem, das mich schon eine Weile nervt: Die Sensoren werden regelmäßig "unavailable", der Auto-Reconnect funktioniert nicht zuverlässig, und manchmal fehlen einfach Stunden an Daten. Ich habe mir das lange genug angeschaut und die Sache jetzt selbst in die Hand genommen. Das Ergebnis ist ein einziges YAML-Package, das die offizielle Integration komplett ersetzt, mehr Sensoren liefert und einfach stabil läuft.
Das eigentliche Problem mit der Tibber-Integration
Die offizielle Integration nutzt eine WebSocket-Verbindung für Echtzeit-Updates. Klingt gut, ist in der Praxis aber leider ziemlich wackelig. Die Verbindung bricht regelmäßig ab, die Sensoren landen auf "unavailable" und ein Auto-Reconnect findet einfach nicht statt. Dazu kommen Token-Probleme nach HA-Updates und gelegentliche Rate-Limit-Fehler bei der OAuth-Authentifizierung.
Der typische Workaround ist eine Automation, die bei "unavailable" automatisch homeassistant.reload_config_entry aufruft. Das ist ein Pflaster, keine echte Lösung. Minutenweise fehlen dann trotzdem Aufzeichnungen, manchmal sogar eine Viertelstunde oder mehr.
Die eigentliche Lösung ist aber viel einfacher: Tibber hat eine offene GraphQL API. Kein WebSocket, kein Reconnect-Problem, simples HTTP-Polling alle 5 Minuten. Strompreise ändern sich stündlich, also ist eine Verzögerung von 5 Minuten völlig irrelevant.
Voraussetzungen und API Token
Du brauchst einen Tibber-Account mit aktivem Stromvertrag und deinen persönlichen API Token. Den bekommst du unter developer.tibber.com, einfach einloggen und auf "Generate Token" klicken.
Den Token trägst du dann in deine secrets.yaml ein. Das Bearer mit Leerzeichen muss dabei im String enthalten sein:
TIBBER_TOKEN: "Bearer DEIN_API_TOKEN_HIER"Außerdem müssen Packages in deiner configuration.yaml aktiviert sein. Falls das noch nicht der Fall ist:
homeassistant:
packages: !include_dir_named packages/Wie das Ganze mit der secrets.yaml und der configuration.yaml zusammenspieltf, findest du übrigens sehr detailliert erklärt auf alles-automatisch.de unter dem Config Explorer. Da ist eigentlich alles ziemlich gut dokumentiert.
Der REST-Sensor als Datenquelle
Das Herzstück des Ganzen ist ein einziger REST-Sensor, der per GraphQL-Call den aktuellen Preis, alle Preise für heute und alle Preise für morgen holt. Alles in einem Request, alle 5 Minuten:
1rest:
2 - resource: https://api.tibber.com/v1-beta/gql
3 method: POST
4 scan_interval: 300
5 timeout: 30
6 verify_ssl: true
7 headers:
8 Authorization: !secret TIBBER_TOKEN
9 Content-Type: application/json
10 User-Agent: HomeAssistant
11 payload: >-
12 {
13 "query": "{ viewer { homes { currentSubscription { priceInfo { current { total energy tax startsAt level } today { total energy tax startsAt level } tomorrow { total energy tax startsAt level } } } } } }"
14 }
15 sensor:
16 - unique_id: tibber_api_rohdaten
17 name: "Tibber API Rohdaten"
18 value_template: >-
19 {{ value_json.data.viewer.homes[0].currentSubscription.priceInfo.current.total | default(0) }}
20 json_attributes_path: "$.data.viewer.homes[0].currentSubscription.priceInfo"
21 json_attributes:
22 - current
23 - today
24 - tomorrow
25 unit_of_measurement: "EUR/kWh"
26 device_class: monetaryDie API liefert pro Stunde total (Gesamtpreis), energy (reiner Energiepreis), tax (Steuern und Abgaben), startsAt (Zeitpunkt) und level von VERY_CHEAP bis VERY_EXPENSIVE. Alles landet in den Attributen des Rohdaten-Sensors, auf die dann die Template-Sensoren zugreifen.
Input Helper für konfigurierbare Schwellenwerte
Zwei Input Helper machen das Package wahnsinnig flexibel, weil du die Werte jederzeit direkt in der HA-Oberfläche anpassen kannst, ohne irgendwas am YAML ändern zu müssen:
1input_number:
2 tibber_fenster_stunden:
3 name: "Tibber: Cheapest-Window Laenge"
4 min: 1
5 max: 6
6 step: 1
7 initial: 3
8 unit_of_measurement: "h"
9 icon: mdi:clock-time-three-outline
10
11 tibber_preisgrenze:
12 name: "Tibber: Absolute Preisgrenze"
13 min: 0.05
14 max: 1.00
15 step: 0.01
16 initial: 0.30
17 unit_of_measurement: "EUR/kWh"
18 icon: mdi:currency-eurMit der Cheapest-Window Länge legst du fest, wie lang das günstigste zusammenhängende Zeitfenster sein soll, das der Sensor suchen soll. 3 Stunden am Stück für das E-Auto zum Beispiel. Die Absolute Preisgrenze ist der Schwellenwert für den Binary Sensor tibber_unter_preisgrenze. Liegt der aktuelle Preis darunter, schaltet er auf ON.
Template-Sensoren für aktuellen Preis und Tagesstatistik
Auf Basis des Rohdaten-Sensors bauen jetzt die eigentlichen Template-Sensoren auf. Erst mal der aktuelle Preis mit Energie- und Steueranteil als Attribute, plus das aktuelle Preislevel:
1template:
2 - sensor:
3 - unique_id: tibber_strompreis
4 name: "Tibber Strompreis"
5 state: >-
6 {% set raw = state_attr('sensor.tibber_api_rohdaten', 'current') %}
7 {{ raw.total | default(0) | float(0) | round(4) if raw else 0 }}
8 unit_of_measurement: "EUR/kWh"
9 device_class: monetary
10 state_class: measurement
11 icon: mdi:flash
12 attributes:
13 energie: >-
14 {% set raw = state_attr('sensor.tibber_api_rohdaten', 'current') %}
15 {{ raw.energy | default(0) | float(0) | round(4) if raw else 0 }}
16 steuer: >-
17 {% set raw = state_attr('sensor.tibber_api_rohdaten', 'current') %}
18 {{ raw.tax | default(0) | float(0) | round(4) if raw else 0 }}
19
20 - unique_id: tibber_preislevel
21 name: "Tibber Preislevel"
22 state: >-
23 {% set raw = state_attr('sensor.tibber_api_rohdaten', 'current') %}
24 {{ raw.level | default('NORMAL') if raw else 'NORMAL' }}Dazu kommen die Tagesstatistiken: Minimum, Maximum und Durchschnitt für heute:
1 - unique_id: tibber_preis_min_heute
2 name: "Tibber Preis Min Heute"
3 state: >-
4 {% set today = state_attr('sensor.tibber_api_rohdaten', 'today') | default([]) %}
5 {% if today | length > 0 %}
6 {{ today | map(attribute='total') | min | round(4) }}
7 {% else %}unknown{% endif %}
8 unit_of_measurement: "EUR/kWh"
9 device_class: monetary
10
11 - unique_id: tibber_preis_max_heute
12 name: "Tibber Preis Max Heute"
13 state: >-
14 {% set today = state_attr('sensor.tibber_api_rohdaten', 'today') | default([]) %}
15 {% if today | length > 0 %}
16 {{ today | map(attribute='total') | max | round(4) }}
17 {% else %}unknown{% endif %}
18 unit_of_measurement: "EUR/kWh"
19 device_class: monetary
20
21 - unique_id: tibber_preis_schnitt_heute
22 name: "Tibber Preis Schnitt Heute"
23 state: >-
24 {% set today = state_attr('sensor.tibber_api_rohdaten', 'today') | default([]) %}
25 {% if today | length > 0 %}
26 {{ ((today | map(attribute='total') | sum) / (today | length)) | round(4) }}
27 {% else %}unknown{% endif %}
28 unit_of_measurement: "EUR/kWh"
29 device_class: monetaryDas günstigste Zeitfenster berechnen
Das ist der Sensor, den ich wirklich am interessantesten finde. Er durchsucht die kombinierten Preisdaten von heute und morgen und findet das günstigste zusammenhängende Zeitfenster, dessen Länge du über den Input Helper definierst. Perfekt um das E-Auto zu laden, die Waschmaschine zu starten oder die Hausbatterie zu befüllen:
1 - unique_id: tibber_guenstigstes_fenster_start
2 name: "Tibber Guenstigstes Fenster Start"
3 state: >-
4 {% set today = state_attr('sensor.tibber_api_rohdaten', 'today') | default([]) %}
5 {% set tomorrow = state_attr('sensor.tibber_api_rohdaten', 'tomorrow') | default([]) %}
6 {% set alle = today + tomorrow %}
7 {% set fenster = states('input_number.tibber_fenster_stunden') | int(3) %}
8 {% if alle | length >= fenster %}
9 {% set ns = namespace(best_avg=999, best_start='unknown') %}
10 {% for i in range(alle | length - fenster + 1) %}
11 {% set window = alle[i:i+fenster] %}
12 {% set avg = window | map(attribute='total') | sum / fenster %}
13 {% if avg < ns.best_avg %}
14 {% set ns.best_avg = avg %}
15 {% set ns.best_start = window[0].startsAt %}
16 {% endif %}
17 {% endfor %}
18 {{ ns.best_start }}
19 {% else %}unknown{% endif %}
20
21 - unique_id: tibber_guenstigstes_fenster_preis
22 name: "Tibber Guenstigstes Fenster Preis"
23 state: >-
24 {% set today = state_attr('sensor.tibber_api_rohdaten', 'today') | default([]) %}
25 {% set tomorrow = state_attr('sensor.tibber_api_rohdaten', 'tomorrow') | default([]) %}
26 {% set alle = today + tomorrow %}
27 {% set fenster = states('input_number.tibber_fenster_stunden') | int(3) %}
28 {% if alle | length >= fenster %}
29 {% set ns = namespace(best_avg=999) %}
30 {% for i in range(alle | length - fenster + 1) %}
31 {% set window = alle[i:i+fenster] %}
32 {% set avg = window | map(attribute='total') | sum / fenster %}
33 {% if avg < ns.best_avg %}
34 {% set ns.best_avg = avg %}
35 {% endif %}
36 {% endfor %}
37 {{ ns.best_avg | round(4) }}
38 {% else %}unknown{% endif %}
39 unit_of_measurement: "EUR/kWh"
40 device_class: monetaryBinary Sensoren als Automations-Trigger
Für Automationen braucht man eigentlich keine Preiszahlen, sondern einfache ON/OFF-Zustände. Genau dafür sind die Binary Sensoren da:
1 - binary_sensor:
2 - unique_id: tibber_guenstiger_strom
3 name: "Tibber Guenstiger Strom"
4 state: >-
5 {% set preis = states('sensor.tibber_strompreis') | float(0) %}
6 {% set schnitt = states('sensor.tibber_preis_schnitt_heute') | float(0) %}
7 {{ preis > 0 and schnitt > 0 and preis < schnitt }}
8
9 - unique_id: tibber_teurer_strom
10 name: "Tibber Teurer Strom"
11 state: >-
12 {% set preis = states('sensor.tibber_strompreis') | float(0) %}
13 {% set schnitt = states('sensor.tibber_preis_schnitt_heute') | float(0) %}
14 {{ preis > 0 and schnitt > 0 and preis > (schnitt * 1.2) }}
15
16 - unique_id: tibber_sehr_guenstig
17 name: "Tibber Sehr Guenstig"
18 state: >-
19 {% set level = states('sensor.tibber_preislevel') %}
20 {{ level in ['VERY_CHEAP', 'CHEAP'] }}
21
22 - unique_id: tibber_unter_preisgrenze
23 name: "Tibber Unter Preisgrenze"
24 state: >-
25 {% set preis = states('sensor.tibber_strompreis') | float(0) %}
26 {% set grenze = states('input_number.tibber_preisgrenze') | float(0.30) %}
27 {{ preis > 0 and preis < grenze }}
28
29 - unique_id: tibber_api_erreichbar
30 name: "Tibber API Erreichbar"
31 state: >-
32 {% set last = states.sensor.tibber_api_rohdaten.last_updated | default(none) %}
33 {% if last %}
34 {{ (now() - last).total_seconds() < 900 }}
35 {% else %}
36 false
37 {% endif %}
38 device_class: connectivitytibber_guenstiger_strom schaltet auf ON, wenn der aktuelle Preis unter dem Tagesdurchschnitt liegt. tibber_teurer_strom schaltet bei mehr als 120% des Tagesdurchschnitts. tibber_sehr_guenstig nutzt direkt das Preislevel der API. Und tibber_api_erreichbar zeigt an, ob die API in den letzten 15 Minuten geantwortet hat.
Automation-Beispiel: Waschmaschine bei günstigem Strom
So sieht eine typische Automation damit aus:
1automation:
2 - alias: "Waschmaschine bei günstigem Strom starten"
3 triggers:
4 - trigger: state
5 entity_id: binary_sensor.tibber_sehr_guenstig
6 to: "on"
7 conditions:
8 - condition: state
9 entity_id: input_boolean.waschmaschine_warten
10 state: "on"
11 actions:
12 - action: switch.turn_on
13 target:
14 entity_id: switch.waschmaschine
15 - action: notify.mobile_app
16 data:
17 message: "Waschmaschine gestartet, Strom ist gerade günstig ({{ states('sensor.tibber_strompreis') }} EUR/kWh)"Du wartest also einfach, bis tibber_sehr_guenstig auf ON geht, und startest dann das Gerät. Wenn du statt dem Preislevel lieber eine absolute Grenze nehmen möchtest, nimmst du tibber_unter_preisgrenze als Trigger.
Offizielle Integration entfernen und umstellen
Bevor du die offizielle Integration löschst, solltest du die Konfiguration prüfen und Home Assistant neu starten. Wenn die neuen Sensoren Daten zeigen, kannst du unter Einstellungen die offizielle Tibber-Integration löschen. Die Auto-Reload-Automation, die du vielleicht gebaut hattest, wird danach nicht mehr gebraucht.
Falls du Statistics-Sensoren für Wochendurchschnitt oder ähnliches hast, musst du deren entity_id auf sensor.tibber_strompreis umstellen:
1sensor:
2 - platform: statistics
3 entity_id: sensor.tibber_strompreis # war: sensor.strom_strompreis
4 name: "Strompreis Ø Woche"
5 state_characteristic: mean
6 max_age:
7 days: 7Der EcoTracker oder Tibber Pulse für Echtzeit-Leistungsdaten läuft übrigens über eine eigene Integration und ist von dieser Änderung gar nicht betroffen. Der liefert weiterhin Watt, Phasen und Zählerstände wie gewohnt.
Wenn du noch kein Tibber-Kunde bist und überlegst zu wechseln: Über meinen Einladungslink bekommst du beim Registrieren einen Bonus. Ich auch. So haben wir beide was davon.
Ich nutze das Package selbst und bin wirklich zufrieden damit. Stabile Daten, mehr Sensoren als vorher, und kein nerviges "unavailable" mehr. Wie setzt du dynamische Strompreise in Home Assistant um? Hast du schon ähnliche Lösungen gebaut oder machst du das noch mit der offiziellen Integration?
