Tibber & Tibber Pulse

Begonnen von hyper2910, 20 November 2022, 10:27:31

Vorheriges Thema - Nächstes Thema

Damian

Zitat von: duu75 am 16 April 2023, 13:57:26Kannst du das mal etwas näher erläutern?
Welche Hardware genau hast du am T.Pulse hängen um zu senden?
Und wie macht man das mit SOCAT und dem 1:1 Weiterleiten von einem Serial-Port zum anderen?

Habe selber die preiswerteste Version nur mit Phototransistor an einem CP2102 USB/UART dranhängen und logge so die OBIS Daten in FHEM.
Das würde ich gerne so belassen aber gleichzeitig auch Tibber Pulse nutzen können.

Ich will nächsten Monat ebenfalls zu Tibber mit Puls wechseln.

Z. Zt. lese ich meinen Stromzähler mit einer Diode und einem Widerstand am Tasmota aus: https://www.mwinklerblog.de/smarthome/aktoren-sensoren/stromz%C3%A4hler-digital/#Schaltplan

Ich habe heute mit einer weiteren IR-Diode am Steckboard experimentiert. Meine Idee ist das Signal am Fototransistor abzugreifen und mit einer weiteren IR-Diode zum Puls durchzuleiten.

In einem Monat weiß ich mehr. Am Steckboard hat es schon mal funktioniert, ggf. muss man einen Operationsverstärker/Transistor dazwischen hängen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

ch.eick

Wenn man Tibber Pulse als Lesekopf hat bekommt man von Tibber über einen Node-Red Stream die aktuellen Messwerte geliefert, das natürlich leider nur mit einer Internet Verbindung und nicht mehr lokal. Damit FHEM nicht sekündlich per MQTT neue readings bekommt habe ich das in Node-Red Flow auf 1/15 Sekunden gebremst.
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Damian

Zitat von: ch.eick am 17 April 2023, 07:28:03Wenn man Tibber Pulse als Lesekopf hat bekommt man von Tibber über einen Node-Red Stream die aktuellen Messwerte geliefert, das natürlich leider nur mit einer Internet Verbindung und nicht mehr lokal. Damit FHEM nicht sekündlich per MQTT neue readings bekommt habe ich das in Node-Red Flow auf 1/15 Sekunden gebremst.

ja, das habe ich schon gelesen. Dennoch wäre mir eine Unabhängigkeit von Tibber/Internet lieber.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

ch.eick

Zitat von: Damian am 17 April 2023, 07:38:46
Zitat von: ch.eick am 17 April 2023, 07:28:03Wenn man Tibber Pulse als Lesekopf hat bekommt man von Tibber über einen Node-Red Stream die aktuellen Messwerte geliefert, das natürlich leider nur mit einer Internet Verbindung und nicht mehr lokal. Damit FHEM nicht sekündlich per MQTT neue readings bekommt habe ich das in Node-Red Flow auf 1/15 Sekunden gebremst.

ja, das habe ich schon gelesen. Dennoch wäre mir eine Unabhängigkeit von Tibber/Internet lieber.
Ich habe ja kein Tibber :-) :-)
Bisher konnte ich noch nicht erkennen, dass ich dadurch etwas sparen würde.
Von April bis Oktober bin ich 100% Autark, im März waren es schon ca. 80%.
Somit bleiben mir im Jahr nur 2600 kWh um die höheren Zählergebüren in 64560 wieder rein zu holen, bevor ich dann sparen könnte.
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Damian

Zitat von: ch.eick am 17 April 2023, 08:18:53Hallo Damian,
kann ich das Diagramm später auch mit der uiTable kombinieren?  Hättest Du da mal den Beispiel Code?

VG  Christian

Klar, das ist ja noch einfacher. Du kannst direkt das Reading von Tibber in uiTable beim card-Aufruf nutzen, dann brauchst du den Umweg über ein zusätzliches DOIF nicht.

z. B. in uiTable:

card([EVU_Tibber:Strompreis:bar2day],undef,"",0,200,90,0,"SEK",undef,"1",",fixedscaling,,,,halfring")}
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

#65
Zitat von: ch.eick am 17 April 2023, 08:22:19Ich habe ja kein Tibber :-) :-)
Bisher konnte ich noch nicht erkennen, dass ich dadurch etwas sparen würde.
Von April bis Oktober bin ich 100% Autark, im März waren es schon ca. 80%.
Somit bleiben mir im Jahr nur 2600 kWh um die höheren Zählergebüren in 64560 wieder rein zu holen, bevor ich dann sparen könnte.

Ob sich ein Wechsel lohnt oder nicht, ist individuell zu entscheiden. Ich hatte bisher 40 Cent/kWh, da kann man beim Wechsel bis April 2024 (Preisbremse) nicht viel falsch machen, insb. wenn die monatliche Pauschale niedriger ist. Eine zweiwöchige Kündigungsfrist spricht auch für sich.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

ch.eick

#66
Zitat von: Damian am 17 April 2023, 10:09:21
Zitat von: ch.eick am 17 April 2023, 08:22:19Ich habe ja kein Tibber :-) :-)
Bisher konnte ich noch nicht erkennen, dass ich dadurch etwas sparen würde.
Von April bis Oktober bin ich 100% Autark, im März waren es schon ca. 80%.
Somit bleiben mir im Jahr nur 2600 kWh um die höheren Zählergebüren in 64560 wieder rein zu holen, bevor ich dann sparen könnte.

Ob sich ein Wechsel lohnt oder nicht, ist individuell zu entscheiden. Ich hatte bisher 40 Cent/kWh, da kann man beim Wechsel bis April 2024 (Preisbremse) nicht viel falsch machen, insb. wenn die monatliche Pauschale niedriger ist. Eine zweiwöchige Kündigungsfrist spricht auch für sich.
Ich habe noch 26ct im Dezember abgeschlosse und das EVU hat noch nicht gekündigt.
Bei meiner PLZ sind auch recht hohe Netzentgelte, was ich von aWATTar her weiß. Tibber gibt mir da erst eine Aussage, wenn ich wechseln würde.
Aber Vorbereitung ist ja alles :-)

Und hier noch ein Bild der heutigen Weiterentwicklung
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Speedy68

#67
Zitat von: ch.eick am 11 April 2023, 08:59:10Das 04_consumtion_hourly_100 ist für ein Nachtragen bei einer Tibber Störung gedacht und deckt ca. 4 Tage rückwirkend ab. Das SQL INSERT würde nur die fehlenden Einträge in der Datenbank ergänzen und die bereits vorhandenen behalten.
Ich habe ein intelligentes Messsystem und brauche daher keinen Pulse. Der Nachteil ist, dass der Netzbetreiber die Daten des Tages erst ab Mitternacht bereitstellt. D. h. ich müsste immer 04_consumtion_hourly_100 nutzen, um die Daten des Vortages korrekt zu bekommen. Die Daten des aktuellen Tages sind immer NULL.
04_consumtion_hourly_100 listet mir auch im httpbody alles völlig korrekt auf, es wird aber leider nichts in die Datenbank geschrieben.
Habe ich da etwas falsch verstanden, oder funktioniert dass dann so gar nicht?
Vielen Dank und Grüße

ch.eick

#68
Zitat von: Speedy68 am 19 April 2023, 17:41:55
Zitat von: ch.eick am 11 April 2023, 08:59:10Das 04_consumtion_hourly_100 ist für ein Nachtragen bei einer Tibber Störung gedacht und deckt ca. 4 Tage rückwirkend ab. Das SQL INSERT würde nur die fehlenden Einträge in der Datenbank ergänzen und die bereits vorhandenen behalten.
Ich habe ein intelligentes Messsystem und brauche daher keinen Pulse. Der Nachteil ist, dass der Netzbetreiber die Daten des Tages erst ab Mitternacht bereitstellt. D. h. ich müsste immer 04_consumtion_hourly_100 nutzen, um die Daten des Vortages korrekt zu bekommen. Die Daten des aktuellen Tages sind immer NULL.
04_consumtion_hourly_100 listet mir auch im httpbody alles völlig korrekt auf, es wird aber leider nichts in die Datenbank geschrieben.
Habe ich da etwas falsch verstanden, oder funktioniert dass dann so gar nicht?
Vielen Dank und Grüße
Moin,
somit hast Du also nicht den stündlichen Tarif, wenn ich das richtig verstehe.

Bisher habe die Massendaten nicht als readings abgelegt, da das das Device geflutet hätte. für diesen durchschnitts Tarif würde dann ja eine Abfrage von 24 Werten ausreichen.


VG  Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Speedy68

Zitat von: ch.eick am 20 April 2023, 08:17:34
Zitat von: Speedy68 am 19 April 2023, 17:41:55
Zitat von: ch.eick am 11 April 2023, 08:59:10Das 04_consumtion_hourly_100 ist für ein Nachtragen bei einer Tibber Störung gedacht und deckt ca. 4 Tage rückwirkend ab. Das SQL INSERT würde nur die fehlenden Einträge in der Datenbank ergänzen und die bereits vorhandenen behalten.
Ich habe ein intelligentes Messsystem und brauche daher keinen Pulse. Der Nachteil ist, dass der Netzbetreiber die Daten des Tages erst ab Mitternacht bereitstellt. D. h. ich müsste immer 04_consumtion_hourly_100 nutzen, um die Daten des Vortages korrekt zu bekommen. Die Daten des aktuellen Tages sind immer NULL.
04_consumtion_hourly_100 listet mir auch im httpbody alles völlig korrekt auf, es wird aber leider nichts in die Datenbank geschrieben.
Habe ich da etwas falsch verstanden, oder funktioniert dass dann so gar nicht?
Vielen Dank und Grüße
Moin,
somit hast Du also nicht den stündlichen Tarif, wenn ich das richtig verstehe.

Bisher habe die Massendaten nicht als readings abgelegt, da das das Device geflutet hätte. für diesen durchschnitts Tarif würde dann ja eine Abfrage von 24 Werten ausreichen.


