Tibber & Tibber Pulse

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

Vorheriges Thema - Nächstes Thema

ch.eick

Zitat von: tomhead am 05 Januar 2024, 23:44:06
Zitat von: jnewton957 am 03 Januar 2024, 16:29:52Komisch ist es schon.
Habe mal über die https://developer.tibber.com/explorer eine live Abfrage gemacht.

< snip >

Quasi gleiches Ergebnis. accumulatedCost": null, currency": null,

ich beobachte das mal weiter. Aktuell haben wir keinen PV Ertrag und eben 423.4 W Verbrauch.

Ist bei mir auch so, alle Werte sind vorhanden, nur accumulatedCost:null, currency:null
Ich denke, dass diese Werte gar nicht über die live Werte mit geliefert werden, denn die Kosten ergeben sich ja erst nach einer abgelaufenen Stunde. In meinem Node-Red Beispiel habe ich den live Stream als zweiten Flow implementiert, der nur die live Werte liefert. Alle anderen Werte werden über die API abgefragt. Beim live Stream habe ich noch zusätzlich eine Filterung auf z.B. alle 15 Sekunden eingerichtet, damit FHEM nicht mit sinnlos vielen Werten geflutet wird.
Bei meiner PV-Anlage werte ich auch nur alle 60 Sekunden aus um nicht die Datenbank, auf dem RPI, zu sprengen.

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

Torxgewinde

Zitat von: ch.eick am 06 Januar 2024, 09:12:29...
Ich denke, dass diese Werte gar nicht über die live Werte mit geliefert werden, denn die Kosten ergeben sich ja erst nach einer abgelaufenen Stunde.
...
Ne, bei meinem echten Daten zählt der brav meine Tagessumme wie auch in der App mit. Es ist eher die App die da "stottert" und ab und zu ewig braucht um die Live-Werte anzuzeigen.

Zitat von: ch.eick am 06 Januar 2024, 09:12:29...
In meinem Node-Red Beispiel habe ich den live Stream als zweiten Flow implementiert, der nur die live Werte liefert. Alle anderen Werte werden über die API abgefragt. Beim live Stream habe ich noch zusätzlich eine Filterung auf z.B. alle 15 Sekunden eingerichtet, damit FHEM nicht mit sinnlos vielen Werten geflutet wird.
...
Jein, der Pulse liefert real ca. alle fünf Sekunden einen frischen Wert. Die Websocket stottert dann mit einem ziemlichem Jitter die Werte zurück, aber in ähnlichen Intervallen. Ggf. macht es aber tatsächlich Sinn die Readings nochmal in ihrer Rate zu begrenzen, z.B. mit "attr Tibber.ws event-on-change-reading .*" etc. An Perfomanceprobleme stoße ich allerdings trotz geringer Rechenleistung des Servers nicht.

Torxgewinde

Hier einmal eine Liste welche Werte bei mir kommen und welche nicht. Die Werte habe ich mit einfachen Zahlenfolgen ersetzt, aber nur dort wo ich echte Werte hatte. Heute war kein PV-Ertrag, deswegen macht es Sinn dass der auf 0 steht:

{"id":"TorxgewindeID","type":"next","payload":{"data":{"liveMeasurement":{"timestamp":"2024-01-06T17:24:35.000+01:00","power":1234,"lastMeterConsumption":1234.5678,"accumulatedConsumption":1.234,"accumulatedProduction":0,"accumulatedProductionLastHour":0,"accumulatedCost":2.613382,"accumulatedReward":null,"currency":"EUR","minPower":117,"averagePower":496.3,"maxPower":6373,"powerProduction":0,"powerReactive":null,"powerProductionReactive":null,"minPowerProduction":0,"maxPowerProduction":0,"lastMeterProduction":1234.5678,"powerFactor":null,"voltagePhase1":218,"voltagePhase2":220.5,"voltagePhase3":219.5,"signalStrength":null}}}}

tomhead

Hier die Liste meiner Werte:
{"id":"TomID","type":"next","payload":{"data":{"liveMeasurement":{"timestamp":"2024-01-06T18:24:25.000+01:00","power":1277,"lastMeterConsumption":9311.8,"accumulatedConsumption":11.6,"accumulatedProduction":0,"accumulatedProductionLastHour":0,"accumulatedCost":null,"accumulatedReward":null,"currency":null,"minPower":0,"averagePower":630.1,"maxPower":4997,"powerProduction":0,"powerReactive":null,"powerProductionReactive":null,"minPowerProduction":0,"maxPowerProduction":6,"lastMeterProduction":3762.1,"powerFactor":null,"voltagePhase1":226.4,"voltagePhase2":227.5,"voltagePhase3":229.2,"signalStrength":null}}}}

tomhead

