Tibber & Tibber Pulse

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

Vorheriges Thema - Nächstes Thema

ch.eick

Zitat von: MadMax am 14 Januar 2024, 19:21:53Also bist du Kunde?
Klappt das und bist du soweit zufrieden?
:-) ich bin kein Kunde, habe aber von einem Gönner einen Zugang zum Testen.
Bei mir lohnt sich Tibber nicht, da ich nur 2600 kWh/Jahr zukaufe, wo die LWP, E-Auto und das Heizen der Mietwohnung bereits mit drin sind. Ich teste bereits über ein Jahr und kann meine Geräte sehr präziese in die niedrig Preise von Tibber legen, trotzdem schaffe ich maximal eine 0€ Runde wegen der hohen Grundgebühren. Mein EVU ist momentan anscheinend unschlagbar mit 24 ct/kWh :-) Ich bin aber immer gerne vorbereitet und hatte schon bei aWATTar spaß an der Möglichkeit, bei was wäre wenn.
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

MadMax

Ich denke bei mir wird es ähnlich sein ich brauche auch nur noch 2500kWh im Jahr.
Ich habe jetzt mal den Wechselkurs hinterlegt und schaue mir das mal an.

Die Wallbox und die WP kann man ja etwas beeinflussen ;)

Danke.

Gruß
Max
Lenovo M910Q Tiny Debian 12, FHEM 6.3, 2x Siemens Logo 0BA7, Homematic CCU3, Philips HUE, 6x SMA Wechselrichter, BYD HVM, BYD HVS, SMA EVCharger, KEBA Wallbox, 2x HMS800W, Daikin Wärmepumpe über CAN, viele ESPs

Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/MadMax

ch.eick