VG  Christian
Hallo Christian,
doch, ich habe den stündlichen Tarif. Der wird bei mir allerdings erst einen Tag später rückwirkend abgerechnet. Der Netzbetreiber speichert den Zählerstand alle 15 min (*:00, *:15, *:30, *:45) und übermittelt den jeweils kurz nach Mitternacht an Tibber. Tibber berechnet dann den stündlichen Verbrauch.
Wenn ich Dein '04_consumtion_hourly_100' in FHEM aufrufe, bekomme ich auch alle Werte richtig angezeigt (nur den aktuellen Tag nicht, da sind die Werte NULL).
Bis auf den aktuellen Tag also (vermutlich) genau wie beim Pulse.
Meine Frage ist jetzt: Wie bekomme ich die stündlichen Werte in die Datenbank. Du schriebst ja "Das 04_consumtion_hourly_100 ist für ein Nachtragen bei einer Tibber Störung gedacht und deckt ca. 4 Tage rückwirkend ab. Das SQL INSERT würde nur die fehlenden Einträge in der Datenbank ergänzen und die bereits vorhandenen behalten."
Doch das funktioniert bei mir offensichtlich nicht.
Beispiel von heute mit der Zeit um Mitternacht:
...
{"from":"2023-04-19T21:00:00.000+02:00","to":"2023-04-19T22:00:00.000+02:00","cost":0.3149783273,"unitPrice":0.2968693,"unitPriceVAT":0.0473993,"consumption":1.061,"consumptionUnit":"kWh"},{"from":"2023-04-19T22:00:00.000+02:00","to":"2023-04-19T23:00:00.000+02:00","cost":0.2598194235,"unitPrice":0.2814945,"unitPriceVAT":0.0449445,"consumption":0.923,"consumptionUnit":"kWh"},{"from":"2023-04-19T23:00:00.000+02:00","to":"2023-04-20T00:00:00.000+02:00","cost":0.1852918298,"unitPrice":0.2716889,"unitPriceVAT":0.0433789,"consumption":0.682,"consumptionUnit":"kWh"},{"from":"2023-04-20T00:00:00.000+02:00","to":"2023-04-20T01:00:00.000+02:00","cost":null,"unitPrice":0.2699396,"unitPriceVAT":0.0430996,"consumption":null,"consumptionUnit":"kWh"},{"from":"2023-04-20T01:00:00.000+02:00","to":"2023-04-20T02:00:00.000+02:00","cost":null,"unitPrice":0.26299,"unitPriceVAT":0.04199,"consumption":null,"consumptionUnit":"kWh"},
...
Weil das nicht in die Datenbank geschrieben wird, habe ich natürlich dann auch keine Monats-/Jahreswerte.
Hast Du da eine Idee, was da schiefläuft?
Vielen Dank und Grüße
Frank

ch.eick

#70
ZitatHallo Christian,
doch, ich habe den stündlichen Tarif. Der wird bei mir allerdings erst einen Tag später rückwirkend abgerechnet. Der Netzbetreiber speichert den Zählerstand alle 15 min (*:00, *:15, *:30, *:45) und übermittelt den jeweils kurz nach Mitternacht an Tibber. Tibber berechnet dann den stündlichen Verbrauch.
Wenn ich Dein '04_consumtion_hourly_100' in FHEM aufrufe, bekomme ich auch alle Werte richtig angezeigt (nur den aktuellen Tag nicht, da sind die Werte NULL).
Bis auf den aktuellen Tag also (vermutlich) genau wie beim Pulse.
Meine Frage ist jetzt: Wie bekomme ich die stündlichen Werte in die Datenbank. Du schriebst ja "Das 04_consumtion_hourly_100 ist für ein Nachtragen bei einer Tibber Störung gedacht und deckt ca. 4 Tage rückwirkend ab. Das SQL INSERT würde nur die fehlenden Einträge in der Datenbank ergänzen und die bereits vorhandenen behalten."
Doch das funktioniert bei mir offensichtlich nicht.
Beispiel von heute mit der Zeit um Mitternacht:
...
{"from":"2023-04-19T21:00:00.000+02:00","to":"2023-04-19T22:00:00.000+02:00","cost":0.3149783273,"unitPrice":0.2968693,"unitPriceVAT":0.0473993,"consumption":1.061,"consumptionUnit":"kWh"},{"from":"2023-04-19T22:00:00.000+02:00","to":"2023-04-19T23:00:00.000+02:00","cost":0.2598194235,"unitPrice":0.2814945,"unitPriceVAT":0.0449445,"consumption":0.923,"consumptionUnit":"kWh"},{"from":"2023-04-19T23:00:00.000+02:00","to":"2023-04-20T00:00:00.000+02:00","cost":0.1852918298,"unitPrice":0.2716889,"unitPriceVAT":0.0433789,"consumption":0.682,"consumptionUnit":"kWh"},{"from":"2023-04-20T00:00:00.000+02:00","to":"2023-04-20T01:00:00.000+02:00","cost":null,"unitPrice":0.2699396,"unitPriceVAT":0.0430996,"consumption":null,"consumptionUnit":"kWh"},{"from":"2023-04-20T01:00:00.000+02:00","to":"2023-04-20T02:00:00.000+02:00","cost":null,"unitPrice":0.26299,"unitPriceVAT":0.04199,"consumption":null,"consumptionUnit":"kWh"},
...
Weil das nicht in die Datenbank geschrieben wird, habe ich natürlich dann auch keine Monats-/Jahreswerte.
Hast Du da eine Idee, was da schiefläuft?
Hallo Frank,
ich bin bereits dran und es läuft wohl auch schon.

- Beim 04_consumtion_hourly_100 muss man sich das INSERT noch selber aus dem JSON zusammen bauen. Dazu hätte ich eine Beschreibung.
- Wenn man den Node-Red Flow verwendet kann man sich dort das INSERT generieren lassen, was dann als reading im FHEM erscheint.
- Bei Dir würde man kurz nach Mitternacht das neue 04_consumtion_hourly_24 aufrufen, was dann 24h als readings ablegt
  und diese auch mit INSERT in die Datenbank schreibt. Ich beschränke mich jedoch jetzt auf "from, cost, consumption", damit
  man nicht von readings erschlagen wird.

Je nach dem wann die Berechnung wirklich bei Tibber erscheint müsste man eventuell noch 2-3 LAST Werte abfragen, aber das wird man dann bei Deinem Test sehen.

Die Statistiken werden mit den userReadings direkt in der datenbank berechnet. Keine Daten, keine Statistiken ;-)

Etwas Zeit brauche ich jedoch noch :-)
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

#71
Hallo zusammen,
hier mal eine aktuelle Zusammenfassung.

UPDATE 20230421 12:00 Teil 1

Das Umfeld:
Bei Tibber sind mir zwei Varianten bekannt.
1) Intelligentes Messsystem
  Hier wird der EVU Zähler alle 15 Minuten vom Netzbetreiber ausgelsen und die Ergebnisse an Tibber übermittelt.
  Tibber berechnet die Kosten im Stundentarif und stellt die Ergebnisse einmal am Tag nach Mitternacht zur Verfügung.
  Fragt man diese Berechnungen jedoch stündlich ab, so bekommt man den ganzen Tag Null gemeldet.
  Hierzu Dank an Frank für diesen Post
  Auf diesen Zähle kann man dann noch zusätzlich einen IR Lesekopf aufsetzen, um die aktuellen Messwerte lokal zu verarbeiten.
 
2) Tibber Pulse
  Dies ist ein Lesekopf, der auf einen digitalen Zähler, auf die IR Schnittstelle kommt. Dort werden dann die OBIS Register
  gelesen und direkt an Tibber gesendet, wo dann der Verbrauch, aber auch die aktuellen Leistungen bereit gestellt werden.
  Die Kosten können in diesem Fall stündlich abgefragt und im SmartHome verarbeitet werden. Natürlich ist es ebenfalls möglich
  das nur einmal am Tag zu machen, wie unter 1) angegeben.
  Die aktuellen Messwerte können mit Tibber Pulse, über das Internet, auch in einer http Session, im Sekundentakt gestreamt werden,
  was somit den eigenen IR Lesekopf ersetzen würde. Ein Manko dabei ist nur, dass dafür permanent die Internetverbindung benötigt wird.
 
  Nun gibt es hier wieder zwei Anwendungsvarianten:
 
  - Tibber Pulse ohne http Session für aktuelle Messwerte
    Sollte man keine aktuellen Messwerte über die http Session streamen wollen, so reicht eine einfache HTTPMOD Abfrage der Statistiken
    von Tibber, sowie die Abfrage der Preise für heute und morgen.
    Dies kann direkt aus FHEM erfolgen und bedarf keinem Umweg über z.B. Node-Red als "Proxy"
 
  - Tibber Pulse mit aktuellen Messwerten
    Für die aktuellen Messwerte wird eine HTTP Session benötigt, die so nicht direkt aus FHEM aufgebaut werden kann. Um dies zu lösen gibt
    es einen Node-Red Flow, der permanent die streaming Session aufrecht erhält.
    Für die Abfrage der Statistiken könnte man nun auch die direkte HTTPMOD Verbindung aus FHEM heraus nutzen, was jedoch über Node-Red ebenfalls
    erfolgen kann. Dies erspart ein Device udn läst das ganze eleganter wirken. Im Node-Red kann man dann auch noch weitere Flows erstellen, die
    zusätzlichen Komfort bereitstellen.
    Diese Implementierung setzt jedoch im FHEM eine bereits laufende MQTT Umgebung vorraus, die hier nicht nochmals beschrieben wird.
   
Vorausetzung:
- DbLog und DbRep mit MySQL
    z.B. im Docker
    Diese Implementierung setzt jedoch zwingend eine MySQL DbLog und ein DbRep Device vorraus, da aus dem userReadings
    direkt mir SQL Statements gearbeitet wird. Achtet bitte auch darauf, dass in der MySQL Datenbank ein
    "ADD PRIMARY KEY (`TIMESTAMP`, `DEVICE`, `READING`);" gesetzt wurde.
   