So, seit heute kommen bei mir nun auch die Daten zu "accumulatedCost" und "currency".
@Torxgewinde: wie kann ich denn einstellen, dass z.B. nur alle 5 Minuten die Daten abgefragt werden?
VG, Tom

ch.eick

Zitat von: Torxgewinde am 04 Januar 2024, 18:31:22Hier die aktuelle Version der "liveMeasurements" via Websocket. Die homeId und der token sind funktionale Demo-Werte von
< snip >
connect:wert:.connect {
    my $hash = $defs{$name};
    my $devState = DevIo_IsOpen($hash);
    return "Device already open" if (defined($devState));
   
    $hash->{DeviceName} = AttrVal($name, "websocketURL", "wss:echo.websocket.org:443");
   
    # special headers needed for Tibber, see also Developer Tools in Browser
    $hash->{header}{'Sec-WebSocket-Protocol'} = 'graphql-transport-ws';
    $hash->{header}{'Host'} = 'websocket-api.tibber.com';
    $hash->{header}{'Origin'} = 'https://developer.tibber.com';
   
    # callback function when "select" signals data for us
    # websocket Ping/Pongs are treated in DevIo but still call this function
    $hash->{directReadFn} = sub () {
        my $hash = $defs{$name};
        readingsBeginUpdate($hash);
       
        # we can read without closing the DevIo, because select signalled data
        my $buf = DevIo_SimpleRead($hash);
       
        if(!defined($buf)) {
            DevIo_CloseDev($hash);
            $buf = "not_connected";
        }
       
        #Log(1, "$name:$reading: websocket data: >>>$buf<<<");
       
        # only update our reading if buffer is not empty
        readingsBulkUpdate($hash, "websocketData", "$buf") if ($buf ne "");
        readingsEndUpdate($hash, 1);
    };
   
    # open DevIo websocket
    DevIo_OpenDev($hash, 0, undef, sub(){
        my ($hash, $error) = @_;
        return "$error" if ($error);
       
        my $token = AttrVal($name, "token", "???");
       
        DevIo_SimpleWrite($hash, '{"type":"connection_init","payload":{"token":"'.$token.'"}}', 2);
    });
       
    return POSIX::strftime("%H:%M:%S",localtime(time()));
},
< snip >
Moin,
ich habe dann jetzt auch mal das liveMeasurement ausprobiert und hätte da schon einen Wunsch. In dem oben gelisteten Code Stück wird ja der WebSocket gelesen und nur bei Änderungen in die readings geschrieben.
Zitat von: tomhead am 09 Januar 2024, 23:19:42@Torxgewinde: wie kann ich denn einstellen, dass z.B. nur alle 5 Minuten die Daten abgefragt werden?
Könnte man da noch ein Attribut abfragen, dass eine Zeit in Sekunden beinhaltet, um die Abfrage zu verzögern/verlangsamen?
In meinem Fall frage ich z.B. Zähler und die PV-Anlage nur im 60 Sekunden Takt ab, was mit beim EVU Zähler auch reichen würde. Dadurch verringere ich die Anzahl der Events im FHEM und natürlich auch das Logging in die DbLog.
Auch wenn man den Datenverkehr auf dem WebSocket nicht verlangsamen kann, könnte man das setzen der readings verringern und einfach einige Werte verschlucken :-)

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

Torxgewinde

Zitat von: ch.eick am 10 Januar 2024, 10:04:42Könnte man da noch ein Attribut abfragen, dass eine Zeit in Sekunden beinhaltet, um die Abfrage zu verzögern/verlangsamen?
...
Auch wenn man den Datenverkehr auf dem WebSocket nicht verlangsamen kann, könnte man das setzen der readings verringern und einfach einige Werte verschlucken :-)
Jupp, das ist technisch korrekt, die Websocket liefert einfach was und wann sie liefert, aber man könnte "skippen" wenn nicht mindestens XX Sekunden vergangen sind. Ich guck mal wann ich dazu kommen kann, dauert ne Weile da ich gerade wieder recht busy bin... Wer da zwischenzeitlich dran möchte ist herzlich eingeladen es vor mir zu machen...

ch.eick

#187
Zitat von: Torxgewinde am 10 Januar 2024, 18:24:14Jupp, das ist technisch korrekt, die Websocket liefert einfach was und wann sie liefert, aber man könnte "skippen" wenn nicht mindestens XX Sekunden vergangen sind. Ich guck mal wann ich dazu kommen kann, dauert ne Weile da ich gerade wieder recht busy bin... Wer da zwischenzeitlich dran möchte ist herzlich eingeladen es vor mir zu machen...
Welches der Statements müsste ich den mit der Zeit überspringen?
Könnte es diese stelle sein?
        # we can read without closing the DevIo, because select signalled data
        my $buf = DevIo_SimpleRead($hash);

