Damit das Skript nach einem Reboot automatisch gestartet wird, musst du es nur "enablen" - Schiebeschalter-Symbol rechts.
Beiträge von eiche
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.
-
-
Sobald in Abständen von ca. 1 Minute die gemessenen Temperaturwerte eintreffen, kannst du diese jeweils einmalig verarbeiten lassen. Dann liegt das Timing in erster Linie am System, welches diese drei Ereignisse mitteilt. Vermutlich sollte das genügen, da die Temperaturen sich nicht schnell verändern dürften.
Willst du aber das Timing sekundengenau selbst festlegen, dann sind hierfür die schedule jobs bestens geeignet. In diesen können von dir festgelegte Funktionen deines Skript aufgerufen werden. In einer solchen Funktion kannst du eine Temperatur abfragen und speichern. Da hier in der Anzahl limitierte RPC erforderlich sind, empfehle ich dir, zu jeder Temperaturabfrage einen separaten schedule job und eine separate Funktion. Es genügt, wenn die schedule jobs jeweils 1 Sekunde auseinander liegend deine Funktionen aufrufen. In einem vierten schedule job lässt du dann die Verarbeitungsfunktion aufrufen, welche deinen Motor steuert. All dies geschieht dann einmal in jeder Minute.
Beispiele für die timespec Werte der schedule jobs:
0 * * * * * zum Abfragen der ersten Temperatur + speichern
1 * * * * * zum Abfragen der zweiten Temperatur + speichern
2 * * * * * zum Abfragen der dritten Temperatur + speichern
3 * * * * * zur Verarbeitung der Temperaturwerte und Steuerung des Motors
Du kannst die Sekundenabstände selbstverständlich auch größer wählen.siehe hierzu auch https://shelly-api-docs.shelly.cloud/gen2/Component…rvices/Schedule
Ich habe in einem aktuellen Projekt solche schedule jobs verwendet und zum Anlegen solcher Jobs eine Webseite erstellt. Die passt zwar nicht zu deinem Projekt, dort kannst du dir aber mal ansehen, wie solche schedule jobs per HTTP GET angelegt werden können.
Edit:
Es ist auch möglich die schedule trigger mehrmals pro Minute zu nutzen. Dann verwendest du statt 0 bis 3 in den Sekunden */10 (in 10 Sekunden Abständen) oder bspw. */20 (in 20 Sekunden Abständen). Für die oben erwähnten schedule jobs müsste ich noch sorgfältig über passende timespec Werte nachdenken. Alternativ ließe sich nur ein solcher schedule job einsetzen und im Skript Timer verwenden.
-
Der Eventhandler ist keine Endlosschleife. Auch das Skript ist es nicht. So etwas gibt es in der Arduino Programmierung und heißt dort loop().
Teile eines solchen Skripts werden durch Ereignisse aufgerufen, wie bspw. deine anonyme Eventhandler Funktion innerhalb des Aufrufs von Shelly.addEventHandler().
Hierbei wird dem System (Firmware) mitgeteilt, welche Funktion aufzurufen ist, wenn ein Ereignis eintritt, wie bspw. das Messen einer Temperatur.
Anonym ist die Funktion deshalb, weil sie keinen Namen erhält. Es ginge auch anders:
Codefunction processData(event) { // process the imported event info } Shelly.addEventHandler(processData);
Diese Eventhandler Funktion ist nicht anonym, weil sie einen Namen erhält (processData).
Es ist wichtig, zu verstehen, dass ausschließlich Ereignisse die Abarbeitungen im Skript triggern müssen. Vermeide jegliches Warten per Schleife auf ein solches Eintreffen!
Andere Ereignisse können bspw. solche sein, die per Zeitplan, hier schedule job genannt, ausgelöst werden.
Das musst du jetzt noch nicht alles wissen oder genau verstehen. Es ist aber zweckmäßig, dass du schon einmal davon gelesen hast und nachsehen kannst, wenn du einen entsprechenden Fehler in dein Skript einbaust.
Falls du schon einmal Tasmota mit Rules verwenden haben solltest - für die Tasmota Rules gilt das Gleiche bzgl. Ereignissteuerung.
Edit:
Die Anweisungen im Skript werden mit dem Skript Start genau einmal abgearbeitet. Dies ist bspw. das Anlegen von Variablen/Objekten und insbesondere das Eintragen einer Eventhandler Funktion. Shelly.addEventHandler(...) ist eine solche Anweisung, die mit dem Start des Skripts ausgeführt wird und die veranlasst, dass beim Eintreffen eines Event die von dir gewünschte Funktion aufgerufen wird.
-
Ich bin ja ein Anhänger von Code reduzierenden Datenstrukturen und täte es wie folgt implementieren.
-
Du kannst in der Eventhandler-Funktion bspw. nach event.info.event==="temperature_measurement" selektieren. Dann ist die Reihenfolge weniger "wirr". Auch erhältst du so in regelmäßigen Abständen von ca. 1 Minute die Temperaturwerte. Mit temperature_change kommen nur Werte bei Temperaturänderung rein, was auch genutzt werden könnte, aber hier nicht erforderlich ist.
Code
Alles anzeigen// Vor dem Eventhandler: let Status = { Location1: {Temp:null}, // und mehr nach Bedarf Location2: {Temp:null}, // dito Location3: {Temp:null} // dito }; // Innerhalb des Eventhandlers: let i = event.info; // Nur, damit der Quellcode eetwas kürzer wird. if (i.event==="temperature_measurement") { if (i.id===100) Status.Location1.Temp = i.tC else if(i.id===101) Status.Location2.Temp = i.tC else Status.Location3.Temp = i.tC; // und weiteres bei Bedarf, evtl. Verarbeitungsfunktion aufrufen }
Statt LocationX solltest du für deine Zwecke passende Namen wählen, auch müssen die LocationX keine Objekte sein. Wenn du darin nicht zusätzliches speichern willst, genügt es, dort direkt die Temperatur abzulegen. Dann wird der jeweilige Zugriff etwas kürzer.
Die Verarbeitung der Temperaturen (in Status) kann direkt im Eventhandler erfolgen oder später an anderer Stelle. Bei unmittelbarer Verarbeitung solltest du die Werte zuvor auf ungleich null prüfen lassen. Hier empfiehlt sich der Aufruf einer Verarbeitungsfunktion.
-
Solltest du noch ein Relais für 24V mit zwei Umschaltern, also 2 mal 3 Kontakten liegen haben oder günstig ergattern können, wäre dies zu empfehlen. Damit kannst die den gewünschten Betrieb realisieren.
Ich habe mal schnell bei Amazon nachgeschaut. Andere Händler täte ich auch abfragen wie Reichelt, Voelkner ...
Mit diesem Relais sollte dein Anliegen leicht erfüllbar sein.
Btw, mit zwei pnp-Transistoren und passenden Parametern sollte dies auch gelingen. Das brauchte dann weniger Strömchen.
... oder vielleicht FETs
Womöglich könnte im Motorgehäuse etwas elektrisch entfernt werden, damit er auch auf Masse Schalten passend reagiert. Vermutlich würde dies bspw. thgoebel oder DIYROLLY versuchen.
-
Wenn der Motor eine interne Elektronik hat, sind deine Bedenken berechtigt.
Ohne interne Elektronik sollte es afaik unerheblich sein, ob der Shelly - oder + schaltet.
Im ersten Fall wären
zweizusätzliche Relais oder Transistorschaltungen geeignet.Ein Polwende-Relais genügt. Das ist ein Relais mit zwei Umschaltkontakten. -
Ich finde es erstaunlich, dass der Motor auch läuft, wenn beide Plus-Anschlüsse Strom erhalten.
Ich wollte dies jedenfalls vermeiden, was technisch ja kein Problem darstellt.
Btw, du kannst im Shelly Plus 2 den Roller Modus einstellen, per Actions das gewünschte Verhalten konfigurieren oder dies per Skript steuern.
Wenn es per konfigurieren gelingen sollte, täte ich dies nicht im Skript implementieren.
-
Nö, einen Shelly Plus 2 oder Pro 2 einsetzen - besser ist das.
Wegen des AddOn selbstredend einen Plus 2 ...
Warum mehr Devices als erforderlich?
-
Klar.
Deshalb sind dafür die Schedules bestens geeignet.
-
Aha, danke an Seven of Nine, ich las diesen ursprünglichen Beitrag jetzt auch.
Die Temperaturdifferenzen zu ermitteln ist per Skript sehr leicht. Ich empfehle dir dazu Schedule Jobs einzusetzen, welche nacheinander und in regelmäßigen Abtänden folgendes triggern.
- Temperaturwerte erfassen (einlesen oder kopieren) - Job 1
- Differenzen der vorliegenden Temperaturen berechnen und speichern - Job 2
- An Hand der gespeicherten Temperaturdifferenzen die gewünschten Aktionen auslösen - Motorsteuerung unter Verwendung von Timer.set() schalten - Job 3
Die von dir als Komfort angesehene Zeitsteuerung ist per weiterer Schedule Jobs ebenfalls kein Problem.
Falls du Kenntnisse von Unix Cron Einträgen hast, werden dir die Schedule Jobs nicht schwer fallen. Du brauchst halt zusätzlich Kenntnisse von den RPC und JSON.
-
Die Firmware ist imho sehr gut, weil sie viele Möglichkeiten bietet. Wenn man das erst einmal erkennt, nerven die RPC nicht mehr. Dann sind diese Remote Procedure Calls schlicht sehr erfreulich.
Inzwischen verstehe ich, dass damit das System offen und sehr vielseitig nutzbar ist.
Anfangs muss man sich halt eine höhere Frustrationsschwelle zulegen.
-
Nach vielen Tests und einigen Ergänzungen habe ich das Skript und weiteres an dieser Stelle zur Verfügung gestellt.
Alle daran Interessierte dürfen mich gerne danach und nach Einzelheiten der Implementation fragen.
Viel Erfolg damit.
-
-
Mit einem Web-Frontend pflegst du dein Skript. Verbinde dich doch einfach mal per Browser mit deinem Shelly Plus X und sieh dir die Oberfläche an!
Vergiss dazu die Cloud!
Und bringe vorher den Shelly in dein WLAN. Danach führst du ein Firmware Upgrade durch. Dann findest du leicht die Abteilung Script. ...
Die Skripte laufen ausschließlich auf den Shellies. Die Firmware bietet ein vielseitiges API. Insbesondere die RPC solltest du testen, was auch per HTTP GET gut geht - auch ohne Skript.
Ein einfaches Beispiel: http://<ip-address>/rpc/script.list
Dieses zeigt dir alle deine auf dem Shelly gespeicherten Skripte und ob sie gerade laufen ...
Informationen zu den Remote Procedure Calls: https://shelly-api-docs.shelly.cloud/gen2/General/RPCProtocol
-
Noch etwas:
Du musst unbedingt das JSON Format kennen! Ohne diese Kenntnisse wirst du dich sehr schwer tun.
Zwei Methoden stehen zur Verfügung.
JSON.stringify(Objekt) liefert die Struktur als String, auch zum Senden von Nachrichten geeignet.
JSON.parse(String) macht das Umgekehrte. Ein String im JSON Format wird in ein Objekt (Struktur) transformiert (geparst), wenn der String fehlerfreies JSON enthält.
-
https://shelly-api-docs.shelly.cloud/gen2/Addons/ShellySensorAddon
Dieser Link führt dich direkt zu den AddOn. Da geht es aber um das Einbinden und Konfigurieren von Sensoren.
Zum Abfragen eines Sensors ist dieser Link geeignet: https://shelly-api-docs.shelly.cloud/gen2/Component…ces/Temperature
Am einfachsten geht es aber per Eventhandler, den du relativ leicht hinzufügen kannst:
https://shelly-api-docs.shelly.cloud/gen2/Scripts/S…ddstatushandler
Die Firmware liefert in regelmäßigen Abständen von ca. 1 Minute die Sensorwerte als Ereignis, welches dein Eventhandler nur entgegenzunehmen braucht. Zusätzlich kommen auch Sensorevents rein, wenn sich der Messwert ändert.
Zum Skripten gibt es ein sehr grundlegendes Tutorial, welches allerdings nicht sehr weit führt:
https://shelly-api-docs.shelly.cloud/gen2/Scripts/Tutorial
Am besten ist es, wenn du folgendermaßen beginnst:
Dies gibt dir die Informationen aus, welche mit dem Event reinkommen. Diese solltest du dir genau ansehen und versuchen, das herauszuarbeiten, was du brauchst.
Btw, recht gute Informationen zu verschiedenen Sprachen sind bei https://www.w3schools.com/ zu finden, auch zu JavaScript.
Durcharbeiten musst du aber selbst.
-
horkatz thgoebel @dekat win und andere
Zum Entwicklungs-Zwischenstand der Hauptuhr-Emulation per Shelly Plus 2:
Ich habe mittlerweile das Projekt auf einer Website beschrieben.
Mit diesem Link geht es dorthin.
Es fehlt nur noch die Möglichkeit die angezeigte Uhrzeit per Software einzustellen. Das sollte mein (vorläufig) letzter Schritt in diesem Projekt sein.
Danach will ich das Skript zusammen mit einer Installationsanleitung auf obiger Website zur Verfügung stellen.Btw, die automatische Zeitumstellung funktionierte, sogar bei "Stromausfall" während der offiziellen Zeitumstellung.
-
Noch ein paar Hinweise zur Reduktion der RPC (Shelly.call()) und der Timer in einem Skript:
- Wann immer es möglich ist, kann eine Verzögerung eines RPC-Aufrufs - per Timer oder, wie in meinem Projekt per Schedule Job, die Akkumulation an laufenden RPC verringern.
- Entsprechendes gilt für Timer. Wann immer ein Timer durch einen Schedule Job ersetzt werden kann, würde ich den Schedule Job bevorzugen - es sei denn, es sind bereits viele davon aktiv.
- Bei Verwendung des KVS mit mehreren Einträgen lassen sich alle diese Einträge bspw. durch Verwendung eines gemeinsamen Prefix per Shelly.call("KVS.GetMany", {"match":Prefix+'*'} ... mit einem statt mehrerer RPC einlesen und in der empfangenen Datenstruktur selektieren - auch fehlertolerant.
Alternativ kann man stattdessen eine größere Datenstruktur in JSON einsetzen und per "KVS.Get" mit dem key arbeiten. Letzteres empfiehlt sich aber nur dann, wenn beim Schreiben in den KVS alle Komponenten der Struktur auf einmal geschrieben werden. Andernfalls empfehle ich, das Prefix einzusetzen, damit möglichst wenige Schreibzugriffe mit möglichst kleinen Umfängen stattfinden.
zu 3. In meinem Projekt wird der timestamp zum Minutenimpuls naturgegeben minütlich gespeichert, während ein Abstandswert bei Zeitumstellungen nur zweimal im Jahr gespeichert wird. Deshalb verwende ich dort die Prefix-Variante.
Die Limits sind unangenehm, aber verständlich. Und das API stellt imho hinreichend viele Varianten zur Verfügung, um viele Probleme damit umgehen zu können. Hier ist halt, wie so oft in der Entwicklung, Kreativität gefragt.
-
@dekat win
ZitatFunktioniert deine Uhr nur über Sekunden Pulse? Dann könnte man das 5 Timer Limit damit umgehen und eine Art Easy Delay zusammenbauen.
Wie hast du die Last Verzögerung kompensiert?
Es wäre toll, wenn du deinen Code in einem Beitrag unter Vorlagen verlinken könntest.
Die vom Shelly plus 2 gesteuerte Nebenuhr ist, streng betrachtet, nur eine Anzeige, deren Zeiger im Minutentakt durch Pulse weiterrücken. Die Uhr besitzt selbst keinerlei Taktgeber.
Ich lasse also minutenweise Pulse per Ausgänge ausgeben. Ein Ausgang führt den Taktimpuls, der andere sorgt für die erforderliche Umschaltung eines Polwenderelais.
Ausgang 2 reagiert per simpler Shelly-Konfiguration auf Ausgang 1. Mein Projekt besteht aus dem Skript (inkl. KVS-Einträgen) und drei Schedule Jobs.
Der erste Schedule Job mit einem timespec="59 * * * * *" und einem Funktionsaufruf im Skript per Methode "Script.Eval" sorgt für die Ausgabe der minütlichen Pulse an die Uhr.
Per Eventhandler beim Schalten von Ausgang 1 lasse ich einige Prüfungen vornehmen, die Zeit betreffend.
Darin wird ermittelt, ob zwischenzeitlich der Shelly bzw. das Skript nicht arbeitete (typischerweise wegen Stromausfall). Ist dies der Fall, wird auf den zweiten Schedule Job gewechselt, der (aus guten Gründen) in 2s Abständen dieselbe Funktion aufruft wie der erste Job. Damit wird die Uhr in kurzer Zeit auf die richtige Anzeige geführt. Danach wird wieder auf den ersten Job gewechselt, der für die minütlichen Pulse sorgt.
Du siehst daran, dass hierfür kein Timer.set gebraucht und auch nicht eingesetzt wird.
Trotzdem brauche ich wegen der Asynchronität bei RPC Aufrufen und beim Stellen der Uhr (bspw. Zeitumstellung) Verzögerungen per Timer.set. Dies ist u.a. wegen möglicher Stromausfälle erforderlich, da der timestamp des letzten Impulses persistent - im KVS - gespeichert werden muss.
Dieser und ein zweiter Wert wird immer beim Start des Skripts (bspw. nach Power On) in den RAM kopiert, um damit einen synchronen Zugriff zur Verfügung zu haben.
Ich gerate tatsächlich mitunter an die Grenze von 5 zugleich arbeitenden RPC, weshalb ich das Timing zur Prüfung auf Zeitumstellung einem dritten Schedule Job überlassen muss.
Dieser hat den timespec="29 * * * * *" und ist somit zeitlich verzahnt mit den beiden anderen Jobs. Damit reduziere ich die gleichzeitig aktiven RPC, damit sich (hoffentlich) kein Skript-Abbruch wegen zu vieler RPC ereignet.
Das Projekt befindet sich in einer Beta-Version und wird von mir und einem Mitstreiter weiterhin getestet.
Fazit zu deinen Fragen:
Ja, es ist notwendig, die Anzahl an Timer.set soweit wie möglich zu reduzieren, was ich per Schedule Jobs erreiche.
Falls eine Nebenuhr sekündliche Pulse brauchen sollte, würde ich einen weiteren Shelly Gen 2 einsetzen, welcher diese liefern kann. Damit wäre mein jetziger Shelly mit Skript ... tatsächlich überfordert.
Im timespec von Schedule Job 1 kann man bei längeren Verzögerungszeiten der Uhr, bspw. wegen träger Mechanik, den Sekundenwert reduzieren, bspw. auf 58 oder 57, was ja am Minutentalkt nichts ändert.
Die Dauer der Pulse ist in den ersten beiden Schedule Jobs im Aufruf der Skript-Funktion als Parameter eingebaut und kann leicht per Schedule.Update dem Bedarf angepasst werden.
Ohne diese Schedule Jobs wäre das Projekt in meiner jetzigen Fassung nicht implementierbar. Es ist tatsächlich sehr wichtig, mit den RPC- und Timer-Ressourcen sparsam umzugehen und auf deren Limits zu achten.
Beispiel eines RPC zum Anlegen des ersten Schedule Jobs (aus dem Gedächtnis):
http://<ip-address>/rpc/schedule.create?timespec="59 * * * * *"&calls=[{"method":"script.eval","params":{"id":1,"code":"pulse(100)"}}]
Dieser Job ruft minütlich bei Sekunde 59 im Skript mit Id=1 die Funktion pulse(100) auf, worin 100 eine Pulsdauer von 100ms festlegt.
Bei weiteren Fragen stehe ich zur Verfügung.
Ich bin evtl. bereit, den Skriptcode hier zur Verfügung zu stellen - allerdings nicht in der noch vorliegenden Laborversion. Diese Version muss ich gelegentlich noch von Zustandserfassungsnachrichten für Testzwecke und Fehlersuchen befreien. Dann bin ich nach einer ausreichenden Testphase prinzipiell bereit, den Skriptcode hier zur Verfügung zu stellen. Oder ich platziere diesen dann zusammen mit einer Installationsanleitung auf einer meiner Websites und verlinke von hier dorthin.
Gruß aus Rheinland-Pfalz
Edit:
Evtl. sind in meinen obigen Erläuterungen kleinere, aber unwesentliche Fehler enthalten, weil ich diese zügig herunterschrieb. Im wesentlichen stehe ich aber zu diesen Erläuterungen und weiß an allen Stellen des Skripts und der Zusätze (Schedules, KVS) wofür diese zuständig sind.