- MQTT bei Verwendung von Tibber Pulse

- Ein laufendes Node-Red
    z.B. im Docker
   
- Node-Red für Tibber Pulse streaming
    Paletten:
      node-red 3.0.2
      node-red-contrib-cron-plus 1.5.7
      node-red-contrib-tibber-api 5.2.1
    Tibber Flow
      kommt weiter unten

FHEM Devices:

1) Das DbRep Device dient der direkten Kommunikation mit der Datenbank und führt die MySQL Befehle aus dem userReading aus.
defmod LogDBRep_EVU_Tibber_connect_SQL DbRep LogDB
attr LogDBRep_EVU_Tibber_connect_SQL DbLogExclude .*
attr LogDBRep_EVU_Tibber_connect_SQL room System
attr LogDBRep_EVU_Tibber_connect_SQL sqlCmdHistoryLength 5

2) Für das bereitstellen des Vormonats wird dieses DbRep Device benötigt
defmod LogDBRep_Statistic_previous_Month DbRep LogDB
attr LogDBRep_Statistic_previous_Month DbLogExclude .*
attr LogDBRep_Statistic_previous_Month allowDeletion 0
attr LogDBRep_Statistic_previous_Month comment Version 2023.04.21 12:00
attr LogDBRep_Statistic_previous_Month room System
attr LogDBRep_Statistic_previous_Month verbose 0
Darin wird dann von Euch dieses sqlCmd ausgeführt.
Ich verwende das gleiche DbRep, um in einem SELECT für alle Vormonate die Daten bereit zu stellen.
Das DbRep Device muss dann jeweils zum ersten jeden Monats mit dem MySQL SELECT ausgeführt werden.
SELECT max(TIMESTAMP) AS TIMESTAMP,
       'EVU_Tibber_Pulse_nodes_consumption_month' AS READING,
       cast(sum(VALUE) AS DECIMAL(10, 0)) AS VALUE
FROM history
WHERE DEVICE='EVU_Tibber_connect'
  AND READING='nodes_consumption'
  AND TIMESTAMP > DATE_FORMAT(NOW() - INTERVAL 1 MONTH, '%Y-%m-01 00:00:00')
  AND TIMESTAMP < DATE_FORMAT(LAST_DAY(NOW() - INTERVAL 1 MONTH), '%Y-%m-%d 23:59:59')

3) Nach dem gleichen Muster wird es auch ein DbRep für das Vorjahr geben.
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

#72
UPDATE 20230421 12:00 Teil 2

Achtung, im Vergleich zu den bisherigen Device Namen hat sich etwas geändert. Die connect Devices heißen nun beide gleich, also "EVU_Tibber_connect",
da sie wahlweise zu verwenden sind. Dort entfällt auch das stateFormat. Das Device "EVU_Tibber" ist jetzt neu und übernimmt den Status, sowie die Steuerung.

4) EVU_Tibber Device
  Das DOIF Device händelt die Visualisierung mit uiTable und zeigt den Status an.
  Es werden auch Diagramme für die Tages Preise von heute und morgen im FHEMWEB angezeigt.
  Weiterhin erfolgt hier das Scheduling für die Statistikabfragen im HTTPMOD. Wenn man Node-Red verwendet kann man die Abfragen auch dort schedulen.
  Es ist in diesem Konzept angedacht in diesem DOIF auch die aktivierung von Verbrauchern zu triggern, was z.B. das Laden eines Hausspeichers oder
  auch das Signal für das BEV Laden sein könnte. Auch zusätzliches starten von einer Wärmepumpe oder einem Klima Gerät sollten hier platziert werden.