Zitat von: MadMax am 14 Januar 2024, 19:35:04Ich denke bei mir wird es ähnlich sein ich brauche auch nur noch 2500kWh im Jahr.
Ich habe jetzt mal den Wechselkurs hinterlegt und schaue mir das mal an.
Ich denke das wird nichts, die Preise könnten auch generiert sein :-)
{"data":{"viewer":{"home":{"currentSubscription":{"priceInfo":{"current":{"total":0.2688,"startsAt":"2024-01-14T20:00:00.000+01:00"},"today":[{"total":0.2486,"startsAt":"2024-01-14T00:00:00.000+01:00"},{"total":0.2464,"startsAt":"2024-01-14T01:00:00.000+01:00"},{"total":0.2473,"startsAt":"2024-01-14T02:00:00.000+01:00"},{"total":0.2486,"startsAt":"2024-01-14T03:00:00.000+01:00"},{"total":0.2494,"startsAt":"2024-01-14T04:00:00.000+01:00"},{"total":0.25,"startsAt":"2024-01-14T05:00:00.000+01:00"},{"total":0.2525,"startsAt":"2024-01-14T06:00:00.000+01:00"},{"total":0.2577,"startsAt":"2024-01-14T07:00:00.000+01:00"},{"total":0.2638,"startsAt":"2024-01-14T08:00:00.000+01:00"},{"total":0.269,"startsAt":"2024-01-14T09:00:00.000+01:00"},{"total":0.2684,"startsAt":"2024-01-14T10:00:00.000+01:00"},{"total":0.2698,"startsAt":"2024-01-14T11:00:00.000+01:00"},{"total":0.2681,"startsAt":"2024-01-14T12:00:00.000+01:00"},{"total":0.2641,"startsAt":"2024-01-14T13:00:00.000+01:00"},{"total":0.2666,"startsAt":"2024-01-14T14:00:00.000+01:00"},{"total":0.2704,"startsAt":"2024-01-14T15:00:00.000+01:00"},{"total":0.2755,"startsAt":"2024-01-14T16:00:00.000+01:00"},{"total":0.2818,"startsAt":"2024-01-14T17:00:00.000+01:00"},{"total":0.2878,"startsAt":"2024-01-14T18:00:00.000+01:00"},{"total":0.2782,"startsAt":"2024-01-14T19:00:00.000+01:00"},{"total":0.2688,"startsAt":"2024-01-14T20:00:00.000+01:00"},{"total":0.266,"startsAt":"2024-01-14T21:00:00.000+01:00"},{"total":0.2622,"startsAt":"2024-01-14T22:00:00.000+01:00"},{"total":0.2524,"startsAt":"2024-01-14T23:00:00.000+01:00"}],"tomorrow":[{"total":0.2532,"startsAt":"2024-01-15T00:00:00.000+01:00"},{"total":0.2498,"startsAt":"2024-01-15T01:00:00.000+01:00"},{"total":0.2485,"startsAt":"2024-01-15T02:00:00.000+01:00"},{"total":0.2463,"startsAt":"2024-01-15T03:00:00.000+01:00"},{"total":0.2463,"startsAt":"2024-01-15T04:00:00.000+01:00"},{"total":0.2549,"startsAt":"2024-01-15T05:00:00.000+01:00"},{"total":0.2676,"startsAt":"2024-01-15T06:00:00.000+01:00"},{"total":0.2722,"startsAt":"2024-01-15T07:00:00.000+01:00"},{"total":0.2906,"startsAt":"2024-01-15T08:00:00.000+01:00"},{"total":0.2918,"startsAt":"2024-01-15T09:00:00.000+01:00"},{"total":0.2854,"startsAt":"2024-01-15T10:00:00.000+01:00"},{"total":0.2799,"startsAt":"2024-01-15T11:00:00.000+01:00"},{"total":0.2722,"startsAt":"2024-01-15T12:00:00.000+01:00"},{"total":0.2702,"startsAt":"2024-01-15T13:00:00.000+01:00"},{"total":0.273,"startsAt":"2024-01-15T14:00:00.000+01:00"},{"total":0.2789,"startsAt":"2024-01-15T15:00:00.000+01:00"},{"total":0.2885,"startsAt":"2024-01-15T16:00:00.000+01:00"},{"total":0.2991,"startsAt":"2024-01-15T17:00:00.000+01:00"},{"total":0.3067,"startsAt":"2024-01-15T18:00:00.000+01:00"},{"total":0.3038,"startsAt":"2024-01-15T19:00:00.000+01:00"},{"total":0.2943,"startsAt":"2024-01-15T20:00:00.000+01:00"},{"total":0.2817,"startsAt":"2024-01-15T21:00:00.000+01:00"},{"total":0.2789,"startsAt":"2024-01-15T22:00:00.000+01:00"},{"total":0.2753,"startsAt":"2024-01-15T23:00:00.000+01:00"}]}}}}}}
Hier mal ein Beispiel von heute.
fc_avg 26.92
fc_max 30.67
fc_med 26.89
fc_min 24.63     <<< das min ist schon echt gut, wenn man die letzten Wochen anschaut
fc_trigger_price 25.8

ZitatDie Wallbox und die WP kann man ja etwas beeinflussen ;)
Ich könnte den Speicher variabel laden und mein Nachbar lädt sein Auto auch bei mir. Dann kommt noch der Wirlpool dazu und selbst das alles reicht nicht um die Grundgebühr, die ja 12 Monate anfällt wieder raus zu bekommen, wenn man eine PV-Anlage hat.

Lohnen wird sich das ohne PV-Anlage, wenn man strikt nach Tibber steuert.
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

MadMax

Ja das denke ich auch.

Die Grundgebühr zahle ich 12 Montate und brauche das ganze aber nur 3-4 Monate...
Für die Grundgebühr kann man einiges an Strom kaufen.
Lenovo M910Q Tiny Debian 12, FHEM 6.3, 2x Siemens Logo 0BA7, Homematic CCU3, Philips HUE, 6x SMA Wechselrichter, BYD HVM, BYD HVS, SMA EVCharger, KEBA Wallbox, 2x HMS800W, Daikin Wärmepumpe über CAN, viele ESPs

Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/MadMax

ch.eick

