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.

    Ein bisschen Senf von mir:

    Das JSON-RPC Protokoll definiert nur das Layout von Nachrichten, aber nicht den Transportmechanismus. Shellies können JSON-RPC Nachrichten offenbar über HTTP, UDP, MQTT, WebSocket und Bluetooth empfangen.

    Die Diskussion hat mich neugierig gemacht, weil ich mich bisher nie gefragt habe, wie mein HA eigentlich mit dem Shelly kommuniziert. Des Rätsels Lösung ist: WebSocket. Die Dokumentation sagt Folgendes:

    Zitat

    Websocket

    The connection is kept alive through the whole duration of the communication (not only for one request-response pair) as used by the local web interface and aioshelly. Each Shelly device has a websocket endpoint and a client can connect to it to communicate with the device. Protection through digest authentication is supported over this channel.

    The websocket channel is served on ws://<shelly.addr>/rpc. Clients must send at least one request frame with valid src to be able to receive notifications from the device.

    Das erwähnte aioshelly ist die Python Library, die für die HA-Shelly Kommunikation zuständig ist (und auch auf GitHub zu finden). Wenn ich via HA den Switch des Shelly betätige, erscheint im Shelly Log auch eine entsprechende Nachricht mit WS_in als Quelle:

    Code
    Switch.Set [17@aios-546907190912] via WS_in 192.168.178.254:42364

    HA hält also via WebSocket eine permanente Verbindung zum Shelly offen und ich würde annehmen, dass das wohl die effizienteste/performanteste Lösung ist...

    Hallo Coloschni ,

    wenn ich zwei Skripte auf einem Modul laufen lasse, schalten die sich gegenseitig weg

    Ja, das ist so. Beide Script-Instanzen versuchen zu jeder vollen Stunde, den Switch anhand ihrer internen Tabelle umzuschalten und letzten Endes ist es Zufall, welche der beiden Versionen gewinnt.

    Von der Programmierung her wäre es einfach, den Tag in Segmente zu unterteilen und für jedes Segment separat die günstigsten Stunden zu errechnen. Das Problem dabei ist, dass die Konfiguration des Scriptes damit wesentlich komplizierter werden würde (und mit der Umstellung auf Viertelstundenpreise gilt das umso mehr).

    Ich experimentiere gerade in dem Bereich, aber ich kann noch nicht sagen, ob ich dafür eine zufriedenstellende Lösung finden werde...

    NScale

    Okay, dann würde ich noch eine Änderung im Script machen, nämlich den Content-Type - statt

    JavaScript
    "Content-Type": "application/json",

    solte er

    JavaScript
    "Content-Type": "application/x-www-form-urlencoded",

    sein (weil der Inhalt des Body eigentlich kein JSON mehr ist).

    Mit dieser Änderung sieht der vom Shelly gesendete Request in meinen Tests dann 1:1 wie der von curl aus. Wenn das auch nicht reicht, bin ich dann am Ende meiner Weisheit...

    NScale

    Das ist komisch - wenn du diese Meldung bekommst, müsste OpenDTU das eigentlich akzeptiert haben. Bei genauerer Ansicht fällt mir noch auf, dass die Definition des Request body nicht der Dokumentation entspricht. Probiere noch, diese Zeile:

    JavaScript
    body: JSON.stringify({ data: payload }),

    durch diese zu ersetzen:

    JavaScript
    body: "data=" + JSON.stringify(payload),

    Und du könntest noch schaun, ob OpenDTU den folgenden curl-Request (natürlich mit deinen Daten) akzeptiert - der ist direkt aus der OpenDTU Dokumentation:

    Code
    curl -u "admin:password" http://192.168.10.10/api/limit/config -d 'data={"serial":"11418180xxxx", "limit_type":1, "limit_value":50}'

    Vorweg: Ich verwende OpenDTU nicht und kann daher nur nach Doku vorgehen.

    Laut der Konsole wird der Befehl ausgeführt und das Limit gesetzt. Allerdings kann ich in der openDTU keine Änderung verzeichnen. Kann mir jemand helfen?

    Die Meldung in der Konsole sagt nur, dass der Request erfolgreich abgeschickt wurde. Sie sagt NICHT, dass OpenDTU den Request auch akzeptiert hat. Mit hoher Wahrscheinlichkeit lehnt OpenDTU den Request ab, weil User und Passwort nicht korrekt gesendet wurden.

    Hier ist eine modifizierte Version deines Scriptes, in der ich drei Dinge geändert habe:

    1. Anstelle von HTTP.POST wird HTTP.Request mit der Methode POST verwendet (weil bei HTTP.POST kurioserweise keine eigenen Header mitgegeben werden können).
    2. Username und Passwort werden im Header so mitgegeben, wie es die Basic HTTP Authentication vorsieht.
    3. Zusätzlich ist eine Fehlerbehandlung implementiert, die genaue Auskunft über etwaige Probleme geben sollte.

    Wenn du jetzt die Funktion sendLimit() aufrufst, sollte in der Konsole eine von drei Meldungen erscheinen:

    • Shelly Fehler ... wenn der Request nicht abgeschickt werden konnte
    • OpenDTU Fehler ... wenn OpenDTU den Request nicht akzeptiert hat
    • Limit erfolgreich geändert wenn alles funktioniert hat

    Versuch es bitte mal und lass mich wissen, was die Konsole sagt...

    mleit1210 Ich habe mit Cloud-API keinerlei Erfahrung, aber das hat tvbshelly ja schon abgedeckt (und sein Hinweis mit event.info.state ist auch korrekt).

    Ich würde dir noch raten, den addEventHandler Block durch diesen hier zu ersetzen:

    JavaScript
    Shelly.addEventHandler(function (event) {
      if (event.component === "switch:0") {
        if (event.info && event.info.event === "toggle") {
          let newState = event.info.state; // true = AN, false = AUS
          controlTargetShelly(newState);
          print("Lokales Relais geändert → Remote Shelly:", newState ? "AN" : "AUS");
        }
      }
    });

    Der Grund:

    Im Moment feuert dein Script bei ALLEN Events, die den Switch betreffen. Da gibt es eine ganze Menge und für jeden dieser Events sendest Du einen unnötigen Cloud-Request, der vom Ziel-Shelly sowieso abgewiesen wird. Mit der obigen Änderung wird tatsächlich nur beim Ein-/Ausschalten gesendet.

    Ach, wir haben alle einmal angefangen. Ich bleibe bei dem von mir geposteten Beispielscript - wenn ich das auf dem Shelly speichere und starte, sieht das so aus:

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

    Der untere Abschnitt ist die Konsole. Wenn du dort 'Only Script Logs' aktiviert hast, siehst du nur die Ausgabe des aktuellen Scriptes (und nicht alle Meldungen des Shelly).

    Die Ausgabe enthält alle Texte, die mit dem print() Befehl ausgegeben werden (und gegebenenfalls noch Fehlermeldungen des Scriptes).

    Das Script gibt in diesem Falle jedesmal eine Meldung aus, wenn der Switch des Shelly ein- oder ausgeschaltet wird. Das bedeutet, dass das Script tut was es soll und jetzt kann man den Code hinzufügen, der beim Ein-/Ausschalten ausgeführt werden soll.

    Der Fehler ist eigentlich nicht seltsam - das Problem ist, dass das abgefragte Feld event.delta.output einfach nicht existiert. Das Event Objekt bei einer Änderung der Schalterstellung des Switches hat die folgende Struktur:

    Folgerichtig müsste der Code für eine Abfrage dieses Events dann ca. so aussehen:

    JavaScript
    Shelly.addEventHandler(function (event) {
      if (event.component === "switch:0") {
        if (event.info && event.info.event === "toggle") {
          print("Switch 0 steht auf ", event.info.state)
        }
      }
    });

    Auch wenn ich dein Skript nicht benötige, möchte ich Dir einfach mal schreiben, dass ich dein Engagement mit diesem Skript einfach toll finde

    Vielen Dank für die Blumen, aber im Endeffekt mache ich das ja, weil's mir Spaß macht. Das ist ein schönes kleines Projekt mit einer überschaubaren Zielgruppe und ich kann gleichzeitig ein bisschen Open Source praktizieren (und auch bei kleinen Projekten lernt man immer was dazu)...

    Ich habe Version 3.2 des Scriptes veröffentlicht. Hier ist das Changelog:

    Dies ist eine wichtige Version, und ein Update sollte aus dem folgenden Grund so schnell wie möglich durchgeführt werden:

    AB DEM 1. OKTOBER 2025 FUNKTIONIEREN ALLE VORHERGEHENDEN VERSIONEN DES SCRIPTES NICHT MEHR.

    Am 1. Oktober wird der Day-Ahead Handel an den europäischen Energiemärkten von Stundenintervallen auf 15-Minuten-Intervalle umgestellt. Die daraus resultierende Zunahme der Preise pro Tag führt dazu, dass frühere Script-Versionen nach dem 30. September unsinnige Ergebnisse produzieren.

    Diese Script-Version verwendet bis zum 30. September Stundenpreise und ab dem 1. Oktober 15-Minuten-Preise.

    Es ist jedoch zu beachten, dass 15-Minuten-Preise noch nicht vollständig unterstützt werden. Stattdessen verwendet das Skript diese Preise, um einen Durchschnittspreis pro Stunde zu ermitteln, und dieser Durchschnitt wird dann zur Berechnung der Schaltzeiten verwendet. Abgesehen von der (internen) Durchschnittsberechnung verhält sich das Skript genau wie bisher.

    Ich beabsichtige, die Unterstützung für 15-Minuten-Preise zu einem späteren Zeitpunkt hinzuzufügen, aber im Moment gibt es sowohl aus technischer als auch aus konzeptioneller Sicht mehrere Unbekannte, die sich hoffentlich nach der erfolgten Umstellung klären werden.

    Hallo marekz ,

    Danke für das Feedback!

    Eine Invertierung ist problemlos möglich, indem du eine einzige Zeile ins Script einfügst. Für deine Anforderung müsstest du das Script zuerst so konfigurieren, dass es die 21 günstigsten Stunden des Tages schaltet:

    JavaScript
    let switchOnDuration = 21;
    let timeWindowStartHour = 0;
    let timeWindowEndHour = 0;
    let blockMode = false;

    Somit hast du 21 Stunden auf EIN und drei Stunden auf AUS. Um das umzudrehen, muss in die Funktion set() eine Zeile eingefügt werden:

    Durch das Einfügen dieser Zeile erreichst du eine exakte Umkehrung des Schaltverhaltens - es bleiben also 21 Stunden auf AUS und (die teuersten) drei Stunden auf EIN.

    Ich werde mir noch anschaun, ob ich diese Invertierung in einer zukünftigen Version über eine Konfigurationsvariable ermögliche...

    Okay, nach einmal Schlafen ist mein Gehirn wieder im Vollbetrieb und ich verstehe jetzt, warum das Script trotz fehlerhafter Konfiguration Schaltungen vorgenommen hat... der Grund ist, dass ich das so programmiert habe ;). Passiert ist Folgendes:

    Jeden Tag hat das Script ab 15:00 versucht, die Preise abzurufen. Und das Script ist so programmiert, dass es beim Scheitern eines Abrufes 20 Minuten später einen neuen Versuch startet. Aufgrund des falschen Marktcodes sind natürlich alle Abrufe gescheitet und wenn das passiert, geht das Script um ca. 23:45 in den Fallbackmodus.

    Im Fallbackmodes verwendet das Script fix hinterlegte statistische Preise, um die Schaltzeiten zu errechnen und genau das ist hier passiert. Es gibt also keine mysteriöse unbekannte Quelle für die Schaltungen...

    Coloschni

    Vielen Dank für die Infos - ohne die hätte ich nie herausgefunden, was hier falsch läuft.

    Das Problem ist, dass die epexBZN Variable falsch gesetzt ist. Der korrekte Code für Deutschland ist nicht DE, sondern DE-LU (weil Deutschland innerhalb der EPEX einen gemeinsamen Markt mit Luxemburg betreibt).

    Der inkorrekte Code führt dazu, dass das Script keine Preisdaten herunterladen kann und daher überhaupt nicht funkioniert.

    Natürlich wirft das die Frage auf, wer oder was jetzt deinen Shelly schaltet, denn das Script ist es offensichtlich nicht. Kommen die Grafiken aus dem Home Assistant und hast du dort vielleicht auch irgendeine Automation konfiguriert? Oder hast du vielleicht gleichzeitig noch eine zweite Version des Scriptes auf diesem Shelly laufen?

    Ich werde mir überlegen, ob ich ein solches Setup-Problem irgendwie an den Benutzer kommunizieren kann. In den Versionen vor 3.0 trat dieses Problem übrigens nicht auf, weil ich da noch ein anderes API verwendet habe, für das der Wert DE richtig war.

    Nebenbei:

    In deinem derzeitigen Setup arbeitet das Script nur im Zeitraum von 0 bis 23 Uhr. Wenn du den ganzen Kalendertag abdecken willst, müsstet du die timeWindowEndHour Variable ebenfalls auf 0 setzen. Damit beginnt das Zeitfenster um 0:00 Uhr des aktuellen Tages und endet um 0:00 des Folgetages.

    Zusammengefasst sollte das Script mit dem folgenden Setup tun, was du erwartest:

    JavaScript
    let epexBZN = "DE-LU"; // EPEX Bidding Zone - see documentation for valid codes
    
    let timeWindowStartHour = 0; // minimum 0, maximum 23
    let timeWindowEndHour = 0; // minimum 0, maximum 23

    Lass mich bitte wissen, ob damit alles wunschgemäß läuft...

    Ich hatte immer mal wieder das Gefühl bzw. festgestellt das es sich nicht ganz an die Zeiten hält. Bei mir soll es von 5-22 Uhr zu den billigen Stunden ein Geräte 7 Stunden einschalten. Wenn ich das Kontrolliert habe, wurde teilweise schon eine Stunde zu früh eingeschaltet. Ich habe aber nie kontrolliert, ob und nach welchen Strompreisen das Skript arbeitet.

    Danke - sehr interessant. Aufgrund der internen Logik würde ich das im ersten Moment als unmöglich einstufen, aber es wäre nicht das erste Mal, dass mich mein eigener Code überrascht...

    Ich lasse mal Version 3.0 und 3.1 mit dem beschriebenen Setup für ein paar Tage laufen und beobachte das Schaltverhalten.

    Nur zur Sicherheit: die Zeitzoneneinstellung auf deinem Shelly ist korrekt?

    Ich habe Version 3.1 des Scriptes veröffentlicht. Dies ist ein Service-Release ohne funktionale Änderungen. Das Changelog enthält zwei Punkte:

    • Behoben: Umgang mit Zeitumstellung
      Aufgrund von Einschränkungen der Shelly-Zeitberechnungs-Routinen hätte das Script an den Tagen der Zeitumstellung auf/von Sommerzeit die Synchronität mit dem Kalender verloren. Dies ist mit dieser Version behoben.
    • Geändert: Optimierungen
      Aufgrund eines verbesserten Speichermodells und allgemeiner Code-Optimierungen verwendet das Skript nun weniger Speicher. Der Spitzenverbrauch hat sich von ~9,5 kB auf ~7,2 kB in der speicheraufwändigsten Konfiguration reduziert.