Ich habe das Dummy Device bei mir schon mal direkt in das HTTPMOD mit eingebaut, damit später nur ein Device für EVU_Tibber_connect notwendig ist.
Das scheint sogar zu funktionieren, dass man die HTTPMOD abfragen tätigt und wärend dessen der WebSocket die liveMeasurement aktualisiert.
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

KölnSolar

ZitatWer da zwischenzeitlich dran möchte ist herzlich eingeladen es vor mir zu machen...
Nicht wirklich. 8)
Aber vielleicht kann Dir das OBIS-Modul helfen, da es vergleichbares bietet.
Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

ch.eick

Zitat von: KölnSolar am 10 Januar 2024, 19:09:31Aber vielleicht kann Dir das OBIS-Modul helfen, da es vergleichbares bietet.
Hallo Markus,
das übersteigt etwas meine Perl Kenntnisse. Im OBIS Modul habe ich keine Stelle gefunden, die zeitabhängig etwas überspringen würde.
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

Torxgewinde

Hi, müsste eigentlich schon so gehen (hier begrenzt auf mindestens 60 Sekunden Pausen nach jedem Update):

defmod Tibber.ws dummy
attr Tibber.ws userattr websocketURL homeId token myId minInterval
attr Tibber.ws alias Tibber Websocket
attr Tibber.ws event-on-change-reading .*
attr Tibber.ws eventMap /wert connect:start/wert disconnect:stop/
attr Tibber.ws homeId 96a14971-525a-4420-aae9-e5aedaa129ff
attr Tibber.ws icon hue_filled_plug
attr Tibber.ws minInterval 60
attr Tibber.ws myId TorxgewindeID
attr Tibber.ws readingList wert
attr Tibber.ws room Power
attr Tibber.ws setList wert
attr Tibber.ws stateFormat payload_data_liveMeasurement_accumulatedCost payload_data_liveMeasurement_currency (payload_data_liveMeasurement_power W, Import: payload_data_liveMeasurement_accumulatedConsumption kWh, Export: payload_data_liveMeasurement_accumulatedProduction kWh)
attr Tibber.ws token 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE
attr Tibber.ws userReadings connect:wert:.connect {\
    my $hash = $defs{$name};;\
    my $devState = DevIo_IsOpen($hash);;\
    return "Device already open" if (defined($devState));;\
    \
    $hash->{DeviceName} = AttrVal($name, "websocketURL", "wss:echo.websocket.org:443");;\
    \
    # special headers needed for Tibber, see also Developer Tools in Browser\
    $hash->{header}{'Sec-WebSocket-Protocol'} = 'graphql-transport-ws';;\
    $hash->{header}{'Host'} = 'websocket-api.tibber.com';;\
    $hash->{header}{'Origin'} = 'https://developer.tibber.com';;\
    \
    # callback function when "select" signals data for us\
    # websocket Ping/Pongs are treated in DevIo but still call this function\
    $hash->{directReadFn} = sub () {\
        my $hash = $defs{$name};;\
        \
        # we can read without closing the DevIo, because select signalled data\
        my $buf = DevIo_SimpleRead($hash);;\
        \
        if(!defined($buf)) {\
            DevIo_CloseDev($hash);;\
            $buf = "not_connected";;\
        }\
        \
        #Log(1, "$name:$reading: websocket data: >>>$buf<<<");;\
        \
        # only update our reading if buffer is not empty and if last update is older than minInterval\
        my $websocketDataAge = ReadingsAge($name, "websocketData", 3600);;\
        my $minInterval = AttrVal($name, "minInterval", 0);;\
        if ($buf ne "") {\
            my $isNext = ($buf =~ /{"id":".*","type":"next","payload":{"data":{"liveMeasurement":.*}/s);;\
            \
            readingsBeginUpdate($hash);;\
            if ($isNext && $websocketDataAge > $minInterval) {\
                readingsBulkUpdate($hash, "websocketData", "$buf");;\
            } elsif (!$isNext) {\
                readingsBulkUpdate($hash, "websocketData", "$buf");;\
            }\
            readingsEndUpdate($hash, 1);;\
        }\
    };;\
    \
    # open DevIo websocket\
    DevIo_OpenDev($hash, 0, undef, sub(){\
        my ($hash, $error) = @_;;\
        return "$error" if ($error);;\
        \
        my $token = AttrVal($name, "token", "???");;\
        \
        DevIo_SimpleWrite($hash, '{"type":"connection_init","payload":{"token":"'.$token.'"}}', 2);;\
    });;\
        \
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
disconnect:wert:.disconnect {\
    my $hash = $defs{$name};;\
    RemoveInternalTimer($hash);;\
    DevIo_SimpleRead($hash);;\
    DevIo_CloseDev($hash);;\
    \
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
onDisconnect {\
    my $myState = ReadingsVal($name, "state", "???");;\
    my $myData = ReadingsVal($name, "websocketData", "???");;\
    return if ($myState ne "disconnected" and $myData ne "not_connected");;\
    \
    ## timer callback function, called after a few seconds to initiate a reconnect\
    my $timerFunction = sub() {\
        my ($hash) = @_;;\
        my $devState = DevIo_IsOpen($hash);;\
        readingsSingleUpdate($hash, "wert", "connect", 1) if (!defined($devState));;;;\
    };;\
    my $hash = $defs{$name};;\
    RemoveInternalTimer($hash, $timerFunction);;\
    \
    # wait a random time before reconnect (exponential backoff TBD):\
    my $rwait = int(rand(200)) + 30;;\
    InternalTimer(gettimeofday() + $rwait, $timerFunction, $hash);;\
    readingsBulkUpdate($hash, "wert", "reconnect attempt in $rwait seconds");;\
    \
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
onConnectionAck:websocketData:.*connection_ack.* {\
    Log(1, "$name:$reading: got connection ack");;\
    \
    my $hash = $defs{$name};;\
    my $devState = DevIo_IsOpen($hash);;\
    return "Device not open" if (!defined($devState));;\
    \
    my $homeId = AttrVal($name, "homeId", "???");;\
    my $myId = AttrVal($name, "myId", "???");;\
    \
    my $json = '{ "id":"'. $myId .'", "type":"subscribe"'.", ";;\
    $json .= '"payload":{';;\
    $json .= '"variables":{}'.", ";;\
    $json .= '"extensions":{}'.", ";;\
    $json .= '"query":"subscription { liveMeasurement( homeId: \"'.$homeId.'\" ) ';;\
    #$json .= '{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}"';;\
    $json .= '{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction ';;\
    $json .= 'accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower ';;\
    $json .= 'powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction ';;\
    $json .= 'powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}"';;\
    $json .= '}}';;\
    \
    Log(1, "$name:$reading: sending JSON: >>>$json<<<");;\
    DevIo_SimpleWrite($hash, $json, 2);;\
    \
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
onNextLiveMeasurement:websocketData:.*next.*payload.*data.*liveMeasurement.* {\
    my $val = ReadingsVal($name, "websocketData", "{}");;\
    my %res = %{json2nameValue($val, undef, undef, "payload_data_liveMeasurement.*")};;\
    \
    my $ret = "got values for:\n";;\
    foreach my $k (sort keys %res) {\
        $ret .= "$k\n";;\
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\
    }\
    return $ret;;\
}
attr Tibber.ws websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions

tomhead

Zitat von: Torxgewinde am 10 Januar 2024, 21:02:38Hi, müsste eigentlich schon so gehen (hier begrenzt auf mindestens 60 Sekunden Pausen nach jedem Update):

Vielen Dank für die schnelle Anpassung, funktioniert!

KölnSolar

Hi Christian,

Problem scheint ja gelöst, aber trotzdem zu Deiner Frage
Zitatdas übersteigt etwas meine Perl Kenntnisse. Im OBIS Modul habe ich keine Stelle gefunden, die zeitabhängig etwas überspringen würde
Im OBIS-Modul gibt es 3 entscheidende Attribute, die ich nutze, weil meine Zähler massenhaft Daten übertragen und dadurch FHEM überlastet wird.
- pollingMode - Changes from direct-read to polling-mode. Useful with meters, that send a continous datastream. Reduces CPU-load.
- interval    - The polling-interval in seconds. (Only useful in Polling-Mode)
- alignTime   - Aligns the intervals to a given time. Each interval is repeatedly calculated. So if alignTime=00:00 and interval=600 aligns the interval to xx:00:00, xx:10:00, xx:20:00 etc....

Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

ch.eick

Zitat von: KölnSolar am 11 Januar 2024, 09:56:58Hi Christian,

Problem scheint ja gelöst, aber trotzdem zu Deiner Frage
Zitatdas übersteigt etwas meine Perl Kenntnisse. Im OBIS Modul habe ich keine Stelle gefunden, die zeitabhängig etwas überspringen würde
Im OBIS-Modul gibt es 3 entscheidende Attribute, die ich nutze, weil meine Zähler massenhaft Daten übertragen und dadurch FHEM überlastet wird.
- pollingMode - Changes from direct-read to polling-mode. Useful with meters, that send a continous datastream. Reduces CPU-load.
- interval    - The polling-interval in seconds. (Only useful in Polling-Mode)
- alignTime   - Aligns the intervals to a given time. Each interval is repeatedly calculated. So if alignTime=00:00 and interval=600 aligns the interval to xx:00:00, xx:10:00, xx:20:00 etc....

Grüße Markus
Okay, danke
dann muss ich nur noch den Code dazu im Modul finden und verstehen ;-)
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

tomhead

Wie bekomme ich denn das hin, dass der Websocket bei jedem FHEM Neustart automatisch startet?  :-[