Hallo zusammen,
könnte mir mal jemand Tibber Preise, so ab 2023-01-01 aus dem Raum 64xxx schicken? Ich würde liebend gerne mal meine SQL SELECT Kenntnisse ausprobieren und mit echten Daten Spielen.

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

ch.eick

#215
Hallo zusammen,
hier mal der Zwischenstand von heute.
Es gibt zwei Devices EVU_Tibber_connect und EVU_Tibber
- EVU_Tibber_connect
  - Ist ein HTTPMOD und fragt diverse Informationen ab
  - Über das userReadings ist liveMessurment im HTTPMOD mit WebSocket integriert
    - Die readings habe ich vom Namen her mit ws_* verändert
    - ws_wert dient dem Starten/Stoppen des WebSocket und wurde beim Wert auf connected/disconnected
      verändert, wodurch es im EVU_Tibber uiTable klarer zu verstehen ist
  - Die Visualisierung geschieht über das EVU_Tibber mit uiTable
- EVU_Tibber
  - Ermöglicht die Bedienung von EVU_Tibber_connect mit Drop Down Menü
  - Mit einem Button wird der Zustand des WebSocket angezeigt und ist auch bedienbar
  - Über die init() Funktion wird der WebSocket vom EVU_Tibber_connect beim Start von FHEM direkt mitgestartet
  - Die Preis von fc0 und fc1 werden in Diagrammen angezeigt
  - Aktuelle Statistiken werden als Zahlenwert angezeigt
  - Das Triggerfenster für fc0 und fc1 wird angezeigt
  - Im Bereich der Statistiken werden die liveMessurment Werte angezeigt sowie Tages/Monats/Jahres Werte
Du darfst diesen Dateianhang nicht ansehen.
Ich denke, den Stand werde ich dann in den nächsten Tagen ins Wiki stellen.
Bei meinen zu steuernden Geräten habe ich dann noch im FHEMWEB solche Blöcke im uiTable, damit man die Geräte separat auf den Tibber Trigger reagieren lassen kann.
Hier wäre der Block für die Speicher Steuerung, um dann auch die Ladestärke konfigurieren zu können.
Du darfst diesen Dateianhang nicht ansehen.

Solltet Ihr noch Ideen haben, wäre jetzt der richtige Zeitpunkt es zu äußern.
- Denkbar wären jetzt natürlich auch noch Statistiken aus der Datenbank mit Vortag/Vormonat/letztes Jahr

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

Damian

Zitat von: MadMax am 14 Januar 2024, 19:21:53Also bist du Kunde?
Klappt das und bist du soweit zufrieden?

Ich bin seit Mai Tibber-Kunde und habe mir gerade meine monatlichen Rechnungen bei Tibber Juni bis November angeschaut. Wir haben einen dynamischen Tarif, eine PV-Anlage, keinen Speicher. Die PV Anlage ist eher kontraproduktiv. Unser jährlicher Bezug lag bisher bei ca. 2200 kWh.

Die vertrauenswürdigen Anbieter für unsere Region liegen z. Zt. über 30 Cent/kWh, daher kann ich mich über die bisherigen Rechnungen von Tibber nicht beklagen.

So sahen die monatlichen Stromkosten bei uns aus:
Du darfst diesen Dateianhang nicht ansehen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

horizon

Zitat von: ch.eick am 15 Januar 2024, 17:28:35Solltet Ihr noch Ideen haben, wäre jetzt der richtige Zeitpunkt es zu äußern.

Hallo Christian,
kann man mit deinen Devices Entladesperrzeiten für den Speicher automatisch setzen?

Ich bin seit 01.01.2024 Tibber-Kunde und versuche den Strombezug zu optimieren. In der Nacht rechnet FHEM bei mir aus dem Stromverbrauch des vorherigen Tages und dem zu erwartenden Solar-Ertrag des aktuellen Tages einen prognostizierten Stromverbrauch aus. Aus dem prognostizierten Strombedarf wird die Länge des Ladezeitraums berechnet und das günstigste Zeitfenster zwischen 0 und 7 Uhr bestimmt. Zur Startzeit des Ladezeitfensters lädt der Speicher auf 80% des prognostizierten Strombedarfs. Auf die Kosten für diese Ladung rechne ich 15% Verlust drauf und erhalte dann den Preis, den der Strom aus dem Speicher kostet. So lange der Tibber-Preis günstiger ist, wie der Preis des gespeicherten Stroms, wird eine Entladesperre für den Speicher gesetzt.