Dieses Device ist für beide EVU_Tibber_connect verwendbar,
Bei der MQTT EVU_Tibber_connect Anbindung kann das Scheduling jedoch direkt im Node-Red erfolgen und sollte deshalb dann hier auskommentiert werden.
Für die, die gerne Device Namen verändern wäre auch innerhalb des Device Codes an einigen Stellen der Device Name zu ändern. Ich habe es zwar versucht
zu zentralisieren, aber an einigen Stellen ist das nicht gelungen.
defmod EVU_Tibber DOIF ################################################################################################################\
## 1 Scheduling für das Abholen von Tibber Daten\
1_EVU_Tibber_PriceInfo\
{if( !([$SELF:state] eq "off")                                           ## DOIF enabled\
    and\
    (     [:03]                                                          ## Kurz nach jeder vollen Stunde\
    )\
    or [$SELF:ui_command_1] eq "1_EVU_Tibber_PriceInfo"                  ## Hier wird das uiTable select ausgewertet\
   ) {\
\
  ::CommandGet(undef, "EVU_Tibber_connect 01_priceInfo");;                ## Preis für die aktuelle Stunde\
  ::CommandGet(undef, "EVU_Tibber_connect 03_consumption_hour");;         ## Kosten der letzen drei Stunden\
  if (AttrVal("$SELF","verbose",0) >=3) {\
      Log 3, "$SELF cmd_1  : Abfrage von Tibber";;\
    }\
\
    set_Reading("ui_command_1","---");;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\
                                                                         ## kann das Kommando nicht sofort wiederholt werden\
  }\
}\
\
################################################################################################################\
## 2 Scheduling für das Abholen der Tibber Preise\
2_EVU_Tibber_PriceAll\
{if( !([$SELF:state] eq "off")                                           ## DOIF enabled\
    and\
    ([00:03] or [14:03]                                                  ## Ab 14:00 Uhr gibt es die Preise für den nächsten Tag\
    )\
    or [$SELF:ui_command_1] eq "2_EVU_Tibber_PriceAll"                   ## Hier wird das uiTable select ausgewertet\
   ) {\
\
  ::CommandGet(undef, "EVU_Tibber_connect 02_priceAll");;\
  if (AttrVal("$SELF","verbose",0) >=3) {\
      Log 3, "$SELF cmd_1  : Abfrage von Tibber für den nächsten Tag";;\
    }\
\
    set_Reading("ui_command_1","---");;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\
                                                                         ## kann das Kommando nicht sofort wiederholt werden\
  }\
}\
\
################################################################################################################\
## 2 Erstellen des Diagramms im uiTable\
3_EVU_Tibber_Diagramm\
{if( !([$SELF:state] eq "off")                                           ## DOIF enabled\
    and\
    (     [00:05] or [14:05]                                             ## Kurz nach Mitternacht\
    )\
    or [$SELF:ui_command_1] eq "3_EVU_Tibber_Diagramm"                   ## Hier wird das uiTable select ausgewertet\
   ) {\
\
  my (@out) = ("") x 2;;\
  my $timestamp;;\
\
  for (my $j=0;;$j<=1;;$j++){\
    for (my $i=0;;$i<=23;;$i++){\
      $timestamp = ReadingsVal("EVU_Tibber_connect",sprintf("fc%d_%02d_startsAt",$j,$i),"");;\
      $timestamp =~ s/ /_/g;;\
      $out[$j] .=$timestamp." ".::round(ReadingsVal("EVU_Tibber_connect",sprintf("fc%d_%02d_total",$j, $i),0)*100,1)."\n";;\
      if (    $i == 23\
          and ::ReadingsVal("EVU_Tibber_connect","fc0_00_startsAt","") eq ::ReadingsVal("EVU_Tibber_connect","fc1_00_startsAt","")\
         ) {                                                             ## Der nächste Tag ist noch nicht da\
          if (AttrVal("$SELF","verbose",0) >=3) {\
            Log 3, "$SELF cmd_1  : Tibber Daten von morgen sind noch nicht da";;\
          }\
          $timestamp = POSIX::strftime("%Y-%m-%d",localtime(time+86400));; ## Setze das Datum auf morgen\
          for (my $k=0;;$k<=23;;$k++) {\
            $out[$j] .= sprintf("%s_%02d:00:00 0\n", $timestamp, $k);;    ## Die Daten mit 0 ergänzen\
          }\
          $j = 2;;                                                        ## Aus der Schleife springen\
        }\
    } # End $i\
  } # End $j\
  if (AttrVal("$SELF","verbose",0) >=3) {\
      Log 3, "$SELF cmd_1  : Werte für das Diagramm";;\
      print($out[0]."\n\n");;\
      print($out[1]."\n");;\
    }\
  ## Die readings current_price und current_level dienen hier nur als Trigger Events, und müssen für\
  ## jedes Diagramm unterschiedlich sein, die Daten werden über $out[] bereit gestellt !!\
  ::DOIF_modify_card_data("EVU_Tibber","EVU_Tibber_connect","current_price","bar1day",0,$out[0]);;\
  ::DOIF_modify_card_data("EVU_Tibber","EVU_Tibber_connect","current_level","bar1day",-86400,$out[1]);;\
  ## Mit der Abfrage 03_consumption_hour werden die Trigger erneut ausgelöst\
  ::CommandGet(undef, "EVU_Tibber_connect 03_consumption_hour");;         ## Kosten der letzen drei Stunden\
\
    set_Reading("ui_command_1","---");;                                   ## Hier wird das uiTable select wieder zurückgesetzt, ansonsten\
                                                                         ## kann das Kommando nicht sofort wiederholt werden\
  }\
}
attr EVU_Tibber DbLogExclude .*
attr EVU_Tibber comment Version 2023.04.24 09:00 \
Dieses Device benötigt EVU_Tibber_connect als Verbindung zu Tibber.
attr EVU_Tibber disable 0
attr EVU_Tibber group PV Steuerung EVU
attr EVU_Tibber icon sani_pump
attr EVU_Tibber room Strom->Photovoltaik
attr EVU_Tibber sortby 315
attr EVU_Tibber uiTable {\
package ui_Table;;\
  $TABLE = "style='width:100%;;'";;\
\
  $TD{0..9}{0}     = "align='center' style='font-size:16px;;border-right-style:solid;;border-color:darkgreen;;border-right-width:2px;;width:26%'";;\
\
  $TD{0..9}{1} = "style='border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:36%;;font-weight:bold;;'";;\
  $TD{0..9}{2..4} = "style='border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:1px;;width:8%;;text-align:center;;'";;\
  $TD{0..9}{5} = "style='border-top-style:solid;;border-bottom-style:solid;;border-right-style:solid;;border-color:darkgreen;;border-top-width:2px;;border-bottom-width:2px;;border-right-width:2px;;width:8%;;text-align:center;;'";;\
\
sub FUNC_Status {\
    my($value, $min, $colorMin,  $statusMin,  $colorMiddel, $statusMiddle, $max, $colorMax, $statusMax)=@_;;\
    my $ret = ($value < $min)? '<span style="color:'.$colorMin.'">'.$statusMin.'</span>' : ($value > $max)? '<span style="color:'.$colorMax.'">'.$statusMax.'</span>' : '<span style="color:'.$colorMiddel.'">'.$statusMiddle.'</span>';;\
    return $ret;;\
  }\
\
sub Device {\
    return "$SELF"."_connect";;\
  }\
\
sub Price {\
  my($i)=@_;;\
  my $j;;\
  my $value;;\
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\
\
  if ($i == 0) {\
    $value = ::ReadingsVal(Device(),"current_price",0);;\
    $value = ( ::ReadingsVal(Device(),"fc0_trigger","off") eq "on" ) ?\
         "<span style='color:green'>".$value."</span>" :\
         "<span style='color:red'>".$value."</span>" ;;\
    $value .= " ct/kWh";;\
  } else {\
    $j       = $i+$hour;;\
    if ($j < 24) {\
      $value = ::round(::ReadingsVal(Device(),"fc0_".sprintf("%02d",$j)."_total",0)*100,1);;\
    } else {\
      $j = $j - 24;;\
      $value = ::round(::ReadingsVal(Device(),"fc1_".sprintf("%02d",$j)."_total",0)*100,1);;\
    }\
    $value = ( ::ReadingsVal(Device(),"fc0_trigger_price","0") > $value ) ?\
         "<span style='color:green'>".$value."</span>" :\
         "<span style='color:red'>".$value."</span>" ;;\
    $value = sprintf("%02d",$j)." :  ".$value ;;\
  }\
  return  $value;;\
 }\
\
sub Cost {\
  my($i)=@_;;\
  my $currency = (::ReadingsVal(Device(),"current_currency","") eq "EUR")? " €" : "";;\
\
  return ::ReadingsVal(Device(),"total_cost_".$i,0).$currency;;\
}\
\
sub Format {\
  my($i)=@_;;\
\
  my $MonthBefore   = "LogDBRep_Statistic_previous_Month";;\
  my $MonthPrevious = ::ReadingsTimestamp("$MonthBefore","EVU_Tibber_Pulse_nodes_consumption_month","null");;\
       $MonthPrevious = ($MonthPrevious ne "null") ?    POSIX::strftime("%Y",localtime(::time_str2num(::ReadingsTimestamp("$MonthBefore","EVU_Tibber_Pulse_nodes_consumption_month","null")))) : "null";;\
\
  my $YearBefore   = "LogDBRep_Statistic_previous_Year";;\
  my $YearPrevious = ::ReadingsTimestamp("$YearBefore",Device()."_nodes_consumption_year","null");;\
       $YearPrevious = ($YearPrevious ne "null") ? POSIX::strftime("%Y",localtime(::time_str2num(::ReadingsTimestamp("$YearBefore",Device()."_nodes_consumption_year","null")))) : "null";;\
\
  if ($i eq "day") {\
      return sprintf("%04d",::ReadingsVal(Device(),"nodes_consumption_day",0));;\
    } elsif ($i eq "month") {\
      my $evu_em = sprintf("%04d",::ReadingsVal(Device(),"nodes_consumption_month",0));;\
      $evu_em .= ($MonthPrevious ne "null") ? sprintf(" / %04d", ::ReadingsVal("$MonthBefore","EVU_Tibber_Pulse_nodes_consumption_month",0) ) : "";;\
      return $evu_em;;\
    } elsif ($i eq "year") {\
      my $evu_ey = sprintf("%04d",::ReadingsVal(Device(),"nodes_consumption_year",0));;\
      $evu_ey .= ($YearPrevious ne "null") ? sprintf(" / %04d", ::ReadingsVal("$YearBefore","EVU_Tibber_Pulse_nodes_consumption_month",0) ) : "";;\
      return $evu_ey;;\
    } elsif ($i eq "trigger") {\
      return (    ::ReadingsVal(Device(),"fc0_min",0) > ::ReadingsVal(Device(),"fc0_trigger_price",0)\
                 or ::ReadingsVal(Device(),"fc0_trigger_start","") eq "null" ) ?\
            "<span style='color:red'>Heute kein Trigger <br>mehr unter ".\
                 ::ReadingsVal(Device(),"fc0_trigger_price","null")." ct</span>" :\
            "<span style='color:green'>Trigger von<br>".\
                 ::ReadingsVal(Device(),"fc0_trigger_start","00:00")." bis ".::ReadingsVal(Device(),"fc0_trigger_stop","00:00")."<br>unter ".\
                 ::ReadingsVal(Device(),"fc0_trigger_price","null")." ct</span>" ;;\
    }\
  return "null";;\
}\
\
}\
\
"$SELF"|"Kommando<dd>Auswahl</dd>" |widget([$SELF:ui_command_1],"uzsuDropDown,---,1_EVU_Tibber_PriceInfo,2_EVU_Tibber_PriceAll,3_EVU_Tibber_Diagramm") |""|""|""\
\
|"Statistiken ".::ReadingsVal(Device(),"current_date",0)." in kWh"|"<span style=font-weight:bold>aktuell</span>"|"<span style=font-weight:bold>heute</span>"|"<span style=font-weight:bold>Monat</span>"|"<span style=font-weight:bold>Jahr</span>"\
\
|"Bezug vom Netz"|sprintf("%04d W",::ReadingsVal(Device(),"Pulse_P_act",0))|Format("day")|Format("month")|Format("year")\
\
|"Einspeisung ins Netz"|sprintf("%04d W",::ReadingsVal(Device(),"Pulse_P_act_Prod",0))|""|""|""\
\
|"Strom<dd>Preis / Kosten</dd>"|Price(0)|Cost("day")|Cost("month")|Cost("year")\
\
|"Strompreis<br>".card([EVU_Tibber_connect:current_price:bar1day],undef,undef,0,60,90,0,"fc0  ".::ReadingsVal(Device(),"current_currency",""),undef,"1","130,,,,,,220").card([EVU_Tibber_connect:current_level:bar1day],undef,undef,0,60,90,0,"fc1  ".::ReadingsVal(Device(),"current_currency",""),undef,"1","130,,,,,,220")|"<span style=font-weight:bold>nächste 3h</span><br><br>".Price(1)."<br>".Price(2)."<br>".Price(3)|"<span style=font-weight:bold>Statistik fc0</span><br><br>".::ReadingsVal(Device(),"fc0_avg",0)." avg<br>".::ReadingsVal(Device(),"fc0_min",0)." min<br>".::ReadingsVal(Device(),"fc0_max",0)." max"|"<span style=font-weight:bold>Trigger</span><br>Basis ".widget([EVU_Tibber_connect:compensation_grid],"selectnumbers,0,0.1,12,1,lin")."<br>".Format("trigger")|""\

attr EVU_Tibber verbose 3
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

#73
UPDATE 20230421 12:00 Teil 3

5.1) EVU_Tibber_connect als HTTPMOD
  Das Device dient der Abfrage von Tibber Statistiken und Daten, die dann im EVU_Tibber DOIF als Status aufbereitet werden.
  Hierzu kann man auch ein stateFormat für den Status verwenden, was dann jedoch keine Preis Diagramme beinhaltet, da diese uiTable vom DOIF benötigen.

Defaults
setstate EVU_Tibber_connect 2023-04-21 12:00:00 compensation_grid 0.0
setstate EVU_Tibber_connect 2023-04-21 12:00 homeID 96a14971-525a-4420-aae9-e5aedaa129ff
setstate EVU_Tibber_connect 2023-04-21 12:00 token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE
RAW Device
defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0
attr EVU_Tibber_connect DbLogExclude .*
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*
attr EVU_Tibber_connect comment Version 2023.04.21 12:00 \
https://developer.tibber.com/explorer\
\
homeID 96a14971-525a-4420-aae9-e5aedaa129ff\
token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE\
\
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\
setreading EVU_Tibber compensation_grid <Eure Einspeisevergütung>\
\
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\
    (fc0_avg - fc0_min)  /2 + fc0_min\
\
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\
    (fc0_avg - compensation_grid) *0.85
