Java Skript für Shelly gesucht: Tibber Preis abrufen

Hallo zusammen,

ich stecke beim Programmieren fest und brauche Hilfe. Auf meinen Shellys können Java Skripte ausgeführt werden. Neuerdings kann Shelly auch mit dynamischen Tarifen arbeiten - via Skript.

Gesucht wird ein Skript, bei dem der Abruf des aktuellen Stundenpreises klappt (priceInfo). Mein Tibber-Token funktioniert, das habe ich via cUrl getestet und erhalte den korrekten Preis. Lediglich das Übersetzen in .js gelingt mir nicht. Ebenso funktioniert der Aufruf via Tibber Developer Explorer.

Ich poste bewusst keinen Code, um keine falsche Fährte zu legen :smiley:

https://developer.tibber.com/docs/guides/calling-api

Ich hab mal ChatGPT für dich gefragt:

Auf meinen Shellys können Java Skripte ausgeführt werden. Gesucht wird ein Skript, bei dem der Abruf des aktuellen Stundenpreises von Tibber klappt (priceInfo). Mein Tibber-Token funktioniert,

Und da wurde auch sofort geantwortet:


Super, dass dein Tibber-Token funktioniert. Dann kannst du mit einem Shelly (z. B. Gen2-Gerät mit Skript-Unterstützung) über ein JavaScript-Skript den aktuellen Tibber-Strompreis abrufen. Tibber stellt die Preisinfos über eine GraphQL-API zur Verfügung.

Hier ist ein Beispiel-Skript, das du auf deinem Shelly laufen lassen kannst. Es ruft den aktuellen Tibber-Preis per HTTP-Anfrage ab:

let token = "<DEIN_TIBBER_TOKEN>";
let homeId = "<DEINE_HOME_ID>"; // optional – wird für genauere Abfrage benötigt

let query = JSON.stringify({
  query: `
  {
    viewer {
      homes {
        currentSubscription {
          priceInfo {
            current {
              total
              energy
              tax
              startsAt
            }
          }
        }
      }
    }
  }`
});

HTTP.request({
  url: "https://api.tibber.com/v1-beta/gql",
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer " + token
  },
  body: query,
  timeout: 5,
  success: function(resp, code, headers, body) {
    let data = JSON.parse(body);
    let price = data.data.viewer.homes[0].currentSubscription.priceInfo.current.total;
    print("Aktueller Strompreis:", price, "EUR/kWh");
  },
  error: function(err) {
    print("Fehler beim Abruf:", err);
  }
});

Hinweise:

  • Ersetze <DEIN_TIBBER_TOKEN> durch deinen API-Token.
  • Falls du mehrere „homes“ hast, kannst du homeId zur genaueren Auswahl anpassen (in der Query z. B. viewer { home(id: "<dein_id>") { ... } }).
  • Der Strompreis kommt als Wert in Euro/kWh zurück, z. B. 0.287.

Möchtest du das Skript regelmäßig ausführen (z. B. jede Stunde oder alle 5 Minuten), kann ich dir auch ein Timer.set() Beispiel hinzufügen.

Möchtest du das?


Den Rest musst du dann machen. Viel Erfolg!

Muss es unbedingt Tibber sein?
Es gäbe hier ein entsprechendes Script für Shelly via EPEX.
Evtl kannst du das dann auch adaptieren für Tibber.

Vielen Dank, ihr beiden :slight_smile:

Die KI hatte ich auch schon befragt und angewendet. Leider erhalte ich immer einen Fehler, dass die Authentifizierung nicht geklappt hat (no Token und unauthenticated). Laut Recherche muss im query ein Fehler sein, welchen ich nicht finde.

@peterf Ich werde deinen Code dennoch testen :slight_smile:

@shysdrag Du hast absolut recht. Das wäre das Rückfallszenario aber irgendwie bin ich gechallengt und möchte Tibber einmal zum laufen bekommen :sweat_smile:

1 „Gefällt mir“

Ich kenne deinen Code nicht, aber wesentlich bei der Authentifizierung ist der Authorization Header.

Das Ganze kannst du auch gut mit Postman testen:

Die Info kommt aber von einer NI, kann also Fehler enthalten oder unvollständig sein. :wink:

1 „Gefällt mir“

NI für natürliche Intelligenz :sweat_smile:?

1 „Gefällt mir“

Ganz genau :sunglasses::joy:!

1 „Gefällt mir“

Home Assistant ist keine Option? Das kann Tibber und Shelly. Eine Automation die auf Preisänderung triggert und das Shelly an oder abschaltet ist kein Hexenwerk.

1 „Gefällt mir“

Derzeit nicht, da ich keine Anwendung dafür habe. Ich wollte lediglich den dynamischen Tarif in Shelly implementieren um die Kostendarstellung zu optimieren.

Für den HA benötige ich einen Server/Raspi, korrekt?

Docker würde für sowas genügen - falls Du also z.B. ein NAS in Nutzung hast.

Habe ich leider nicht :upside_down_face:

Raspi (4/5) geht, aber „besser“ und langfristig flexibler ist ein kleiner Mini-PC-Server. Braucht idR unwesentlich mehr Strom, leistet aber ggf. mehr und man ist auch flexibler in der Konfiguration (z.B. 16/32GB RAM, große, schnelle SSD)

Wenn man sowas sucht, kann man sich vielleicht im ersten Schritt an den Infos hier orientieren (eher an den Infos als an den konkreten Geräten):
https://www.heise.de/bestenlisten/testsieger/top-10-der-beste-mini-pc-im-test/6cybv8w

Tipps:

Und: Den Mini-PC am besten per Proxmox - Open-Source Server Solutions konfigurieren, dann kann man HA in einer VM betreiben!

Wer sich aber um nichts kümmern will oder kann, für den geht auch ein HA green:

1 „Gefällt mir“

Gegenmeinung: Server macht, wer Bock auf Linux, Docker und Co hat.

Ein HA auf Raspi geht komplett ohne Linuxkenntnisse. Imageprogramm unter Win/Mac runterladen, Image auswählen, SD Karte einlegen und warten. Umstecken in Raspi, einschalten. Im Browser anmelden.

1 „Gefällt mir“

Kann alles richtig sein!

Hier ein paar Hintergrundinfos mit Entscheidungshilfen für den eigenen Weg - auch, wann und warum man besser (nicht) eine Proxmox-VM nehmen sollte:

1 „Gefällt mir“

So, meine bessere Hälfte hat das Problem gelöst. Hauptfehler war das HTTP.POST, welches die Shellys nicht verarbeiten können. Derzeit ist die Firmware 1.4.4 drauf. Diese basiert nicht auf MGOS sondern der Shelly Script Engine (Gen2). Daher muss HTTP.REQUEST genutzt werden.

let apiUrl = "https://api.tibber.com/v1-beta/gql";
let token = "XXX";
	// Hier euren Tibber-Token einsetzen
let query = JSON.stringify({
  query: '{ viewer { homes { currentSubscription { priceInfo { current { total }}}}}}'
});
let shellyCloudUrl = "XXX";
	// Die URL sieht grob so aus: https://shelly-NN-eu.shelly.cloud/v2/user/pp-ltu/xxx
let shellyVar = "current_price";
	// Variable zur lokalen Speicherung des Preises

function fetchTibberPrice() 
{
  Shelly.call("HTTP.REQUEST", 
    {
      method: "POST",
      url: apiUrl,
      headers: 
      {
        "Content-Type": "application/json",
        "Authorization": "Bearer " + token
      },
      body: query
    }, 
    function (res, err) 
    {
      if (err) 
      {
        print("Fehler beim Abrufen: ", JSON.stringify(err));
        return;
      }
      let response = JSON.parse(res.body);
      //print("Antwortcode: ", res.code);
      //print("Antwort: ", JSON.stringify(response));
      //print(response);
      // 1 Preis in Shelly lokal speichern
      Shelly.call("KVS.Set", 
        {
          key: shellyVar, value: response
        }
      );
      // 2 Preis an die Shelly Cloud API senden
      let jsonPayload = JSON.stringify({ price: response.data.viewer.homes[0].currentSubscription.priceInfo.current.total.toFixed(4) });
      //print(jsonPayload);
      print("Strompreis aktuell: ", response.data.viewer.homes[0].currentSubscription.priceInfo.current.total, " €/kWh");
      Shelly.call("HTTP.REQUEST", 
        {
          method: "POST",
          url: shellyCloudUrl,
          headers: 
          {
            "Content-Type": "application/json"
          },
          body: jsonPayload
        },
        function (cloudRes, cloudErr) 
        {
          if (cloudErr) 
          {
            print("Fehler beim Senden an Shelly Cloud: ", JSON.stringify(cloudErr));
          }
          else 
          {
            print("Brutto-Preis erfolgreich an Shelly Cloud gesendet!");
          }
        }
      );
    }   
  );
}

// Skript beim Start ausführen und dann entsprechend aktualisieren
fetchTibberPrice();

Timer.set(300000, true, fetchTibberPrice);
// Zeit in Millisekunden 
// alle fünf Minuten = 300000

Als Basis habe ich folgenden Code genutzt - Dank an @tvbshelly geht raus!

2 „Gefällt mir“

Optimierungspotential:

Code-Kur - immer her damit
Aktualisierungszeit so schreiben, dass es genau zu jeder neuen Stunde bzw. bald zu jeder Viertelstunde ausgeführt wird

  • derzeit lasse ich das Skript alle fünf Minuten laufen
  • je nach Startzeit habe ich also einen Preis-Versatz von bis zu vier Minuten, bevor der korrekte Preis gesendet wird
  • Tibber erlaubt eine minütliche Aktualisierung

Ich habe nun den Timer optimiert. Er prüft minütlich, ob eine neue Viertelstunde angebrochen ist. Wenn ja, dann wird ein neuer Preis ermittelt und gesendet:

Timer.set(60000, true, function ()
  {
    let now = new Date();
    let minute = now.getMinutes();
    // Nur alle 15 Minuten
    if (minute % 15 === 0)
      {
        fetchTibberPrice();
      }      
    function pad(num)
    {
      return (num < 10 ? "0" : "") + num;
    }
    let hourStr = pad(now.getHours());
    let minuteStr = pad(now.getMinutes());
    let secondStr = pad(now.getSeconds());
    let timeStr = hourStr + ":" + minuteStr + ":" + secondStr;
    print("Timer ausgeführt um ", timeStr);
  }, null
);

Aktueller Ablauf:
• Es prüft jede Minute (60000 ms).
• Wenn die aktuelle Minute durch 15 teilbar ist (00, 15, 30, 45), wird fetchTibberPrice() aufgerufen.
• Die Ausgabe zeigt sauber „Timer ausgeführt um HH:MM:SS“.

Ich frage mich, was Du jetzt mit dem aktuellen Preis anstellst ?
Für eine smarte Steuerung braucht es doch zusätzlich Kontext wie z.B. Tagestief und Tagesmittel.

Raspi 5 mit SSD, beschde.

Meine Shellys geben mir nun die korrekten Kosten aus. Vorher gab es nur statische Tarife.

1 „Gefällt mir“