Mit der Automatisierung dieses Vorgangs hapert es aktuell noch und ich muss ständig manuell eingreifen. Ich weiß noch nicht, bei welchem kWh-Preis ich im Durchschnitt am Ende des Monats landen werde, aber es sieht aktuell danach aus, dass Tibber teurer sein wird, wie andere Anbieter. Die günstigeren Preise der anderen Anbieter kommen allerdings nur durch einen Durchschnittspreis über das ganze Jahr zustande, d.h. als Solaranlagenbetreiber profitiert man davon, dass andere Kunden im Sommer zu viel zahlen. Meine Tibber-Bilanz wird zusätzlich noch dadurch verhagelt, dass die Stromnebenkosten am 01.01.2024 unerwartet um 5 Cent pro kWh gestiegen sind.

Ich tendiere dazu das Experiment demnächst abzubrechen und wieder zu einem Anbieter mit fixen Preisen zu wechseln, weil der Aufwand deutlich zu hoch ist. Es ist schade, weil ich Tibber für ein faires Angebot halte.

Grüße,
Oli

ch.eick

Zitat von: horizon am 18 Januar 2024, 15:01:15
Zitat von: ch.eick am 15 Januar 2024, 17:28:35Solltet Ihr noch Ideen haben, wäre jetzt der richtige Zeitpunkt es zu äußern.

Hallo Christian,
kann man mit deinen Devices Entladesperrzeiten für den Speicher automatisch setzen?
Hallo Oli,
Das hat nicht wirklich was mit Tibber zu tun.
Ich hatte nur auch schon überlegt,  ob ich auch ein Maximum Fenster berechne, was man dann auch für das Entladen des Speichers verwenden könnte. Die Zeiten könnten dann ja als Sperrzeiten verwendet werden.

In einem DOIF lassen sich die Zeiten in den readings direkt als Timer setzen.

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

ch.eick

Zitat von: ch.eick am 18 Januar 2024, 22:16:05Hallo Oli,
Ich hatte nur auch schon überlegt, ob ich auch ein Maximum Fenster berechne, was man dann auch für das Entladen des Speichers verwenden könnte. Die Zeiten könnten dann ja als Sperrzeiten verwendet werden.

In einem DOIF lassen sich die Zeiten in den readings direkt als Timer setzen.
Hallo Oli,
ich habe da mal was zum Testen.
Diese Code Blöcke kommen zusätzlich ins userReadings. Bei mir habe ich die vor "total_cost_day:nodes_TIMESTAMP.* {" eingesetzt.
fc_trigger_max:fc_avg.* {
  my $fc_avg = ReadingsVal("$NAME","fc_avg",0);
  my $fc_max = ReadingsVal("$NAME","fc_max",0);

  # Berechnung eines Schwellwertes als täglichen Maximalpreises
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);
 
$price_level;
},

fc0_trigger_max_start:fc_trigger_max.* {
  my $fc_trigger_max = ReadingsVal("$NAME","fc_trigger_max",0) /100;

  # Ermitteln des nächsten Trigger_max 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","fc0_".sprintf("%02d",$loop_hour)."_total",0);
      if ( $fc_total > $fc_trigger_max ) {
        return(sprintf("%02d:00",$loop_hour)) ;
      }
    } # end  for loop_hour

  return("null");
},

fc0_trigger_max_stop:fc0_trigger_max_start.* {
  my $fc = 0;
  my $loop_hour = 0;
  my $fc_trigger_max = ReadingsVal("$NAME","fc_trigger_max",0) /100;

  # Ermitteln des nächsten Trigger Fensters
  my $fc_trigger_max_start = ReadingsVal("$NAME","fc0_trigger_max_start","null");
  my $fc_trigger_max_stop = $fc_trigger_max_start;

  if ( $fc_trigger_max_start ne "null" ) {
    $fc_trigger_max_start =~ /(\d\d):/; $fc_trigger_max_start = $1 ;
    my $fc_total = 0;

    for ($loop_hour = $fc_trigger_max_start; $loop_hour <= 23; $loop_hour++) {
      $fc_total = ReadingsVal("$NAME","fc".$fc."_".sprintf("%02d",$loop_hour)."_total",0);
      if ( $fc_total > $fc_trigger_max ) {
        $fc_trigger_max_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_max_stop);
},

fc0_trigger_max:fc0_trigger_max_stop.* {

  # Setzen des maximum Triggers für die aktuelle Stunde
  if ( ReadingsVal("$NAME","current_price",0)  > ReadingsVal("$NAME","fc_trigger_max",0) ) {
    return("on")
  } else {
    return("off")
  }
},

fc1_trigger_max_start:fc_trigger_max.* {
  if (ReadingsVal("$NAME","fc1_00_startsAt","null") ne "null") {
    my $fc_trigger_max = ReadingsVal("$NAME","fc_trigger_max",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 = 0; $loop_hour <= 23; $loop_hour++) {
      $fc_total = ReadingsVal("$NAME","fc1_".sprintf("%02d",$loop_hour)."_total",0);
      if ( $fc_total > $fc_trigger_max ) {
        return(sprintf("%02d:00",$loop_hour)) ;
      }
    } # end  for loop_hour
  }
  return("null");
},

fc1_trigger_max_stop:fc0_trigger_max_start.* {
  my $loop_hour = 0;
  my $fc_trigger_max = ReadingsVal("$NAME","fc_trigger_max",0) /100;

  # Ermitteln des nächsten Trigger Fensters
  my $fc_trigger_max_start = ReadingsVal("$NAME","fc1_trigger_max_start","null");
  my $fc_trigger_max_stop = $fc_trigger_max_start;

  if ( $fc_trigger_max_start ne "null" ) {
    $fc_trigger_max_start =~ /(\d\d):/; $fc_trigger_max_start = $1 ;
    my $fc_total = 0;

    for ($loop_hour = $fc_trigger_max_start; $loop_hour <= 23; $loop_hour++) {
      $fc_total = ReadingsVal("$NAME","fc1_".sprintf("%02d",$loop_hour)."_total",0);
      if ( $fc_total > $fc_trigger_max ) {
        $fc_trigger_max_stop = sprintf("%02d:00",$loop_hour) ;
      } else {
        return(sprintf("%02d:00",$loop_hour));
      }

    } # end for loop_hour
  }
 
  return($fc_trigger_max_stop);
},

Nach dem Abrufen 02_priceAll sollten dann weitere readings erscheinen, die ein Maximum Zeitfenster angeben und auch einen Trigger liefern.
Hier mal ein Beispiel von jetzt
# Für fc0 ist das Maximum bereits vorbei
fc0_trigger_max off
fc0_trigger_max_start null
fc0_trigger_max_stop null

# Für fc1 wird das Maximum von 17:00 bis 20:00 (19:59) erwartet
fc1_trigger_max_start 17:00
fc1_trigger_max_stop 20:00

# Der Maximum Preis wurde ja bereits berechnet und dazu kommt nun noch ein Schwellwert
fc_max 29.65
fc_trigger_max 28

Viel Spaß beim Testen
    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

horizon

Hallo Christian,
danke für den Code :D

Grüße,
Oli

Torxgewinde

Hallo,
Bei dem Dummy-Device für Tibber-Live-Readings via Websocket habe ich noch eine Timeout-Erkennung mit eingebaut und das Ganze in das Wiki gestellt: Wiki --> Websocket

hier auch nochmal der aktuelle Stand:
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 /cmd connect:start/cmd disconnect:stop/
attr Tibber.ws homeId 96a14971-525a-4420-aae9-e5aedaa129ff
attr Tibber.ws icon hue_filled_plug
attr Tibber.ws minInterval 30
attr Tibber.ws myId TorxgewindeID
attr Tibber.ws readingList cmd
attr Tibber.ws setList cmd
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:cmd:.connect {\
my $hash = $defs{$name};;\
my $devState = DevIo_IsOpen($hash);;\
return "Device already open" if (defined($devState));;\
\
# establish connection to websocket\
# format must also include portnumber if a path is to be specified\
$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 read fails, close device\
if(!defined($buf)) {\
DevIo_CloseDev($hash);;\
$buf = "not_connected";;\
}\
\
#Log(3, "$name:$reading: websocket data: >>>$buf<<<");;\
\
# only update our reading if buffer is not empty and if last update is older than minInterval\
if ($buf ne "") {\
my $websocketDataAge = ReadingsAge($name, "websocketData", 3600);;\
my $minInterval = AttrVal($name, "minInterval", 0);;\
my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\
\
readingsBeginUpdate($hash);;\
readingsBulkUpdate($hash, "websocketData", "$buf") if ($isNext && $websocketDataAge > $minInterval);;\
readingsBulkUpdate($hash, "websocketData", "$buf") if (!$isNext);;\
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);;\
});;\
readingsBulkUpdate($hash, "websocketData", "");;\
\
return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
disconnect:cmd:.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 ($arg) = @_;;\
my $hash = $defs{$name};;\
my $devState = DevIo_IsOpen($hash);;\
\
# only re-connect if device is not connected\
readingsSingleUpdate($hash, "cmd", "connect", 1) if (!defined($devState));;\
};;\
RemoveInternalTimer($name.$reading.'Timer');;\
\
# wait a random time before reconnect (exponential backoff TBD):\
my $rwait = int(rand(200)) + 30;;\
InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.'Timer');;\
\
#set cmd to a new value, informs user and allows to retrigger when timer expires\
my $hash = $defs{$name};;\
readingsBulkUpdate($hash, "cmd", "reconnect attempt in $rwait seconds");;\
\
return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
onTimeout:websocketData:.* {\
#re-establish websocket connection if no data received in the past ten minutes\
#but only if our reading "cmd" was not set to the value "disconnect"\
\
#timeout in seconds when the connection is considered dead\
my $timeoutTime = 600;;\
\
# function to execute when timeout expired\
# defining the function here in the userReading, allows us to insert variables directly\
my $timerFunction = sub() {\
my ($arg) = @_;;\
my $hash = $defs{$name};;\
my $rCmd = ReadingsVal($name, "cmd", "???");;\
my $age  = ReadingsAge($name, "websocketData", 0);;\
\
Log(3, "$name: onTimeoutTimer triggered >>$arg<<");;\
\
#do not do anything further if disconnect is on purpose\
if ( $rCmd eq "disconnect" ) {\
Log(3, "$name: cmd was set to disconnect");;\
return;;\
}\
\
# for whatever reason, we triggered to soon (80%)\
if ( $age < $timeoutTime*0.8 ) {\
Log(3, "$name: websocketData is not outdated");;\
return;;\
}\
\
DevIo_CloseDev($hash);;\
Log(3, "$name: onTimeoutTimer closed DevIo...");;\
\
readingsSingleUpdate($hash, "cmd", "connect", 1);;\
Log(3, "$name: onTimeoutTimer set cmd to value 'connect'");;\
};;\
\
#remove/cancel previous timers, because we got fresh data and countdown starts again\
RemoveInternalTimer($name.$reading.'Timer');;\
\
#set timer to expire and execute function defined above, give special arg as identifier\
InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.'Timer');;\
\
return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
onConnectionAck:websocketData:.*connection_ack.* {\
#websocketData contains the string "connection_ack"\
Log(3, "$name:$reading: got connection ack");;\
\
# do not proceed if connection is lost\
my $hash = $defs{$name};;\
my $devState = DevIo_IsOpen($hash);;\
return "Device not open" if (!defined($devState));;\
\
readingsBulkUpdate($hash, "cmd", "got connection ack");;\
\
my $homeId = AttrVal($name, "homeId", "???");;\
my $myId = AttrVal($name, "myId", "???");;\
\
# build the query, do it in pieces, the comma at the end caused perl errors\
# so we put it together in this not very elegant way\
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 .= '}}';;\
\
#send the string via websocket as ASCII\
Log(3, "$name:$reading: sending JSON: >>>$json<<<");;\
DevIo_SimpleWrite($hash, $json, 2);;\
\
return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
onNextLiveMeasurement:websocketData:.*next.*payload.*data.*liveMeasurement.* {\
#websocketData contains next-live-measurement-data\
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 webCmd start:stop
attr Tibber.ws websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions

ch.eick

Zitat von: Torxgewinde am 20 Januar 2024, 11:44:57Bei dem Dummy-Device für Tibber-Live-Readings via Websocket habe ich noch eine Timeout-Erkennung mit eingebaut
Okay,
ich habe das in meine HTTPMOD Version ebenfalls mit aufgenommen, muss jetzt aber leider nochmal etwas testen.
Die zusammengefassten Devices kommen dann hoffendlich diese Woche noch.

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

jnewton957

#223
Ich habe mir aus den EVU_Tibber_connect readings noch ein wenig Statistik gebaut.

Um einmal festzustellen, ob tibber nun wirtschaftlicher ist als andere EVU habe ich mir ein:
Tibber_price_avg_month und Tibber_price_avg_year erstellt.
Einfach total_cost_year / nodes_consumption_year und _month entsprechend.

Bei mir kommt aktuell 0.29 ct/kWh heraus, was inkl. der Gebühren knapp günstiger bzw. im Bereich günstiger EVU sein dürfte. Aber das wird sich ja noch ändern, wenn die eigentlichen Börsentarife noch sinken bzw. ich Verbraucher in günstigere Zeiten legen kann..

Ich habe einige devices, für die ich mit dem Modul ElectricityCalculator eine Statistik erstelle. Für die readings EnergyCostYear/EnergyCostMonth/EnergyCostDay wird das Attribut EnergyPricePerKWh verwendet.
Da sich dieser ja bei tibber stündlich verändert, kann ich nun mit einem täglichen {fhem(attr <device> ElectricityPricePerKWh <Tibber_price_avg_year>} den EnergyPricePerKWh  setzen lassen.

Da ich aber auch eine PV-Anlage (ohne Speicher) habe, stimmt ja der Preis nur wenn eben ausschließlich Bezug über tibber erfolgt. Da es aber ja das SW_Statistic_EnergyHomePv_Year gibt, habe ich mir ein EnergyPricePerKWh aus (SW_Statistic_EnergyHomePv_year * Einspeisevergütung + total_cost_year) / (nodes_consumption_year + SW_Statistic_EnergyHomePv_Year) gebaut.

So komme ich hinreichend genau auf den EnergyPricePerKWh von aktuell 0.20 ct/kWh.
FHEM6.2 auf Pi5
V 1.66 nanoCUL 433 (IT)
V 1.66 nanoCUL868 (HM)
sqlite3 LogDb
ELRO AB440, DECT200,  TFA30.3125, esp8266, HM, TabletUI, IR-Schreiblesekopf (Udo),tibber Pulse, Kostal Pico, cfos Wallbox, Modbus TCP

ch.eick

#224
Sooo,
ich habe dann jetzt mal ein Wiki angelegt.

Update 20240123
  Ich habe auch noch aWATTar im Wiki abgelegt und das EVU_aWATTar_connect vergleichbar aufgebaut.
  Das soll nun noch weiter entwickelt werden, da man von Tibber ja nur als Kunde die wirklichen Preise bekommt.
  Im bisherigen Stand werden die Börsen Preise4 bereits in der DbLog abgelegt, jedoch fehlen noch die Fixkosten.


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