attr EVU_Tibber_connect disable 0
attr EVU_Tibber_connect enableControlSet 1
attr EVU_Tibber_connect get01-1Name current_currency
attr EVU_Tibber_connect get01-2Name current_level
attr EVU_Tibber_connect get01-3Name current_date
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get01-4Name current_price
attr EVU_Tibber_connect get01-4OExpr $val *100
attr EVU_Tibber_connect get01Data { "query": "{viewer {home(id:\"%%homeID%%\") {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}" }
attr EVU_Tibber_connect get01Header01 Content-Type: application/json
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current
attr EVU_Tibber_connect get01Name 01_priceInfo
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get02-10Name fc0_03_total
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-12Name fc0_04_total
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-14Name fc0_05_total
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-16Name fc0_06_total
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-18Name fc0_07_total
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-1Name current_date
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-20Name fc0_08_total
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-22Name fc0_09_total
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-24Name fc0_10_total
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-26Name fc0_11_total
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-28Name fc0_12_total
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-2Name current_price
attr EVU_Tibber_connect get02-2OExpr $val *100
attr EVU_Tibber_connect get02-30Name fc0_13_total
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-32Name fc0_14_total
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-34Name fc0_15_total
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-36Name fc0_16_total
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-38Name fc0_17_total
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-40Name fc0_18_total
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-42Name fc0_19_total
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-44Name fc0_20_total
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-46Name fc0_21_total
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-48Name fc0_22_total
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-4Name fc0_00_total
attr EVU_Tibber_connect get02-50Name fc0_23_total
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-52Name fc1_00_total
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-54Name fc1_01_total
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-56Name fc1_02_total
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-58Name fc1_03_total
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-60Name fc1_04_total
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-62Name fc1_05_total
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-64Name fc1_06_total
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-66Name fc1_07_total
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-68Name fc1_08_total
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-6Name fc0_01_total
attr EVU_Tibber_connect get02-70Name fc1_09_total
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-72Name fc1_10_total
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-74Name fc1_11_total
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-76Name fc1_12_total
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-78Name fc1_13_total
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-80Name fc1_14_total
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-82Name fc1_15_total
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-84Name fc1_16_total
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-86Name fc1_17_total
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-88Name fc1_18_total
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-8Name fc0_02_total
attr EVU_Tibber_connect get02-90Name fc1_19_total
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-92Name fc1_20_total
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-94Name fc1_21_total
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-96Name fc1_22_total
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-98Name fc1_23_total
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02Data { "query": "{viewer {home(id:\"%%homeID%%\") {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}" }
attr EVU_Tibber_connect get02Header01 Content-Type: application/json
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo
attr EVU_Tibber_connect get02Name 02_priceAll
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get03-1Name nodes_00_00_from
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost
attr EVU_Tibber_connect get03-2OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption
attr EVU_Tibber_connect get03-4Name nodes_00_01_from
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost
attr EVU_Tibber_connect get03-50OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost
attr EVU_Tibber_connect get03-5OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption
attr EVU_Tibber_connect get03-7Name nodes_00_02_from
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost
attr EVU_Tibber_connect get03-8OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption
attr EVU_Tibber_connect get03Data { "query": "{viewer {home(id:\"%%homeID%%\") {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}"}
attr EVU_Tibber_connect get03Header01 Content-Type: application/json
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get03Name 03_consumption_hour
attr EVU_Tibber_connect get03RegOpt g
attr EVU_Tibber_connect get03Regex \{"from":"([\d+-]+T[\d+:]+\.000[+-][\d+:]+)","cost":(null|\d+\.\d+|0),"consumption":(null|\d+\.\d+|0)\}
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get04-10Name nodes_24_03_from
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost
attr EVU_Tibber_connect get04-11OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption
attr EVU_Tibber_connect get04-13Name nodes_24_04_from
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost
attr EVU_Tibber_connect get04-14OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption
attr EVU_Tibber_connect get04-16Name nodes_24_05_from
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost
attr EVU_Tibber_connect get04-17OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption
attr EVU_Tibber_connect get04-19Name nodes_24_06_from
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-1Name nodes_24_00_from
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost
attr EVU_Tibber_connect get04-20OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption
attr EVU_Tibber_connect get04-22Name nodes_24_07_from
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost
attr EVU_Tibber_connect get04-23OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption
attr EVU_Tibber_connect get04-25Name nodes_24_08_from
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost
attr EVU_Tibber_connect get04-26OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption
attr EVU_Tibber_connect get04-28Name nodes_24_09_from
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost
attr EVU_Tibber_connect get04-29OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost
attr EVU_Tibber_connect get04-2OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption
attr EVU_Tibber_connect get04-31Name nodes_24_10_from
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost
attr EVU_Tibber_connect get04-32OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption
attr EVU_Tibber_connect get04-34Name nodes_24_11_from
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost
attr EVU_Tibber_connect get04-35OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption
attr EVU_Tibber_connect get04-37Name nodes_24_12_from
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost
attr EVU_Tibber_connect get04-38OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption
attr EVU_Tibber_connect get04-40Name nodes_24_13_from
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost
attr EVU_Tibber_connect get04-41OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption
attr EVU_Tibber_connect get04-43Name nodes_24_14_from
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost
attr EVU_Tibber_connect get04-44OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption
attr EVU_Tibber_connect get04-46Name nodes_24_15_from
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost
attr EVU_Tibber_connect get04-47OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption
attr EVU_Tibber_connect get04-49Name nodes_24_16_from
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-4Name nodes_24_01_from
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost
attr EVU_Tibber_connect get04-50OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption
attr EVU_Tibber_connect get04-52Name nodes_24_17_from
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost
attr EVU_Tibber_connect get04-53OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption
attr EVU_Tibber_connect get04-55Name nodes_24_18_from
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost
attr EVU_Tibber_connect get04-56OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption
attr EVU_Tibber_connect get04-58Name nodes_24_19_from
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost
attr EVU_Tibber_connect get04-59OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost
attr EVU_Tibber_connect get04-5OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption
attr EVU_Tibber_connect get04-61Name nodes_24_20_from
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost
attr EVU_Tibber_connect get04-62OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption
attr EVU_Tibber_connect get04-64Name nodes_24_21_from
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost
attr EVU_Tibber_connect get04-65OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption
attr EVU_Tibber_connect get04-67Name nodes_24_22_from
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost
attr EVU_Tibber_connect get04-68OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption
attr EVU_Tibber_connect get04-70Name nodes_24_23_from
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost
attr EVU_Tibber_connect get04-71OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption
attr EVU_Tibber_connect get04-7Name nodes_24_02_from
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost
attr EVU_Tibber_connect get04-8OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption
attr EVU_Tibber_connect get04Data { "query": "{viewer {home(id:\"%%homeID%%\") {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}"}
attr EVU_Tibber_connect get04Header01 Content-Type: application/json
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get04Name 04_consumption_hour_24
attr EVU_Tibber_connect get04RegOpt g
attr EVU_Tibber_connect get04Regex \{"from":"([\d+-]+T[\d+:]+\.000[+-][\d+:]+)","cost":(null|\d+\.\d+|0),"consumption":(null|\d+\.\d+|0)\}
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get05-10Name Adresse_01_Nachname
attr EVU_Tibber_connect get05-1Name Adresse_03_Strasse
attr EVU_Tibber_connect get05-2Name Adresse_05_Ort
attr EVU_Tibber_connect get05-3Name Adresse_06_Land
attr EVU_Tibber_connect get05-4Name Adresse_09_latitude
attr EVU_Tibber_connect get05-5Name Adresse_10_longitude
attr EVU_Tibber_connect get05-6Name Adresse_04_Plz
attr EVU_Tibber_connect get05-7Name Adresse_08_eMail
attr EVU_Tibber_connect get05-8Name Adresse_07_Telefon
attr EVU_Tibber_connect get05-9Name Adresse_02_Vorname
attr EVU_Tibber_connect get05Data { "query": "{viewer {home(id:\"%%homeID%%\") {consumption(resolution: HOURLY, last: 100) {nodes {from to cost unitPrice unitPriceVAT consumption consumptionUnit}}}}}"}
attr EVU_Tibber_connect get05Header01 Content-Type: application/json
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get05JSON data_viewer_home
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get06-10Name Adresse_01_Nachname
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort
attr EVU_Tibber_connect get06-3Name Adresse_06_Land
attr EVU_Tibber_connect get06-4Name Adresse_09_latitude
attr EVU_Tibber_connect get06-5Name Adresse_10_longitude
attr EVU_Tibber_connect get06-6Name Adresse_04_Plz
attr EVU_Tibber_connect get06-7Name Adresse_08_eMail
attr EVU_Tibber_connect get06-8Name Adresse_07_Telefon
attr EVU_Tibber_connect get06-9Name Adresse_02_Vorname
attr EVU_Tibber_connect get06Data { "query": "{viewer {home(id:\"%%homeID%%\") {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}" }
attr EVU_Tibber_connect get06Header01 Content-Type: application/json
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get06JSON data_viewer_home
attr EVU_Tibber_connect get06Name 06_address
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get07-10Name nodes_24_03_from
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost
attr EVU_Tibber_connect get07-11OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption
attr EVU_Tibber_connect get07-13Name nodes_24_04_from
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost
attr EVU_Tibber_connect get07-14OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption
attr EVU_Tibber_connect get07-16Name nodes_24_05_from
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost
attr EVU_Tibber_connect get07-17OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption
attr EVU_Tibber_connect get07-19Name nodes_24_06_from
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost
attr EVU_Tibber_connect get07-20OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption
attr EVU_Tibber_connect get07-22Name nodes_24_07_from
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost
attr EVU_Tibber_connect get07-23OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption
attr EVU_Tibber_connect get07-25Name nodes_24_08_from
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost
attr EVU_Tibber_connect get07-26OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption
attr EVU_Tibber_connect get07-28Name nodes_24_09_from
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost
attr EVU_Tibber_connect get07-29OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-2Name features_id
attr EVU_Tibber_connect get07-2OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption
attr EVU_Tibber_connect get07-31Name nodes_24_10_from
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost
attr EVU_Tibber_connect get07-32OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption
attr EVU_Tibber_connect get07-34Name nodes_24_11_from
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost
attr EVU_Tibber_connect get07-35OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption
attr EVU_Tibber_connect get07-37Name nodes_24_12_from
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost
attr EVU_Tibber_connect get07-38OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption
attr EVU_Tibber_connect get07-40Name nodes_24_13_from
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost
attr EVU_Tibber_connect get07-41OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption
attr EVU_Tibber_connect get07-43Name nodes_24_14_from
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost
attr EVU_Tibber_connect get07-44OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption
attr EVU_Tibber_connect get07-46Name nodes_24_15_from
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost
attr EVU_Tibber_connect get07-47OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption
attr EVU_Tibber_connect get07-49Name nodes_24_16_from
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-4Name nodes_24_01_from
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost
attr EVU_Tibber_connect get07-50OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption
attr EVU_Tibber_connect get07-52Name nodes_24_17_from
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost
attr EVU_Tibber_connect get07-53OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption
attr EVU_Tibber_connect get07-55Name nodes_24_18_from
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost
attr EVU_Tibber_connect get07-56OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption
attr EVU_Tibber_connect get07-58Name nodes_24_19_from
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost
attr EVU_Tibber_connect get07-59OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost
attr EVU_Tibber_connect get07-5OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption
attr EVU_Tibber_connect get07-61Name nodes_24_20_from
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost
attr EVU_Tibber_connect get07-62OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption
attr EVU_Tibber_connect get07-64Name nodes_24_21_from
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost
attr EVU_Tibber_connect get07-65OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption
attr EVU_Tibber_connect get07-67Name nodes_24_22_from
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost
attr EVU_Tibber_connect get07-68OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption
attr EVU_Tibber_connect get07-70Name nodes_24_23_from
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost
attr EVU_Tibber_connect get07-71OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption
attr EVU_Tibber_connect get07-7Name nodes_24_02_from
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost
attr EVU_Tibber_connect get07-8OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption
attr EVU_Tibber_connect get07Data { "query": "{viewer {home(id:\"%%homeID%%\") {id features{realTimeConsumptionEnabled} } } }" }
attr EVU_Tibber_connect get07Header01 Content-Type: application/json
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get07JSON data_viewer_home
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled
attr EVU_Tibber_connect get07RegOpt g
attr EVU_Tibber_connect get07Regex \{"from":"([\d+-]+T[\d+:]+\.000[+-][\d+:]+)","cost":(null|\d+\.\d+|0),"consumption":(null|\d+\.\d+|0)\}
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect group PV Steuerung EVU
attr EVU_Tibber_connect icon stromzaehler_icon
attr EVU_Tibber_connect replacement01Mode reading
attr EVU_Tibber_connect replacement01Regex %%token%%
attr EVU_Tibber_connect replacement01Value token
attr EVU_Tibber_connect replacement02Mode reading
attr EVU_Tibber_connect replacement02Regex %%homeID%%
attr EVU_Tibber_connect replacement02Value homeID
attr EVU_Tibber_connect requestData { "query": "{viewer {home(id:\"%%homeID%%\") {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}" }
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%
attr EVU_Tibber_connect room Strom->Photovoltaik
attr EVU_Tibber_connect showBody 1
attr EVU_Tibber_connect showError 1
attr EVU_Tibber_connect sortby 313
attr EVU_Tibber_connect userReadings nodes_TIMESTAMP:nodes_00_00_cost.* {\
my ($timestamp,$value) = 2x0;;\
my $tmp = 0;;\
\
for (my $loop_last = 0;; $loop_last <= 2;; $loop_last++) {\
  $timestamp = ReadingsVal("$NAME","nodes_00_".sprintf("%02d",$loop_last)."_from","null");;\
  $value = ReadingsVal("$NAME","nodes_".sprintf("%02d",$loop_last)."_cost","null");;\
\
  if ( $value ne "null" ) {\
    # Eintragen der Kosten für die Stunde\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_cost','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
    # Eintragen des Verbrauchs für die Stunde\
    $value = ReadingsVal("$NAME","nodes_00_".$loop_last."_consumption","null");;\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_consumption','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
  } else {\
    $tmp = "null";;\
  }\
} # end for\
if ($tmp eq "null") {\
  $timestamp = $tmp\
}\
$timestamp;;\
},\
\
nodes_TIMESTAMP:nodes_24_00_cost.* {\
my ($timestamp,$value) = 2x0;;\
my $tmp = 0;;\
\
for (my $loop_last = 0;; $loop_last <= 23;; $loop_last++) {\
  $timestamp = ReadingsVal("$NAME","nodes_24_".sprintf("%02d",$loop_last)."_from","null");;\
  $value = ReadingsVal("$NAME","nodes_24_".sprintf("%02d",$loop_last)."_cost","null");;\
\
  if ( $value ne "null" ) {\
    # Eintragen der Kosten für die Stunde\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_cost','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
    # Eintragen des Verbrauchs für die Stunde\
    $value = ReadingsVal("$NAME","nodes_24_".sprintf("%02d",$loop_last)."_consumption","null");;\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_consumption','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
  } else {\
    $tmp = "null";;\
  }\
} # end for\
if ($tmp eq "null") {\
  $timestamp = $tmp\
}\
$timestamp;;\
},\
\
nodes_cost_avg:nodes_TIMESTAMP.* {\
## Berechnung des Tages Wertes\
  if ( ReadingsVal("$NAME","nodes_TIMESTAMP","null") ne "null" ) {\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND TIMESTAMP >= curdate() ;;") ;;\
  } else {\
    ReadingsVal("$NAME","nodes_cost_avg","null")\
  }\
},\
\
nodes_cost_min:nodes_TIMESTAMP.* {\
##  Ermittlung des minimal Wertes\
if ( ReadingsVal("$NAME","nodes_TIMESTAMP","null") ne "null" ) {\
  ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND TIMESTAMP >= curdate() ;;") ;;\
} else {\
  ReadingsVal("$NAME","nodes_cost_min","null")\
}\
},\
\
nodes_cost_max:nodes_TIMESTAMP.* {\
## Ermittlung des maximal Wertes\
  if ( ReadingsVal("$NAME","nodes_TIMESTAMP","null") ne "null" ) {\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND TIMESTAMP >= curdate() ;;") ;;\
  } else {\
    ReadingsVal("$NAME","nodes_cost_max","null")\
  }\
},\
\
nodes_consumption_day:nodes_TIMESTAMP.* {\
## Berechnung des Tages Verbrauches\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_consumption'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
nodes_consumption_month:nodes_TIMESTAMP.* {\
## Berechnung des Monats Verbrauches\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_consumption'\
             AND YEAR(TIMESTAMP) = YEAR(curdate())\
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;") ;;\
},\
\
nodes_consumption_year:nodes_TIMESTAMP.* {\
## Berechnung des Jahres Verbrauches\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_consumption'\
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;") ;;\
},\
\
fc0_avg:current_price.* {\
## Berechnung des Tages Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='fc0_total'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
fc0_min:current_price.* {\
##  Ermittlung des minimal Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='fc0_total'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
fc0_max:current_price.* {\
## Ermittlung des maximal Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='fc0_total'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
fc0_trigger_price:[fc0_avg|compensation_grid].* {\
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\
my $price_level = round( (ReadingsVal("$NAME","fc0_avg",0) - ReadingsVal("$NAME","fc0_min",0))/2 + ReadingsVal("$NAME","fc0_min",0) , 1);;\
\
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\
if ( ReadingsVal("$NAME","compensation_grid",0) != 0 ) {\
  my $price_level_battery = round( (ReadingsVal("$NAME","fc0_avg",0) - ReadingsVal("$NAME","compensation_grid",0)) *0.85 , 1) ;;\
  if ( $price_level > $price_level_battery ) {\
    $price_level = $price_level_battery\
  }\
}\
$price_level;;\
},\
\
fc0_trigger_start:fc0_trigger_price.* {\
  my $fc = 0;;\
  my $fc_trigger_price = ReadingsVal("$NAME","fc".$fc."_trigger_price",0) /100;;\
\
  # Ermitteln des nächsten Trigger Fensters\
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\
  my $fc_total = 0;;\
\
    for (my $loop_hour = $hour;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc".$fc."_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total < $fc_trigger_price ) {\
        return(sprintf("%02d:00",$loop_hour)) ;;\
      }\
    } # end  for loop_hour\
\
  return("null");;\
},\
\
fc0_trigger_stop:fc0_trigger_start.* {\
  my $fc = 0;;\
  my $loop_hour = 0;;\
  my $fc_trigger_price = ReadingsVal("$NAME","fc".$fc."_trigger_price",0) /100;;\
\
  # Ermitteln des nächsten Trigger Fensters\
  my $fc_trigger_start = ReadingsVal("$NAME","fc0_trigger_start","null");;\
  my $fc_trigger_stop = $fc_trigger_start;;\
\
  if ( $fc_trigger_start ne "null" ) {\
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\
    my $fc_total = 0;;\
\
    for ($loop_hour = $fc_trigger_start;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc".$fc."_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total < $fc_trigger_price ) {\
        $fc_trigger_stop = sprintf("%02d:00",$loop_hour) ;;\
      } else {\
        return(sprintf("%02d:00",$loop_hour));;\
      }\
\
     # wechsel zum nächsten Tag\
     if ( $loop_hour == 23 and $fc == 0 ) {\
       $fc = 1;;\
       $loop_hour = -1;;\
     }\
\
    } # end for loop_hour\
  }\
 \
  return($fc_trigger_stop);;\
},\
\
fc0_trigger:fc0_trigger_stop.* {\
\
  # Setzen des Triggers für die aktuelle Stunde\
  if ( ReadingsVal("$NAME","current_price",100)  < ReadingsVal("$NAME","fc0_trigger_price",0) ) {\
    return("on")\
  } else {\
    return("off")\
  }\
},\
\
total_cost_day:nodes_TIMESTAMP.* {\
## Berechnung des Tages Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
total_cost_month:nodes_TIMESTAMP.* {\
## Berechnung des monats Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND YEAR(TIMESTAMP) = YEAR(curdate())\
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;") ;;\
},\
\
total_cost_year:nodes_TIMESTAMP.* {\
## Berechnung des Jahres Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;") ;;\
},\
\
fc_DbLog:fc0_00_total.* {\
my ($timestamp,$date,$hour,$value) = 4x0;;\
\
for (my $loop_fc = 0;; $loop_fc <= 1;; $loop_fc++) {\
  $date = ReadingsVal("$NAME","fc".$loop_fc."_00_startsAt","null");;\
  $date =~ /([\d+-]+)/;; $date = $1 ;;\
  for (my $loop_hour = 0;; $loop_hour <= 23;; $loop_hour++) {\
    $hour = sprintf("%02d",$loop_hour);;\
    $timestamp = $date." ".$hour.":00:00";;\
    $value = ReadingsVal("$NAME","fc".$loop_fc."_".$hour."_total","null");;\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
                      INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                        VALUES('".$timestamp."','$NAME','Tibber','fc".$loop_fc."_total','".$value."')\
                      ON DUPLICATE KEY UPDATE\
                        VALUE='".$value."';;") ;;\
  }\
}\
ReadingsTimestamp("$NAME","fc0_00_startsAt","null");;\
}
attr EVU_Tibber_connect verbose 0

setstate EVU_Tibber_connect 2023-04-21 12:00:00 compensation_grid 0.0
setstate EVU_Tibber_connect 2023-04-21 12:00:00 homeID 96a14971-525a-4420-aae9-e5aedaa129ff
setstate EVU_Tibber_connect 2023-04-21 12:00:00 token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE

stateFormat für EVO_Tibber_connect (kein RAW) wer kein EVU_Tibber DOIF haben möchte.
Also nochmal, das EVU_Tibber übernimmt den Status und die Steuerung, weshalb die EVU_Tibber_connect kein stateFormat mehr haben.
{
 my $DUMMY  = "";
 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1 ;
 my $DEVICE            = "EVU_Tibber_connect";

 my $YearBefore      = "LogDBRep_Statistic_previous_Year";
 my $YearPrevious    = ReadingsTimestamp("$YearBefore",$DEVICE."_nodes_consumption_year","null");
   $YearPrevious = ($YearPrevious ne "null") ? POSIX::strftime("%Y",localtime(time_str2num(ReadingsTimestamp("$YearBefore",$DEVICE."_nodes_consumption_year","null")))) : "null";

 my $MonthBefore      = "LogDBRep_Statistic_previous_Month";
 my $MonthPrevious    = ReadingsTimestamp("$MonthBefore",$DEVICE."_nodes_consumption_month","null");
   $YearPrevious = ($YearPrevious ne "null") ? POSIX::strftime("%Y",localtime(time_str2num(ReadingsTimestamp("$YearBefore",$DEVICE."_nodes_consumption_month","null")))) : "null";

 
 my $date  = ReadingsVal($DEVICE,"current_date",0);
 my (@price4h) = (0) x 5 ;

 $price4h[0] = ReadingsVal($DEVICE,"current_price",0);
 $price4h[0] = ( ReadingsVal($DEVICE,"fc0_trigger","off") eq "on" ) ?
       "<span style='color:green'>".$price4h[0]."</span>" :
       "<span style='color:red'>".$price4h[0]."</span>" ;
 $price4h[0] .= " ct/kWh";

 for (my $loop_hour = 1;$loop_hour <= 4;$loop_hour++) {
   $price4h[$loop_hour] = round(ReadingsVal($DEVICE,"fc0_".sprintf("%02d",$loop_hour+$hour)."_total",0)*100,1);
   $price4h[$loop_hour] = ( ReadingsVal($DEVICE,"fc0_trigger_price","0") > $price4h[$loop_hour] ) ?
         "<span style='color:green'>".$price4h[$loop_hour]."</span>" :
         "<span style='color:red'>$price4h[$loop_hour]</span>" ;
   $price4h[$loop_hour] = sprintf("%02d",$loop_hour+$hour)." :  ".$price4h[$loop_hour] ;
 }

  my $evu_act = sprintf("%04d W",ReadingsVal($DEVICE,"Pulse_P_act",0));
  my $evu_act_prod = sprintf("%04d W",ReadingsVal($DEVICE,"Pulse_P_act_Prod",0));

  my $evu_ed = sprintf("%04d",ReadingsVal($DEVICE,"nodes_consumption_day",0));

  my $evu_em = sprintf("%04d",ReadingsVal($DEVICE,"nodes_consumption_month",0));
    $evu_em .= ($MonthPrevious ne "null") ? sprintf(" / %04d", ReadingsVal("$MonthBefore",$DEVICE."_nodes_consumption_month",0) ) : "";

  my $evu_ey = sprintf("%05d",ReadingsVal($DEVICE,"nodes_consumption_year",0));



  my $evu_accumulated_production = ReadingsVal($DEVICE,"Pulse_accumulatedProduction",0)." kWh";
  my $evu_accumulated_consumption = ReadingsVal($DEVICE,"Pulse_accumulatedConsumption",0)." kWh";

 my $fc0_avg = ReadingsVal($DEVICE,"fc0_avg",0)." avg";
 my $fc0_min = ReadingsVal($DEVICE,"fc0_min",0)." min";
 my $fc0_max = ReadingsVal($DEVICE,"fc0_max",0)." max";

 my $trigger = (    ReadingsVal($DEVICE,"fc0_min",0) > ReadingsVal($DEVICE,"fc0_trigger_price",0)
                       or ReadingsVal($DEVICE,"fc0_trigger_start","") eq "null" ) ?
            "<span style='color:red'>Heute kein Trigger <br>mehr unter ".
                 ReadingsVal($DEVICE,"fc0_trigger_price","null")." ct</span>" :
            "<span style='color:green'>Trigger von<br>".
            ReadingsVal($DEVICE,"fc0_trigger_start","00:00")." bis ".ReadingsVal($DEVICE,"fc0_trigger_stop","00:00")."<br>unter ".
                 ReadingsVal($DEVICE,"fc0_trigger_price","null")." ct</span>" ;

 my $total_cost_day = ReadingsVal($DEVICE,"total_cost_day",0)." €";
 my $total_cost_month = ReadingsVal($DEVICE,"total_cost_month",0)." €";
 my $total_cost_year = ReadingsVal($DEVICE,"total_cost_year",0)." €";

"<html><table border=2 bordercolor='darkgreen' cellspacing=0 style='width: 100%'>
 <colgroup>
   <col span='1' style='width: 52%;'>
   <col span='1' style='width: 12%;'>
   <col span='1' style='width: 12%;'>
   <col span='1' style='width: 12%;'>
   <col span='1' style='width: 12%;'>
 </colgroup>
 <tr><td style='padding-right:5px;padding-left:5px;font-weight:bold'>Statistik ".$date." in kWh</td><td style='padding-right:5px;padding-left:5px;font-weight:bold;text-align:center'>aktuell</td><td style='padding-right:5px;padding-left:5px;font-weight:bold;text-align:center'>Heute</td><td style='padding-right:5px;padding-left:5px;font-weight:bold;text-align:center'>Monat".(($MonthPrevious ne "null") ? " / Vormonat" : "")."</td><td style='padding-right:5px;padding-left:5px;font-weight:bold;text-align:center'>Jahr</td></tr>

 <tr><td style='padding-right:5px;padding-left:5px;text-align:left;font-weight:bold'>Bezug vom Netz</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$evu_act."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$evu_ed."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$evu_em."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$evu_ey."</td></tr>
 <tr><td style='padding-right:5px;padding-left:5px;text-align:left;font-weight:bold'>Einspeisung ins Netz</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$evu_act_prod."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$DUMMY."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$DUMMY."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$DUMMY."</td></tr>

 <tr><td style='padding-right:5px;padding-left:5px;text-align:left;font-weight:bold'>Strom<dd>Preis / Kosten </dd></td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$price4h[0]."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$total_cost_day."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$total_cost_month."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$total_cost_year."</td></tr>
 <tr><td style='padding-right:5px;padding-left:5px;text-align:left;font-weight:bold'>Strompreis<dd>nächste 3h / Statistik fc0 / Trigger</dd></td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$price4h[1]."<br>".$price4h[2]."<br>".$price4h[3]."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$fc0_max."<br>".$fc0_avg."<br>".$fc0_min."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$trigger."</td><td style='padding-right:5px;padding-left:5px;text-align:center'>".$DUMMY."</td></tr>
 </table></html>"
}
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

#74
UPDATE 20230421 12:00 Teil 4

5.2) EVU_Tibber_connect als MQTT mit Tibber Pulse und Node-Red
  Dieses Device empfängt mit MQTT die Tibber Informationen vom Node-Red. Im Node-Red Flow "Tibber" sind einige Nodes zu konfigurieren.
 
  - homeID
  - token
  - Scheduling
  - Aktivieren "tibber/05_consumption_hourly_100" oder "tibber/05_consumption_hourly_history_MySQL"
  - Aktivieren "tibber-feed" für den Tibber Pulse stream
  - Der stream sendes sekündlich Messwerte, die auf 1/30s gebremst werden. Dies kann im Tibber Flow eingestellt werden.
 
  - Durch inject lassen sich die Abfragen manuell starten
  - Insbesondere ein inject "00_consumption_hourly_10000" bietet die Möglichkeit historische Massendaten abzuholen,
    dafür sollte man dann aber im "mqtt out" die Ausgabe "tibber/05_consumption_hourly_history_MySQL" aktivieren,
    was im FHEM ein reading mit einem MySQL INSERT erzeugt. Das kann über eine MySQL Session (manuell) die Daten in die Datenbank schreiben.
 
defmod EVU_Tibber_connect MQTT2_DEVICE Tibber_Pulse
attr EVU_Tibber_connect DbLogExclude .*
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*
attr EVU_Tibber_connect IODev MQTT2_FHEM_Server
attr EVU_Tibber_connect alias EVU_Tibber_connect
attr EVU_Tibber_connect comment Version 2023.04.21 12:00 \
https://developer.tibber.com/explorer\
\
Dieses Device verwendet einen Node-Red Flow, in dem die homeID und das token eingetragen werden muss.\
\
homeID 96a14971-525a-4420-aae9-e5aedaa129ff\
token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE\
\
Die folgenden Abfragen werden bereits zyklisch im Flow getriggert:\
  01_priceInfo         1/h um 2 Minuten nach\
  02_priceAll          0 und 14 Uhr um 5 Minuten nach\
  03_consumption_hour  alle 15 Minuten\
\
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\
setreading EVU_Tibber_connect compensation_grid <Eure Einspeisevergütung>\
\
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\
    (fc0_avg - fc0_min)  /2 + fc0_min\
\
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\
    (fc0_avg - compensation_grid) *0.85
attr EVU_Tibber_connect devicetopic tibber
attr EVU_Tibber_connect group PV Steuerung EVU
attr EVU_Tibber_connect icon stromzaehler_icon
attr EVU_Tibber_connect readingList $DEVICETOPIC/pulse:.* { json2nameValue($EVENT) }\
\
$DEVICETOPIC/01_priceInfo:.* { json2nameValue($EVENT) }\
$DEVICETOPIC/02_priceAll:.* { json2nameValue($EVENT) }\
$DEVICETOPIC/03_consumption_hour:.* { json2nameValue($EVENT) }\
$DEVICETOPIC/04_consumption_hourly_24:.* { json2nameValue($EVENT) }\
$DEVICETOPIC/05_consumption_hourly_100:.* consumption_hourly_100\
$DEVICETOPIC/05_consumption_hourly_history_MySQL:.* consumption_hourly_history_MySQL\
$DEVICETOPIC/06_address:.* { json2nameValue($EVENT) }\
$DEVICETOPIC/07_realTimeConsumptionEnabled:.* { json2nameValue($EVENT) }\
\

attr EVU_Tibber_connect room Strom->Photovoltaik
attr EVU_Tibber_connect setList 01_priceInfo req/$DEVICETOPIC/01_priceInfo {viewer {homes { currentSubscription {priceInfo {current {total startsAt level}}}  }}}\
02_priceAll req/$DEVICETOPIC/02_priceAll {viewer {homes { currentSubscription { priceInfo {current {total startsAt level} today {total startsAt level} tomorrow {total startsAt level}}}  }}}\
03_consumption_hour req/$DEVICETOPIC/03_consumption_hour {viewer {homes {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }} }}}\
04_consumption_hourly_24 req/$DEVICETOPIC/04_consumption_hourly_24 {viewer {homes { consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption }}  }}}\
05_consumption_hourly_100 req/$DEVICETOPIC/05_consumption_hourly_100 {viewer {homes { consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption }}  }}}\
06_address req/$DEVICETOPIC/06_address {viewer {homes { id address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}  }}\
07_realTimeConsumptionEnabled req/$DEVICETOPIC/07_realTimeConsumptionEnabled {viewer {homes { id features{realTimeConsumptionEnabled}}  }}\

