FHEM Forum

FHEM => Anfängerfragen => Thema gestartet von: maddinthebrain am 23 Juni 2026, 15:17:02

Titel: Dyn. Strompreis auslesen - Octopus Energy
Beitrag von: maddinthebrain am 23 Juni 2026, 15:17:02
Hallo zusammen,

ich möchte gerne den dyn. Strompreis von Octopus Energy über deren API in Fhem verfügbar machen. Ich haben Gemini um Unterstützung gefragt:

# --------- Octopus Strompreis auslesen -------

use HttpUtils;
use JSON::PP;
use Time::Local;

sub getOctopusPrices {
    # ------------------ KONFIGURATION HIER EINTRAGEN ------------------
    my $email    = 'tollemailadresse@mail.de';
    my $accountNo = 'A-xxxxxx';
    # -----------------------------------------------------------------

    # Passwort sicher aus dem FHEM-Speicher auslesen
    my ($pwdErr, $password) = getKeyValue("octopus_password");
   
    if ($pwdErr || !$password) {
        Log 2, "Octopus SMGW Fehler: Passwort konnte nicht aus FHEM-KeyValue-Speicher gelesen werden!";
        return;
    }

    my $gqlUrl = "https://api.oeg-kraken.energy/v1/graphql/";

    # Schritt 1: Login-Mutation mit dem dynamisch geladenen Passwort
    my $loginQuery = {
        query => 'mutation ($email: String!, $password: String!) { obtainKrakenToken(input: { email: $email, password: $password }) { token } }',
        variables => { email => $email, password => $password }
    };
   
    my $loginParam = {
        url        => $gqlUrl,
        timeout    => 10,
        header    => "Content-Type: application/json",
        data      => encode_json($loginQuery),
        callback  => sub {
            my ($param, $err, $data) = @_;
            if ($err ne "") { Log 3, "Octopus SMGW-Login-Fehler: $err"; return; }
           
            my $decodedLogin = eval { decode_json($data) };
            my $token = $decodedLogin->{data}{obtainKrakenToken}{token};
            if (!$token) { Log 3, "Octopus SMGW: Token-Generierung fehlgeschlagen."; return; }
           
            # Schritt 2: Abfrage der Marktpreise für iMSys (Smart Meter Gateway)
            my $dataQuery = {
                query => 'query ($accountNo: String!) {
                    account(accountNumber: $accountNo) {
                        properties {
                            electricityMeteringPoints {
                                agreements {
                                    tariff {
                                        ... on MarketIndexedTarif {
                                            unitRates {
                                                valueWithTax
                                                validFrom
                                                validTo
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }',
                variables => { accountNo => $accountNo }
            };

            my $dataParam = {
                url        => $gqlUrl,
                timeout    => 10,
                header    => "Authorization: Bearer $token\r\nContent-Type: application/json",
                data      => encode_json($dataQuery),
                callback  => sub {
                    my ($dParam, $dErr, $dData) = @_;
                    if ($dErr ne "") { Log 3, "Octopus SMGW-Datenabruf-Fehler: $dErr"; return; }
                   
                    my $decodedData = eval { decode_json($dData) };
                    if (!$decodedData || $decodedData->{errors}) {
                        Log 3, "Octopus API Fehler: " . ($decodedData->{errors}{message} // "Unbekannt");
                        return;
                    }
                   
                    my $points = eval { $decodedData->{data}{account}{properties}{electricityMeteringPoints}{agreements}{tariff}{unitRates} };
                    if (!$points || ref($points) ne 'ARRAY') {
                        Log 2, "Octopus SMGW Fehler: Konnte unitRates im JSON nicht finden.";
                        return;
                    }
                   
                    my $now = time();
                    my $price_current = undef;
                    my $price_next = undef;
                   
                    foreach my $rate (@$points) {
                        my $from = parseIsoToEpoch($rate->{validFrom});
                        my $to  = parseIsoToEpoch($rate->{validTo});
                       
                        if ($now >= $from && $now < $to) {
                            $price_current = $rate->{valueWithTax};
                        }
                        if (($now + 3600) >= $from && ($now + 3600) < $to) {
                            $price_next = $rate->{valueWithTax};
                        }
                    }
                   
                    if (defined($price_current)) {
                        fhem("setreading Octopus_Strompreis price_current " . sprintf("%.2f", $price_current));
                        fhem("setreading Octopus_Strompreis price_next_hour " . sprintf("%.2f", $price_next)) if defined($price_next);
                        fhem("setreading Octopus_Strompreis meter_type LandisGyr_iMSys");
                        fhem("setreading Octopus_Strompreis last_update " . localtime());
                        Log 3, "Octopus SMGW (Landis+Gyr) erfolgreich aktualisiert: $price_current Cent/kWh.";
                    } else {
                        Log 3, "Octopus SMGW: Kein Preis für die aktuelle Stunde im Datensatz vorhanden.";
                    }
                }
            };
            HttpUtils_NonblockingGet($dataParam);
        }
    };
    HttpUtils_NonblockingGet($loginParam);
}

sub parseIsoToEpoch {
    my ($iso) = @_;
    if ($iso =~ /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/) {
        return timegm($6, $5, $4, $3, $2 - 1, $1 - 1900);
    }
    return 0;
}

Nun ist es so, wenn ich die Funktion triggere stürzt FHEM komplett ab und startet neu. Die Werte sollen in ein Dummy geschrieben werden:

[code]define Octopus_Strompreis dummy
attr Octopus_Strompreis readingList price_current price_next_hour last_update
attr Octopus_Strompreis room Energie,MiniPV,Zähler
attr Octopus_Strompreis stateFormat Aktuell: price_current ct/kWh </br> Nächste Stunde: price_next_hour ct/kWh
#  FUUID      6a3a73f7-f33f-54a1-8d84-f2bfb88940d33850
#  FVERSION  98_dummy.pm:0.256060/2022-02-01
#  NAME      Octopus_Strompreis
#  NR        435
#  STATE      Aktuell: price_current ct/kWh </br> Nächste Stunde: price_next_hour ct/kWh
#  TYPE      dummy
#
setstate Octopus_Strompreis Aktuell: price_current ct/kWh </br> Nächste Stunde: price_next_hour ct/kWh

[/code]

Getriggert wird die Funktion alle 60min um 1min nach Ganz.

Hat jemand eine Idee warum das Skript auf die Bretter geht?

Vielen Dank

viele Grüße
Martin
Titel: Aw: Dyn. Strompreis auslesen - Octopus Energy
Beitrag von: betateilchen am 23 Juni 2026, 19:34:37
Meldung im Logfile zum Absturz?
FHEM schonmal in Debug Modus gestartet und dann getestet?
Titel: Aw: Dyn. Strompreis auslesen - Octopus Energy
Beitrag von: maddinthebrain am 23 Juni 2026, 20:28:43
Hi betateilchen,

das ist ja das Problem, im Logfile steht nix dazu. Aber Evtl. ist das ein Hinweis:

Not a HASH reference at ./FHEM/99_myUtils.pm line 164.
2026.06.23 15:02:37 1: reload: Error:Modul 99_myUtils deactivated:

Leider steht dann nix nach dem Doppelpunkt. Achtung die Zeile 164 stimmt nicht mit dem Skript oben überein. Das steht in Realität noch Zeug davor.