Beiträge von towiat

VPN/Proxy erkannt

Es scheint, dass Sie einen VPN- oder Proxy-Dienst verwenden. Bitte beachten Sie, dass die Nutzung eines solchen Dienstes die Funktionalität dieser Webseite einschränken kann.

    Ich habe das Script umformuliert, weil deine Version mit hoher Wahrscheinlichkeit nicht das tut, was du erwartest.

    Das Problem ist (und darüber stolpern viele Neulinge), dass JavaScript nicht wartet, während du die Abfragen an den Pro2 schickst - statt dessen läuft das Script in der Zwischenzeit einfach weiter. Für dein Script bedeutet das:

    JavaScript
    function startControl() {
      // Setze eine Funktion zur regelmäßigen Überprüfung alle 10 Sekunden
      Timer.set(6000, true, function() {
        updateSwitchStatus(); // Frage Switch 0 vom Pro2 ab
        updateSwitchStatus2(); // Frage Switch 1 from Pro2 ab
        // Die folgenden beiden Zeilen werden ausgeführt, bevor der PRO2 geantwortet hat
        print("Das Netz wurde", switch_status ? "auf Netzbetrieb" : "auf Akkubetrieb", "umgeschaltet");
        setRelayState(switch_status && switch_status2); // Aktualisiere den gewünschten Relaiszustand
      });
    }

    Das bedeutet, dass dein Script nicht auf den aktuellen Stand des Pro2 reagiert, sondern auf den Stand vom letzten Durchlauf (also sechs Sekunden früher).

    Wenn du das vermeiden willst, musst du die Statusabfrage im Callback der Abfrage verarbeiten (was die Hauptänderung in meiner geposteten Version ist). Wenn dich diese Verzögerung nicht stört, kannst du natürlich auch damit leben...

    Der folgende Code sollte funktionieren und (auf etwas einfachere Art) exakt das tun, was deine derzeitige Version macht (machen sollte).

    Allerdings sagst du, dass du den Pro 1 einschalten willst, wenn beide INPUTS des Pro2 AUS sind - derzeit fragst du aber ab, ob die OUTPUTS EIN sind. Ist das Absicht oder missverstehe ich da etwas?

    Unter der Annahme, dass du mit Timer.set() arbeitest:

    intern nutzen die shellys zur zeitbasierten Ausführung einen cron deamon.

    Für Timer stimmt das nicht - die arbeiten mit der Uptime des Gerätes. Das geht auch implizit aus der Dokumentation der (in FW 1.5.x neuen) Timer.getInfo() Methode hervor:

    Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen.

    Das macht ja auch Sinn, weil Timer damit auch auf Geräten funktionieren, die mangels Internetzugang keine Zeitsynchronisation durchführen können.

    Meine Vermutung ist, dass die interne Uhr des Shellys zu schnell läuft und daher ein Drift zwischen Uptime und Realzeit auftritt. Das könntest du überprüfen, indem du z. B. die Differenz in der Uptime innerhalb von exakt 24 Stunden misst.

    Wenn diese Vermutung zutrifft, wäre die Lösung - wie von thgoebel vorgeschlagen - ein Schedule, weil der natürlich an der Systemzeit hängt.

    Hallo Coloschni ,

    Eine Berechnung nach dem Durchschnittspreis wird vom Script nicht unterstützt.

    Du könntest ein ähnliches Resultat erzielen, indem du das Script so aufsetzt, dass es nur die zwölf günstigsten Stunden des Tages schaltet:

    JavaScript
    let switchOnDuration = 12; // minimum 1, maximum 24
    let timeWindowStartHour = 0; // minimum 0, maximum 23
    let timeWindowEndHour = 0; // minimum 0, maximum 23
    let blockMode = false; // set calculation mode
    let priceLimit = Infinity; // in cent/kWh

    Das liefert natürlich andere Resultate als eine Durchschnittspreisberechnung, bei der die Anzahl der geschalteten Stunden abhängig von der Preisstruktur des Tages schwanken würde - aber vielleicht reicht es ja für deine Zwecke.

    Es kann passieren, dass ein Script die Shelly-CPU derartig auslastet, dass sie nicht mehr antworten kann. Das könnte z. B. durch eine Endlosschleife im Script ausgelöst werden (die hier offensichtlich nicht vorliegt). Und wenn das Script auf Autostart steht, geht es nach einem Reboot sofort wieder los.

    Keine Ahnung warum der Shelly bei diesem Script so rumzickt, aber um ihn wieder ansprechbar zu machen könntest du versuchen, das Script mittels RPC zu stoppen.

    Dazu müsstest du den RPC http://192.168.1.126/rpc/Script.Stop?id=1 (unter der Annahme, dass das Script die ID 1 hat) via Browser/curl/iwr so oft aufrufen, bis er durchkommt - das kann durchaus ein paar Versuche benötigen...

    Um einen Schedule auf demselben Gerät anzulegen, würde ich übrigens nicht über HTTP.GET gehen, sondern den RPC direkt aufrufen - das würde dann so aussehen:

    JavaScript
    Shelly.call("Schedule.Create", {
     enable: true,
     timespec: "0 16 3 * * 0",
     calls: [{ method: "Cover.Open", params: { id: 0 } }],
    });

    The property for the content type in the HTTP.POST RPC is named content_type, not Content-Type - this could already be the solution for this:

    JavaScript
    let parms = {
          "url": "http://<INTERNAL_IP>/php/controls.php",
          "content_type":"application/x-www-form-urlencoded",
          "body": body
        };

    Du kannst keine Werte aus dem Shelly.call ins Hauptprogramm zurückgeben. Du kannst allerdings die Variablen im Hauptprogramm anlegen und sie dann aus dem Shelly.call heraus updaten:

    In vielen Fällen ist das allerdings nicht das, was du willst.

    Die Frage ist: soll direkt nach der Abfrage der Werte eine Aktion mit diesen Werten ausgeführt werden?

    Wenn die Antwort darauf "ja" ist, solltest du die entsprechende Logik direkt in der Funktion ausführen und nicht im Hauptteil des Scriptes. Wenn du beschreibst, was du nach der Abfrage der Werte machen willst, können wir das noch genauer diskutieren.

    Du könntest dem Benutzer einen Link geben, der die Autorisierung mit der URL in der Form http://admin:password@x.x.x.x/script/x/Dauerbetrieb mitschickt - damit wäre das Passwort natürlich dem Benutzer gegenüber exponiert.

    Ansonsten fiele mir nur ein Zwischenschritt ein - z. B. ein minimaler Webserver, der das HTML ausliefert und im Hintergrund dann den autorisierten Aufruf an den Shelly schickt...

    Grundsätzlich sollte das funktionieren - Fehler -104 ist ein Timeout und deutet stark darauf hin, dass die IP-Adresse nicht korrekt ist.

    Es ist aber generell keine gute Praxis, das eigene Gerät über seine Netzwerkadresse abzufragen. Es gibt zwei Möglichkeiten, wie du das anders lösen kannst:

    1. Könntest du einfach die IP-Adresse 127.0.0.1 verwenden - das ist die Loopbackadresse, die immer auf das eigene Gerät verweist:

    JavaScript
    Shelly.call(
     "HTTP.GET",
     {
       url: "http://127.0.0.1/rpc/Shelly.GetStatus",
     },
     function (result, error) {
       print(result);
       print(error);
     },
    );

    2. Könntest du GetStatus direkt und ohne Umweg über HTTP.GET aufrufen:

    JavaScript
    Shelly.call("Shelly.GetStatus", {}, function (result, error) {
     print(result);
     print(error);
    });

    Diese Variante hätte den Vorteil, dass in result schon ein fertiges JSON-Objekt steckt und du nicht JSON.Parse() verwenden musst, um die Antwort in ein JSON zu konvertieren.

    Beide Möglichkeiten sollten dich ans Ziel bringen...

    Spotelly 2.0: Tester gesucht

    Nachdem das Script offensichtlich einen kleinen, aber feinen Nutzerkreis gefunden hat, habe ich nun eine neue Version mit einigen zusätzlichen Features erstellt. Aufgrund einiger Limitationen in der Ursprungsversion musste ich dazu im Code kräftig umrühren und einige strukturelle Änderungen vornehmen.

    Die neue Version läuft in meinen Tests klaglos, aber angesichts der doch signifikanten Änderungen wäre es schön, wenn sich ein paar Mutige finden würden, die das Script vor der "offiziellen" Freigabe installieren und mir Feedback über eventuelle Probleme geben.

    Wie man an die Vorabversion kommt, beschreibe ich am Ende - vorher noch eine Übersicht über die Änderungen zwischen Version 1.2 und 2.0:

    Geändert: API

    Anstelle des Awatter APIs wird nun das API von http://energy-charts.info verwendet. Dieses API wird vom Fraunhofer-Institut für Solare Energiesysteme (ISE) bereitgestellt und hat den Vorteil, dass es Preisdaten für das gesamte Marktgebiet der Strombörse EPEX anbietet (und das Script somit nicht mehr nur in Deutschland und Österreich verwendbar ist).

    Die Konfigurationsvariable awattarCountry wurde durch epexBZN (für Bidding Zone) ersetzt. Die EPEX unterteilt ihr Marktgebiet in Marktzonen, die nicht unbedingt mit den Landesgrenzen übereinstimmen müssen. Jede Zone wird durch einen Code identifiziert, der der in der Dokumentation verlinkten Tabelle entnommen werden kann.

    Deutsche Benutzer müssen in diese Variable den Wert DE-LU eintragen (weil Deutschland und Luxemburg eine gemeinsame Marktzone betreiben). Für österreichische Benutzer lautet der Code AT (Großschreibung ist in beiden Fällen wichtig!).

    Geändert: Abruflogik und Fehlertoleranz

    In der Vorversion war es notwendig, den Abrufzeitpunkt für die Preisdaten in einer Variable festzulegen. Diese Variable existiert nun nicht mehr - das Script führt den Preisabruf selbsttätig ab ca. 15:00 Uhr durch (der genaue Zeitpunkt ist leicht zufallsgesteuert, um die Last für den API-Server etwas zu verteilen).

    Sollte der API-Aufruf scheitern (weil die Tagespreise noch nicht im API-Server eingepflegt wurden oder auch aufgrund von Netzwerkproblemen etc.), startet das Script in Abständen von 20 Minuten so lange neue Versuche, bis die Daten erfolgreich abgerufen werden konnten. Normalerweise stehen die Preise irgendwann zwischen 15:00 und 17:00 zur Verfügung.

    Neu: nonBlockMode

    Über die neue Konfigurationsvariable blockMode kann nun zwischen zwei Betriebsmodi gewählt werden:

    Steht blockMode auf true (die Grundeinstellung), bleibt alles wie bisher - das Script identifiziert innerhalb des vorgegebenen Zeitfensters den zusammenhängenden Block von x Stunden mit dem niedrigsten Durchschnittspreis und aktiviert die Stromzufuhr für diesen Block.

    Wenn blockMode auf false gestellt wird, werden die x günstigsten Stunden im definierten Zeitfenster aktiviert - unabhängig davon, ob diese Stunden aufeinander folgen oder nicht.

    In beiden Modi wird für jede einzelne Stunde ein Check gegen das (optionale) Preislimit ausgeführt - sollte der Preis das Limit überschreiten, unterbleibt der Einschaltvorgang für die jeweilige Stunde.

    Entfernt: KVS-Eintrag

    Bisher hat das Script die berechneten Schaltzeiten über einen KVS-Eintrag kommuniziert. Für den neuen nonBlockMode ist das aufgrund der größeren Anzahl von Schaltaktionen nicht mehr praktikabel - ich habe daher die KVS-Logik entfernt und an dessen Stelle über einen HTTP-Endpunkt eine Infoseite implementiert - siehe den nächsten Punkt.

    Neu: HTTP-Endpunkt

    Das Script bietet nun einen HTTP-Endpunkt, der mit mit der URL http://<ipDesShelly>/script/<script_id>/spotelly aufgerufen werden kann. Gibt man obige URL im Browser ein, erhält man eine tabellarische Übersicht der berechneten Schaltzeiten samt den zugehörigen Preisen:

    Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen.

    Neu: priceModifier

    In der Grundeinstellung zeigt das Script die EPEX-Großhandelspreise an. Das sind aber üblicherweise nicht die Preise, die an den Stromlieferanten zu bezahlen sind - viele Anbieter verrechnen einen Aufschlag auf den Marktpreis und dazu kommt natürlich noch die Umsatzsteuer und vielleicht noch andere Abgaben oder Gebühren.

    In der Funktion priceModifier kann eine Formel hinterlegt werden, mit der der Marktpreis auf den tatsächlich zu bezahlenden Preis umgerechnet wird (und der so modifizierte Preis wird dann auch im HTTP-Endpunkt angezeigt).

    Beispiel: Ein österreichischer Anbieter verrechnet den EPEX-Spotpreis zuzüglich eines Aufschlages von netto 1.3 cent/kWh und auf diesen Betrag kommt dann noch die landesübliche Umsatzsteuer von 20 %. Diese Kalkulation würde man in der priceModifier Funktion so abbilden:

    JavaScript
    function priceModifier(spotPrice) {
      return (spotPrice + 1.3) * 1.2;
    }

    Neu: switchID

    Über die Konfigurationsvariable switchID kann bei Multi-Switch Geräten festgelegt werden, welcher Switch vom Script gesteuert werden soll. Jede Script-Instanz kann nur einen einzigen Switch verwalten.


    Das waren die Änderungen - um auf die neue Version zuzugreifen, muss im Github-Repository auf die dev Branch umgestellt werden:

    Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen.

    Nach Bestätigung dieser Auswahl sieht man die neue Version inklusive der überarbeiteten Dokumentation (es schadet wahrscheinlich nicht, diese Dokumentation einmal komplett durchzulesen ;)).

    Und hier ist noch einmal der Link auf das Repository:

    https://github.com/towiat/spotelly

    Für Fragen, Probleme, Wünsche und auch sonst alles stehe ich wie immer zur Verfügung ;).

    Der folgende Code tut, was du willst:

    JavaScript
    Shelly.call(
     "HTTP.GET",    // führe einen http GET request aus...
     {
       url: "http://192.168.2.60/rpc/Shelly.GetStatus", // ... und zwar auf diese URL
     },
     function (result, error) {
       print(result);
       print(error);
     },
    );

    Es reicht nicht, bei Shelly.call einfach eine URL reinzustecken - du musst sagen, welchen RPC du ausführen willst (in diesem Fall ist das ein HTTP GET Request) und gegebenenfalls die Parameter mitgeben, die dieser RPC verlangt (in diesem Fall ist der Parameter die URL die du aufrufen willst).

    Das Script ist in der vorliegenden Form tatsächlich nicht lauffähig, weil die Definition der Variablen SCAN_DURATION und ACTIVE_SCAN fehlt.

    Die Änderungshistorie zeigt, dass es am 5. Dezember 2024 eine Überarbeitung der Beispielscripte gab und in diesem Zuge sind die entsprechenden Programmzeilen (wohl unabsichtlich) gelöscht worden. Eine komplette Übersicht aller am 5. Dezember vorgenommen Änderungen zeigt der entsprechende Commit:

    https://github.com/ALLTERCO/shell…aa051540a4b907a

    Das bedeutet auch, dass die überarbeitete Version nie getestet wurde, weil dieser Fehler dann sofort aufgefallen wäre.

    Die einfachste Lösung ist vermutlich, die Version vor diesen Änderungen zu verwenden - die kann man sich aus der Git-Historie herausziehen. Hier ist der entsprechende Link:

    https://raw.githubusercontent.com/ALLTERCO/shell…le-shelly-dw.js