attr EVU_Tibber_connect sortby 314
attr EVU_Tibber_connect userReadings nodes_TIMESTAMP:nodes_00_00_cost.* {\
my ($timestamp,$value) = 2x0;;\
my $tmp = 0;;\
\
for (my $loop_last = 0;; $loop_last <= 2;; $loop_last++) {\
  $timestamp = ReadingsVal("$NAME","nodes_00_".sprintf("%02d",$loop_last)."_from","null");;\
  $value = ReadingsVal("$NAME","nodes_".sprintf("%02d",$loop_last)."_cost","null");;\
\
  if ( $value ne "null" ) {\
    # Eintragen der Kosten für die Stunde\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_cost','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
    # Eintragen des Verbrauchs für die Stunde\
    $value = ReadingsVal("$NAME","nodes_00_".$loop_last."_consumption","null");;\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_consumption','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
  } else {\
    $tmp = "null";;\
  }\
} # end for\
if ($tmp eq "null") {\
  $timestamp = $tmp\
}\
$timestamp;;\
},\
\
nodes_TIMESTAMP:nodes_24_00_cost.* {\
my ($timestamp,$value) = 2x0;;\
my $tmp = 0;;\
\
for (my $loop_last = 0;; $loop_last <= 23;; $loop_last++) {\
  $timestamp = ReadingsVal("$NAME","nodes_24_".sprintf("%02d",$loop_last)."_from","null");;\
  $value = ReadingsVal("$NAME","nodes_24_".sprintf("%02d",$loop_last)."_cost","null");;\
\
  if ( $value ne "null" ) {\
    # Eintragen der Kosten für die Stunde\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_cost','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
    # Eintragen des Verbrauchs für die Stunde\
    $value = ReadingsVal("$NAME","nodes_24_".sprintf("%02d",$loop_last)."_consumption","null");;\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_consumption','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
  } else {\
    $tmp = "null";;\
  }\
} # end for\
if ($tmp eq "null") {\
  $timestamp = $tmp\
}\
$timestamp;;\
},\
\
nodes_cost_avg:nodes_TIMESTAMP.* {\
## Berechnung des Tages Wertes\
  if ( ReadingsVal("$NAME","nodes_TIMESTAMP","null") ne "null" ) {\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND TIMESTAMP >= curdate() ;;") ;;\
  } else {\
    ReadingsVal("$NAME","nodes_cost_avg","null")\
  }\
},\
\
nodes_cost_min:nodes_TIMESTAMP.* {\
##  Ermittlung des minimal Wertes\
if ( ReadingsVal("$NAME","nodes_TIMESTAMP","null") ne "null" ) {\
  ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND TIMESTAMP >= curdate() ;;") ;;\
} else {\
  ReadingsVal("$NAME","nodes_cost_min","null")\
}\
},\
\
nodes_cost_max:nodes_TIMESTAMP.* {\
## Ermittlung des maximal Wertes\
  if ( ReadingsVal("$NAME","nodes_TIMESTAMP","null") ne "null" ) {\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND TIMESTAMP >= curdate() ;;") ;;\
  } else {\
    ReadingsVal("$NAME","nodes_cost_max","null")\
  }\
},\
\
nodes_consumption_day:nodes_TIMESTAMP.* {\
## Berechnung des Tages Verbrauches\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_consumption'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
nodes_consumption_month:nodes_TIMESTAMP.* {\
## Berechnung des Monats Verbrauches\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_consumption'\
             AND YEAR(TIMESTAMP) = YEAR(curdate())\
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;") ;;\
},\
\
nodes_consumption_year:nodes_TIMESTAMP.* {\
## Berechnung des Jahres Verbrauches\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_consumption'\
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;") ;;\
},\
\
fc0_avg:current_price.* {\
## Berechnung des Tages Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='fc0_total'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
fc0_min:current_price.* {\
##  Ermittlung des minimal Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='fc0_total'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
fc0_max:current_price.* {\
## Ermittlung des maximal Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='fc0_total'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
fc0_trigger_price:[fc0_avg|compensation_grid].* {\
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\
my $price_level = round( (ReadingsVal("$NAME","fc0_avg",0) - ReadingsVal("$NAME","fc0_min",0))/2 + ReadingsVal("$NAME","fc0_min",0) , 1);;\
\
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\
if ( ReadingsVal("$NAME","compensation_grid",0) != 0 ) {\
  my $price_level_battery = round( (ReadingsVal("$NAME","fc0_avg",0) - ReadingsVal("$NAME","compensation_grid",0)) *0.85 , 1) ;;\
  if ( $price_level > $price_level_battery ) {\
    $price_level = $price_level_battery\
  }\
}\
$price_level;;\
},\
\
fc0_trigger_start:fc0_trigger_price.* {\
  my $fc = 0;;\
  my $fc_trigger_price = ReadingsVal("$NAME","fc".$fc."_trigger_price",0) /100;;\
\
  # Ermitteln des nächsten Trigger Fensters\
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\
  my $fc_total = 0;;\
\
    for (my $loop_hour = $hour;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc".$fc."_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total < $fc_trigger_price ) {\
        return(sprintf("%02d:00",$loop_hour)) ;;\
      }\
    } # end  for loop_hour\
\
  return("null");;\
},\
\
fc0_trigger_stop:fc0_trigger_start.* {\
  my $fc = 0;;\
  my $loop_hour = 0;;\
  my $fc_trigger_price = ReadingsVal("$NAME","fc".$fc."_trigger_price",0) /100;;\
\
  # Ermitteln des nächsten Trigger Fensters\
  my $fc_trigger_start = ReadingsVal("$NAME","fc0_trigger_start","null");;\
  my $fc_trigger_stop = $fc_trigger_start;;\
\
  if ( $fc_trigger_start ne "null" ) {\
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\
    my $fc_total = 0;;\
\
    for ($loop_hour = $fc_trigger_start;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc".$fc."_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total < $fc_trigger_price ) {\
        $fc_trigger_stop = sprintf("%02d:00",$loop_hour) ;;\
      } else {\
        return(sprintf("%02d:00",$loop_hour));;\
      }\
\
     # wechsel zum nächsten Tag\
     if ( $loop_hour == 23 and $fc == 0 ) {\
       $fc = 1;;\
       $loop_hour = -1;;\
     }\
\
    } # end for loop_hour\
  }\
 \
  return($fc_trigger_stop);;\
},\
\
fc0_trigger:fc0_trigger_stop.* {\
\
  # Setzen des Triggers für die aktuelle Stunde\
  if ( ReadingsVal("$NAME","current_price",100)  < ReadingsVal("$NAME","fc0_trigger_price",0) ) {\
    return("on")\
  } else {\
    return("off")\
  }\
},\
\
total_cost_day:nodes_TIMESTAMP.* {\
## Berechnung des Tages Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
total_cost_month:nodes_TIMESTAMP.* {\
## Berechnung des monats Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND YEAR(TIMESTAMP) = YEAR(curdate())\
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;") ;;\
},\
\
total_cost_year:nodes_TIMESTAMP.* {\
## Berechnung des Jahres Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;") ;;\
},\
\
fc_DbLog:fc0_00_total.* {\
my ($timestamp,$date,$hour,$value) = 4x0;;\
\
for (my $loop_fc = 0;; $loop_fc <= 1;; $loop_fc++) {\
  $date = ReadingsVal("$NAME","fc".$loop_fc."_00_startsAt","null");;\
  $date =~ /([\d+-]+)/;; $date = $1 ;;\
  for (my $loop_hour = 0;; $loop_hour <= 23;; $loop_hour++) {\
    $hour = sprintf("%02d",$loop_hour);;\
    $timestamp = $date." ".$hour.":00:00";;\
    $value = ReadingsVal("$NAME","fc".$loop_fc."_".$hour."_total","null");;\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
                      INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                        VALUES('".$timestamp."','$NAME','Tibber','fc".$loop_fc."_total','".$value."')\
                      ON DUPLICATE KEY UPDATE\
                        VALUE='".$value."';;") ;;\
  }\
}\
ReadingsTimestamp("$NAME","fc0_00_startsAt","null");;\
}
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick