Beiträge von eiche

    Gu123

    Sehr interessant. Mit solchen Webhooks habe ich mich noch nicht in Tiefe beschäftigt.

    Insbesondere die "condition" Komponente ist beachtenswert. Ich werde bei Gelegenheit damit experimentieren. Vielleicht kann so etwas das eine oder andere kurze Skript ersetzen.

    Und per Komponente "enable" lässt sich ein solcher Webhook bspw. per Schedule Job sperren/freigeben. Das ist eine vielversprechende Kombination.

    Es ist gut möglich, dass hiermit dein Anliegen implementierbar ist.

    Diese Webhooks, bspw. per Web UI, einzurichten, ist allerdings auch etwas gewöhnungsbedürftig. Soll heißen, wer brauchbar skripten kann, kommt damit evtl. zügiger zum Ziel - neben der höheren Flexibilität per Skripten. So gesehen bilden die Webhooks eine Teilmenge von per Skript möglichen Implementationen ab.

    Nun schließlich die fast komplette Skriptlösung. Sie ist nur deshalb fast komplett, weil ich weit weg von den Tasten bin und die im EventHandler eintreffenden Events nicht prüfen kann. Dies ist erforderlich, um daraus die Filterbedingung im EventHandler handleButton (s. Skript) zu komplettieren. Das folgende Skript für den i4 ist somit ungetestet, stellt aber die wichtigsten Dinge bereits zur Verfügung. Dabei habe ich versucht, das Skript kurz und einigermaßen verständlich zu gestalten.

    Viel mehr kann ich aus der Ferne leider nicht tun.

    Das Skript auf dem Plus 2PM bleibt so wie in #11.

    Hinweis:

    Das i4 Skript lässt sich auf alle Eingänge, also 4 Tasten, erweitern. Hierfür sind 3 weitere HTTP Endpoints, eine etwas komplexere Datenstruktur (in den ersten Skriptzeilen) und eine Erweiterung des EventHandlers erforderlich. Je durchdachter die Datenstruktur gestaltet ist, desto kürzer kann der Ablaufcode gehalten werden - bei zugleich besserer Wartbarkeit. Wenn die Skripte auf den Plus 2PM etwas flexibler gestaltet würde, d.h. bspw. dem Status noch die Quelle beigefügt, braucht man im i4 Skript keinen zusätzlichen HTTP Endpoint. Vielleicht werde ich eine solche Lösung gelegentlich aufzeigen.

    Fortsetzung zu #10

    Das Skript auf dem i4 soll eine Status-Nachricht vom Plus 2PM empfangen. Hierfür ist am besten ein HTTP Endpoint (genauer HTTPServer Endpoint) geeignet.

    Das Skript auf dem i4:

    Code
    function receiveStatusCover_0(request) {
      if(request.method==="GET" && request.query!==undefined) {
        print(request.query);
      }
    }
    
    HTTPServer.registerEndpoint("Cover_0", receiveStatusCover_0);

    Die HTTPServer Endpoint Funktion habe ich receiveStatusCover_0 genannt. Dieser Name kann auch anders gestaltet werden, bspw. statusBad1Rollladen. So oder so muss diese Funktion als Endpoint registriert werden, was per Aufruf von HTTPServer.registerEndpoint geschieht. Die Funktion gibt zunächst nur den empfangenen Wert aus.

    Nun muss noch der Plus 2PM seinen Cover:0 Status an den i4 übermitteln. Hierfür ist die Methode "HTTP.GET" geeignet, die als Parameter den URL braucht, also die IP Zieladresse (des i4) und zusätzliches für den Endpoint des Plus 2PM.

    Ich nehme im weiteren Verlauf die folgenden IP Adressen an, die für deine Zwecke anzupassen sind.

    i4: 172.16.3.68

    Plus 2PM: 172.16.3.66

    Beide Skripte mögen bspw. die Id 1 besitzen. Deren Id lassen sich leicht per Browser herausfinden: http://<IP Adresse>/rpc/script.list
    Dies listet alle auf dem Shelly gespeicherten Skripte auf - id, name, enable, running. Die Id ist entscheidend.

    Das Skript auf dem Plus 2PM:

    Code
    function sendStatus(status) {
      if(status.component==="cover:0"
        && status.delta!==undefined
        && status.delta.state!==undefined) {
          print(status.delta.state);
          Shelly.call("http.get", {url:"http://172.16.3.68/script/1/Cover_0?" + status.delta.state});
        }
    }
    
    Shelly.addStatusHandler(sendStatus);

    Der URL setzt sich wie folgt zusammen.

    Das Protokoll (http://), die IP Zieladresse (des i4), "/script/", die Skript Id des i4, Slash, Name des Endpoints (Cover_0), Fragezeichen gefolgt vom Request (geänderter Status der Component "cover:0")

    Für die Funktion, hier noch ein Test, müssen beide Skripte laufen.

    Wenn du per Plus 2PM den Rollladen steuerst, wirst du in beiden Konsolenfenstern die gleichen Ausgaben vorfinden. Die beiden jeweils gleichen Ausgaben erfolgen auf dem i4 ca. 2s nach denen auf dem Plus 2PM. Der i4 erhält also zeitnah die Mitteilungen über die Statusänderungen des Rollladens am Plus 2PM - und kann diese für die Zielfunktionalität verarbeiten. Letzteres kommt noch in einer Fortsetzung. ;) Da die Verarbeitung des empfangenen Status auf einen nächsten kurzen Tastendruck vorzubereiten hat, sollte eine Verzögerung von ca. 2s kein Problem darstellen.

    Hinweis: Diese Skripte habe ich so kurz wie möglich gehalten. Man kann weitere Dinge hinzufügen, die die Skripte ein wenig verbessern, was aber an deren Funktionalität nichts ändert.

    Ich beginne mal ganz klein, um zu zeigen, wie das Skript auf dem Plus 2PM arbeitet.

    Code
    function sendStatus(status) {
      if(status.component==="cover:0"
        && status.delta!==undefined
        && status.delta.state!==undefined) {
          print(status.delta.state);
        }
    }
    
    Shelly.addStatusHandler(sendStatus);

    Die StatusHandler Funktion habe ich "sendStatus" genannt. Diese Funktion wird per Shelly.addStatusHandler() als StatusHandler in der Firmware registriert und erhält so alle möglichen Mitteilungen bei Status-Änderungen. Weil nur der aktuelle Zustand des Rollladenantriebs gebraucht wird, muss dieser per etwas komplexerer Bedingung gefiltert werden.

    sendStatus prüft sorgfältig die auslösende Komponente und ob die zu selektierende Information, hier status.delta.state, existiert. Deren Wert wird zunächst nur per print() im Konsolenfenster ausgegeben.

    Wenn der Rollladen, bspw. per Web UI gefahren und angehalten wird, zeigt die Konsolenausgabe nacheinander alle Zustands-Strings, bspw. so:

    Code
    opening
    stopped
    opening
    open
    closing
    stopped
    closing
    closed

    Hier habe ich den Rollladen (remote, VPN, Web UI) zunächst öffnen lassen, dann angehalten, weiter öffnen lassen bis ganz offen.

    Danach habe ich den Rollladen schließen lassen, auf dem Weg dahin angehalten, erneut schließen aktiviert bis ganz geschlossen.

    Die per print() ausgegebenen Wörter müssen noch an den i4 gesendet werden, wofür ich auf dem i4 einen HTTP Endpoint vorsehe. Dann fehlt im obigen Skript nur noch eine Anweisung, die den Status per HTTP Request an den i4 sendet.

    Fortsetzung folgt ;)

    kuhniwerle

    Mir fiel noch eine Lösung ein. Ich setze kein übergeordnetes System und keinen MQTT Broker voraus.

    1. Langer Druck => runter
    2. Kurzer Druck => Status quo abhängig
      stehend => rauf
      fahrend => stop

    Ein Fazit findest du am Ende.

    Mit einem langen Druck, wie oben gewünscht, immer zu fahren, dürfte nicht gelingen, da nach einem Stop per Tastendruck vom Nutzer die Fahrrichtung festgelegt werden muss.

    Dies gelingt mit der Unterscheidung zwischen kurzem und langem Druck. Auch erscheint mir dies hinreichend intuitiv.

    Andernfalls müsste der Nutzer unter Umständen mehrmals drücken, bis die gewünschte Reaktion erfolgt.

    Ob dies zielführend gelingen kann, hängt nur noch davon ab, ob der aktuelle Status zeitnah genug erfassbar ist.

    Ich habe es remote, bin weit weg, mit einem Shelly Plus 2PM getestet.

    Die asynchrone remote Abfrage lautet

    Code
    http://<IP Adresse>/rpc/cover.getstatus?id=0

    Die Antwort in result.state ist einer der folgenden Strings: "opening", "closing", "stopped", "open", "closed"

    Somit ist das Ziel per Skript auf einem i4 implementierbar.

    Ob hierbei evtl. auftretende Verzögerungen akzeptabel sind, bleibt zu prüfen.

    Ein kurzer Tastendruck muss folgende Wirkung haben.

    state: "opening" oder "closing" => stop

    state: "stopped" oder "closed" => rauf

    state: "open" darf bei kurzem Druck keine Wirkung haben. Man könnte dann zwar herunterfahren lassen, dies täte aber vermutlich den Lernerfolg von Nutzern eher behindern.

    Da die Antwort bei einer remote Abfrage evtl. zu stark verzögert eintreffen kann und diese nicht synchron verarbeitbar ist, sind ein Skript sowohl auf dem Plus 2PM als auch auf dem i4 empfehlenswert.

    Das Skript auf dem Plus 2PM kann vermutlich recht kurz sein. Es braucht dazu nur einen Event- oder StatusHandler, der die zielführende Information selektiert und eine Nachricht mit dem Status per HTTP an den i4 sendet.

    Das Skript auf dem i4 speichert die vom Plus 2PM empfangene Info, damit ein kurzer Tastendruck, wie oben angedeutet, zur passenden Nachricht an den Plus 2PM führt.

    Die RPC Methoden sind "Cover.Open", "Cover.Close" und "Cover.Stop" - jeweils mit id=0.

    Ein langer Tastendruck hat immer ein Herunterfahren zur Folge, also http://<IP Adresse 2PM>/rpc/cover.close?id=0 .
    Die Antwort lautet leider immer null. Deshalb ist der Status zusätzlich zu übermitteln.

    Auf dem i4 sind im Skript folgende Teile erforderlich.

    1. Ein HTTP Endpoint, der die Nachricht vom Plus 2PM empfängt und geeignet verarbeitet, d.h. den übermittelten Status speichert.
      Alternativ kann vorbereitend die Methode für den nächsten kurzen Tastendruck selektiert werden.
    2. Ein EventHandler, der sowohl den langen als auch den kurzen Tastendruck verarbeitet, Letzteren wie oben erläutert.

    Das ist das Prinzip. Ich habe ein begonnenes Skript verworfen, weil ich nicht alles, weit weg von den Shelly, testen kann bzw. dies in meiner Situation relativ aufwändig wäre.

    Vielleicht habe ich in wenigen Tagen genügend Muße dazu, dies zu versuchen.

    Fazit:

    Das, was du als Ziel formuliertest, ist prinzipiell geringfügig abgewandelt implementierbar.

    Ob die Reaktionszeiten nach einem Tastendruck erträglich sind, muss im Feldversuch getestet werden. Da ich auch per i4 und Skript steuere, kann ich eine kurze Reaktionszeit in Aussicht stellen.

    Selbstverständlich sind die Handhabungen per kurzem und langem Tastendruck auch vertauschbar.

    Nachgereicht:

    Diese Lösung funktioniert auch dann, wenn zwischendurch eine andere steuernde Quelle genutzt wird, wie Shelly Button 1, Web UI, Sprachassistent (Hey Google, Alexa, Iris, ...), weil der Plus 2PM immer dann seine Nachricht an den i4 sendet, wenn sich sein Status ändert.

    Offensichtlich kennt ChatGPT kein Shelly Script. :S

    kuhniwerle

    Per Skript könnte es gelingen.

    Dazu müsste das Skript nach einem Reboot bzw. nach seinem ersten Start erst einmal den Rollladen bis zu einer Endposition fahren, rauf oder runter. Dann "kennt" das Skript die aktuelle Position.

    Ein wesentliches Problem bleibt aber.

    Du fährst mit long den Rollladen runter und stoppst diesen mit kurz.

    Wie soll danach das Skript bei einem long reagieren?

    Es könnte gegenteilig fahren, also rauf.

    So ist es unmöglich, nach einem Stop den Rollladen weiter in der zuvor genutzten Richtung zu fahren.

    Wenn dir dies genügt, kann es per Skript gelöst werden, weil das Skript die zuletzt genutzte Fahrrichtung speichern kann, evtl. sogar nichtflüchtig für den Fall eines zwischenzeitlichen Stromausfalls.

    Ich nutze zwei i4 Taster je Rollladen mit Skript hierfür. Das Skript hat den Vorteil, dass die Tastdauer erfasst und so beliebig genutzt werden kann, es gibt also nicht nur ein long push.

    Ein Skript kann also prinzipiell mit unterschiedlichen Druckdauern arbeiten. Der von horkatz vorgeschlagene double push ist erheblich leichter implementierbar.

    Flo Rian bambam

    Um welchen Shelly handelt es sich bei dir?

    Falls es ein Shelly der zweiten Generation (mit Plus im Namen) ist, wäre vermutlich ein Workaround bzw. Adaption per Skript möglich.

    Dazu wären alle erforderlichen Daten erforderlich.

    1. Welche Daten (Status, Messwerte, ...) sollen mitgeteilt werden?
    2. Wie soll der Shelly gesteuert werden?
    3. Welche Topics sind erforderlich?

    Uiuiui ...

    mir erscheint es riskant, Frostschutz mit einer Umwälzpumpe zu betreiben. Die Leitungsrohre/-schläuche sind nach meiner Einschätzung dafür zu dünn, obwohl sie nicht wirklich dünn sind.

    Wenn du keine solchen Schläuche haben solltest und die Pumpe unmittelbar am Skimmer sitzt und der Rücklaufeinlass ebenso, mag das gelingen.

    Schließlich ist es deine Sache, es zu riskieren.

    Folgendes zu deiner Darstellung.

    Dass der Uni nicht direkt schalten kann, wirst du sicher wissen. An seine Optokoppler-Ausgänge ist also jeweils ein Relais oder ein Triac oder so anzuschließen, das genügend starke Ströme zum Betrieb des Motors schalten kann.

    Die Einstellung für die Eingänge hängen davon ab, wie du manuell steuern willst, per Taster oder per Schalter.

    Versuche zunächst, deine Ziele per Webhooks/Actions zu erreichen! Damit gelingt bereits einiges.

    Bei der Funktion "Aktion bearbeiten" beim DS18B20 gibt es die Funktion "Wiederholen wann"

    Das kann der Verhinderung von dichteren Actions dienen bzw. um Retriggerung zu vermeiden.

    Allgemein gilt:

    Je komplexer die Steuerung bzw. deren Bedingungen sind, desto stärker ist die Tendenz zur Nutzung

    1. eines übergeordneten Systems - weniger autark als die folgende Alternative - oder
    2. eines Skriptes in Kombination mit Zeitplänen (Schedule Jobs)

    Ich nutze bevorzugt 2., weil ich damit bisher noch alles implementieren konnte, was gewollt ist.

    Da dies auch eine Sicherheitseinrichtung sein soll, empfehle ich eindeutig die autarke Lösung, also per gut getestetem Skript und "Auffangnetz".

    Das "Auffangnetz" ist ein Schedule Job, der in bestimmten Abständen das Skript startet. Läuft es noch, stört das nicht.

    Während einer längeren Probephase ist zusätzlich regelmäßig eine Protokollierung zu analysieren. Als Protokollierung kann entweder diejenige der Firmware oder eine anwendungsorientierte per Skript genutzt werden.

    Btw, in meinem ehemaligen Pool habe ich immer das Wasser bis unter die Schläuche/Skimmer ... abgelassen und dem Wasser Frostschutz zugegeben.

    Nachgereicht das "Sicherheitsnetz":

    Es kann per Browser Adresszeile (URL) angelegt werden. (ungetestet aus dem Gedächtnis)

    Code
    http://<IP-Adresse deines Shelly>/rpc/schedule.create?timespec="0 * * * * *"&calls=[{"method":"script.start","params":{"id":<Skript Id>}}]

    Dieser Job gibt zu jeder vollen Minute die aufgeführte(n) Methode(n) in Auftrag, was recht sicher funktioniert - solange kein Datum und keine Wochentage spezifiziert sind auch ohne synchronisierte Zeit. Hierzu sind am besten Zeitabstände geeignet - */5 bedeutet alle 5 (Sekunden bzw. Minuten bzw. Stunden).

    Wenn dieser Job angelegt ist, kannst du anschließend die Zeiteinstellung relativ leicht per Web UI ändern. Siehe hierzu auch den Artikel "Mächtige Schedule Jobs" von mir.

    Auch ist es möglich mehrere calls-Einträge zu verwenden, damit zum Zeitmuster mehrere Aktionen durchgeführt werden. Diese können per Mthode "HTTP.GET" auch remote wirken.

    Noch etwas fiel mir nachträglich auf.

    Du nutzt die globale Variable status in mehreren Funktionen, obwohl status dort nur zur synchronen Abfrage gebraucht wird und keinen Einfluss auf andere Skriptteile hat.

    Deshalb empfehle ich, in den Funktionen status lokal zu deklarieren mit

    let status = ...

    Auch wenn dies hier noch keine Rolle spielen sollte, dann können sich keine sog. Seiteneffekte ergeben.

    Du kannst selbstverständlich anwendungsorientiert protokollieren lassen.

    Ich setze mal voraus, dass kein übergeordnetes System zum Zuge kommt und evtl. das Protokoll viele Zeilen umfassen können soll.

    Dann bietet sich das Speichern in einer Datei an, ich nenne sie mal "log". log wird wie ein Skript genutzt, obwohl sie kein Skript ist.

    Dort passen aber relativ viele Zeilen hinein.

    Ich habe etwas ähnliches für einen Freund erstellt.

    Wenn es dich interessiert, ich habe die Beschreibung veröffentlicht, allerdings (noch) ohne das Skript selbst.

    Du wirst vermutlich an die Ausgangsklemmen herankommen. Bei 12V Versorgung kannst du zumindest alle Klemmen und angelötete, nach außen führende Leitungen testen.

    Mit einem Multimeter könntest du bei Änderung der Sensorbefeuchtung die verschiedenen Spannungen messen. Falls sich dabei eine Spannung verändert, hast du zumindest eine Ausgangsklemme erwischt. Dann ist noch zu prüfen, wie sich diese Spannung verändert.

    Ändert sie sich sprunghaft von niedrig zu hoch, handelt es sich höchstwahrscheinlich um ein binäres Signal.

    Zusätzlich kannst du mit der Sensorbefeuchtung in möglichst kleinen Schritten experimentieren. Nimmt dann diese Spannung zwischenwerte ein, ist sie analog.

    Mir gefällt dein Skript. Wegen des gut strukturierten Codes will ich nicht meckern. :thumbup:

    Trotzdem folgende Dinge, falls es dich interessiert. Wenn nicht, ignoriere meine Hinweise einfach! ;)

    1. user defined parameter ist rein optional. An solchen null zu übergeben und ud nicht zu nutzen, ist absolut überflüssig.
    2. In JavaScript gibt es den Vergleichsoperator, der auf Wert und Typ prüft (===). Im Zweifelsfall könnte dies zielführend sein.
      Der entsprechende ungleich Operator ist !==.
      Dies kann eine Rolle spielen, da diese Sprache nicht typenstreng ist.
    3. Zum schalten muss nicht vorher geprüft werden, ob der Ausgang bereits den angestrebten Zustand hat. Du erreichts damit allenfalls, dass laufzeitabhängig ein ggf. überflüssiger Methodenaufruf nicht stattfindet.

    status = isTurnedOn();

    // print ("turnOff called, status=" + status);

    if (true == status) {

    Hier genügt bspw.

    if(isTurnedOn()) {

    allerdings nur ohne die Ausgabe zwecks Test/Prüfung.

    Mit status genügt

    if(status) { // status beinhaltet bereits einen Wahrheitswert, der muss nicht noch mit true, oder an anderer Stelle mit false, verglichen werden.

    Ich weiß, dass dies sehr, sehr oft zu finden ist. Das erscheint mir aber sehr stereotyp. Und Häufigkeit hat nichts mit Qualität zu tun. :S

    Berry Programm? Meinst du auf einem Raspberry? das ist schon zu "gross".

    Nein, kein Raspberry Pi.

    Wenn man Tasmota32 (nur für ESP32 Boards) nutzt, steht auch die Programmierumgebung, ein online Editor, zum Erstellen von Programmen zur Verfügung, die in der Programmiersprache Berry erstellt werden. Diese ist C affin und bietet so einiges, was es in Shelly Script nicht gibt. Ich mag Shelly Script insbesondere wegen des gut strukturierten API und der mächtigen Schedule Jobs.

    Ich habe seit langem kein Berry Programm mehr erstellt, weiß aber noch folgendes.

    Es gibt eine Berry Konsole, in welcher man Berry Kommandos eingeben und damit testen sowie experimentieren kann.

    Bei laufendem Berry Programm kann man bspw. Variableninhalte ausgeben lassen und auch Funktionen aufrufen.

    Es steht ein einfaches Dateisystem zur Verfügung, in welchem man seine Berry Programme ablegen kann.

    Berry ist eine Hybridsprache, Quellcode wird in Dateien mit Suffix .be abgelegt. Ein Compilat erhält das Suffix .bec. Der kleine Interpreter arbeitet solche .bec Dateien ab, die geladen wurden.

    In eine Datei autoexec,be trägt man am besten per load <Dateiname> die Dateien ein, die mit dem Booten geladen und ausgeführt werden sollen. .be Dateien werden mit dem Laden automatisch compiliert, das Compilat in einer .bec Datei abgelegt und ausgeführt.

    Berry ist sehr interessant und man kann von Rules Berry Funktionen aufrufen lassen - mit Parameterübergabe.

    Per Berry kann man auf die flüchtigen (Varx) und die nichtflüchtigen (Memx) Rules-Variablen zugreifen.

    Die Rules sind Ereignis gesteuert und somit die Berry Funktionen auch.

    Es ist sogar möglich, per Berry externe Hardware (Sensoren, Aktoren) direkt anzusprechen (Gerätetreiber), was ich aber nie ernsthaft tat.

    Inzwischen soll es weitere Möglichkeiten geben, die ich (noch) nicht kenne.

    Ich habe ein wenig dazu dokumentiert.