Hast du mal die Methode Script.SetConfig versucht?
Falls die Firmware eine Chance hat, darauf zu reagieren, wird mit folgendem URL der automatische Start verhindert.
Danach reboot ...
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.
Hast du mal die Methode Script.SetConfig versucht?
Falls die Firmware eine Chance hat, darauf zu reagieren, wird mit folgendem URL der automatische Start verhindert.
Danach reboot ...
Teste doch einfach die Lösung von thgoebel in #2!
Sorge zuerst dafür, dass der AP des Shelly aktiv ist und gib diesem ein Passwort!
Deaktiviere dann die Cloud und am besten entferne den Shelly aus dem WLAN!
Dann führe den Funktionstest durch.
Du kannst dann immer noch den Shelly über dessen Access Point erreichen.
Was hast du denn wildes in deinem Skriptexperiment versucht?
oder wenigstens im lokalen Netz ansprechen können
Also hast du dessen Access Point deaktiviert.
Für zukünftige Experimente/Projekte:
Lasse den AP des Shelly zusätzlich aktiv und gib ihm ein Passwort!
Dann wirst du ihn per IP Adresse 192.168.33.1 ansprechen können, nachdem du dein Endgerät mit seinem WLAN gekoppelt hast.
Wenn alle Versuche fehlschlugen, ist der Shelly vielleicht defekt.
Dein Skriptskelett in #1 startet sich nicht selbst. Dies wäre ohnehin paradox. Ein laufendes Skript sich selbst starten zu lassen, obwohl es schon läuft?
Im Ernst:
In einem Shelly Skript gibt es keine Endlosschleife. Ein solches Skript sollte, wenn es etwas zielführendes tun soll, Ereignis gesteuert arbeiten.
Du kannst etwas ähnliches nachbilden per Timer, der eine Funktion periodisch aufruft.
Dafür gibt es Methoden.
Zum Factory Reset sollte diese Methode führen: Shelly.FactoryReset
Solange der Plus 1 bzw. Shelly ab der zweiten Generation erreichbar ist:
http://<IP Adresse>/rpc/shelly.factoryreset
Ich habe es nicht getestet, rechne aber wegen der eindeutigen Dokumentation damit, dass dies funktioniert.
Edit:
Interessant wäre ein Versuch, dies per Skript zu realisieren:
Folgende Anweisung sollte hierfür genügen.
Ich habe mir etwas tiefergehend die Webhooks (=Actions) angesehen.
Prinzipiell ist es möglich, das Skript auf dem Plus 2PM (s. #11) durch 5 Webhooks zu ersetzen, aber ...
Beispiel zu 2.
Wenn ich einem Endpoint eine strukturierte Information übermitteln will, in welcher der Device Name enthalten ist, so kann dieser leicht per RPC Aufruf in einem Skript geholt werden. Ich habe viele Experimente per Token in einem Webhook durchgeführt und hatte keinen Erfolg, wohl hauptsächlich, weil es hierzu an Dokumentation oder durchgreifendem Konzept fehlt.
Fazit: Wenn ausgefeilte, nicht vorgefertigte Pfade beschritten werden sollen, sind Skripte den Webhooks deutlich überlegen. Dann stoßen Webhooks bereits früh an ihre Grenzen.
Falls per Methode Webhook.Create oder Webhook.Update doch noch ausgefeiltere Dinge möglich sein sollten, werde ich gerne meine Aussage relativieren.
Btw, da gibt es einen kleinen verräterischen Fehler in der Dokumentation - im ersten Absatz. Vielleicht finde ich noch weitere.
Zitat
A revision number is maintained which is incremented on every update of the schedules.
Vermutlich wurde hier aus der Doku zu Schedule kopiert und unter Webhook eingefügt. Richtig sollte es lauten:
A revision number is maintained which is incremented on every update of the webhooks.
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.
let Destination = "172.16.3.66", // IP address of the cover controller
ButtonId = 0,
longPushURL = "http://" + Destination + "/rpc/cover.close?id=0",
shortPushURL = [ // Datenfeld aus zwei URL, Zugriff per Index 0 oder 1
"http://" + Destination + "/rpc/cover.open?id=0",
"http://" + Destination + "/rpc/cover.stop?id=0"
],
Sel = 0; // selected shortPushURL Index
function receiveStatusCover_0(request) {
if(request.method==="GET" && request.query!==undefined) {
print(request.query);
Sel = request.query==="stopped" || request.query==="closed" ? 0 : 1; // für short push vorselektieren
}
}
HTTPServer.registerEndpoint("Cover_0", receiveStatusCover_0);
function handleButton(event) {
// print(JSON.stringify(event)); // zwecks Analyse aller eintreffenden Events
if( // das passende Event filtern, vorfiltern per component "input:<ButtonId>"
event.component==="input:" + ButtonId
// && // passende Filter hinzufügen
) {
print(JSON.stringify(event)) // zwecks Analyse der hier zu verarbeitenden Events wie push und long push
// Sobald klar ist, welche Infos zur Weiterverarbeitung zu nutzen sind, die folgenden Anweisungen passend ergänzen und Kommentarsymbole (//) entfernen!
let Url;
// if(<long push selektieren>) Url = longPushURL;
// else Url = shortPushURL[Sel];
// Shelly.call("http.get", {url:Url}); // für das Verarbeiten des Tastendrucks
}
}
Shelly.addEventHandler(handleButton);
Alles anzeigen
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:
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:
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.
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:
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
Mir fiel noch eine Lösung ein. Ich setze kein übergeordnetes System und keinen MQTT Broker voraus.
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
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.
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.
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.
Gibt es einen Grund, weshalb du an die Relais den L an NO legst und nicht an COM?
Ich jedenfalls hätte den L an COM gelegt.
Ich weiß, dass es auch so geht.
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.
Wenn du klein anfangen kannst, also nicht gleich das Endprodukt brauchst, kann ich dir bei Bedarf sukzessive helfen.
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
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)
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.
Ich interpretiere dein "Nein" in Bezug auf die ausschließliche Nichtfunktion des Ausschaltens.
Wenn das gemeint war, kannst du dann dein Nein begründen?
Ansonsten stimme ich dir selbstverständlich zu.