Ein Skript ist ausschließlich ereignisgesteuert zu erstellen. Warteschleifen führen zumeist zu erheblichen Problemen und Skriptabstürzen.
Wer daran gewöhnt ist, bspw. ein Arduino-Mikrocontrollerboard per Arduino-Entwicklungsumgebung zu programmieren, wird vermutlich gewisse erste Umstellungsschwierigkeiten bei Shelly Skripten erleben. Die Programmierung eines Arduino erfolgt in der Programmiersprache C++ bzw. einer Teilmenge derselben. Aber das ist nicht das eigentliche Problem. Die Arduino-Programmierung beinhaltet zumindest eine Initialisierungsfunktion setup() und eine zyklisch abgearbeitete Funktion loop(). Letztere entspricht etwa einem SPS-Programm. loop() wird im Hintergrund per abgearbeiteter Schleife zyklisch aufgerufen. Man implementiert darin das, was zyklisch abzufragen und ggf. auszuführen ist. In Shelly-Skripten ist dies völlig anders.
Hier wird ein Programmcode zur Verfügung gestellt und zur Ausführung aktiviert, der keiner Abarbeitung in einer Schleife unterliegt. Zuallermeist wird, vereinfacht dargelegt, das Skript wartend nichts tun. Genau genommen wartet es nicht einmal. Es sollte ausschließlich Funktionen beinhalten, die von der zugrunde liegenden Firmware aufgerufen werden können. Solche Aufrufe werden durch Ereignisse (events) ausgelöst, welche von der Firmware erfasst und verarbeitet werden. Einer solche Verarbeitung kann per Skript ein zusätzlicher Schritt hinzugefügt werden, welcher eine im Skript enthaltene JavaScript-Funktion aufruft, mitsamt Ereignisparameter, also Informationen zum eingetretenen Ereignis.
Vermeide hier jegliche wiederholende Ablaufstruktur (Schleife), die auf etwas wartet oder viel Zeit in Anspruch nimmt! Eine solche Schleife bringt den "Firmware-Motor" zumeist zum stottern und lässt zumindest das Skript mit einem Fehler beenden, wenn nichts Schlimmeres geschieht. Ein Skript ist hier ausschließlich dazu geeignet, auf Ereignisse zu reagieren.
Hier könnte ein Vergleich hoffentlich verständnisfördernd sein.
Stelle dir vor, ein Paketzusteller versucht, ein Paket jemandem auszuhändigen, möglichst dem Adressaten. Gelingt dies nicht, nimmt er das Paket wieder mit, die weiteren Schritte seien hier nicht betrachtet.
Der Adressat erhält über den Zustellversuch keine Information und kann somit nicht aktiv werden.
Wenn der Adressat dem Zusteller - oder einem dafür Zuständigen - mitteilt, dass er bei einem Zustellversuch per E-Mail benachrichtigt werden will, dann muss dessen E-Mail Adresse registriert werden. Auf Grund einer solchen Registrierung wird der Zusteller zusätzlich zum Paketzustellversuch eine Nachricht per E-Mail an den Adressaten senden lassen. Darin ist sinnvollerweise eine Information (Parameter) enthalten, welche aussagt, ob die Zustellung erfolgreich war und evtl. wo das Paket abgeholt werden kann.
Der Vorteil einer solchermaßen erweiterten Abarbeitung eines Zustellversuchs liegt darin, dass der Adressat Kenntnis erhält und bei Bedarf aktiv werden kann. Es mag ein Mitbewohner oder Nachbar das Paket angenommen haben. Oder das Paket steht zur Abholung an einem Ort bereit. Oder ...
Entscheidend in diesem Vergleich ist, dass der Adressat dem Logistikunternehmen seine E-Mail Adresse mitteilen muss, damit er die gewünschte Nachricht erhalten kann. Der Zusteller führt dann neben der Zustellung einen zusätzlichen Schritt (E-Mail Nachricht senden) aus.
In einem Skript ist die E-Mail Adresse des Adressaten eine Funktion, die auf Grund eines eingetretenen Ereignisses neben der üblichen Verarbeitung zusätzlich aufgerufen wird. Das Logistikunternehmen ist die Shelly-Firmware und der Zusteller ist der Firmwareteil, welcher auf Grund des eingetretenen Ereignisses abgearbeitet wird. Letzterer kann nur dann zusätzlich die Funktion aufrufen, wenn diese der Firmware mitgeteilt wird. Die Mitteilung führt zur Registrierung der Funktion in der Firmware. Die in der Firmware registrierte Funktion ist ein (Skript interner) Eventhandler, also der Skript interne Verarbeiter von Ereignissen. Diese Registrierung kann auch gelöscht werden. Sie ist in jedem Fall nicht persistent und muss mit jedem Reboot neu erfolgen.
Wie sich im Beispiel der Adressat verhält, muss innerhalb des Skript in der Eventhandler-Funktion stehen. Dies ist der zunächst entscheidende erste Schritt in der Nutzung eines Shelly-Skript. Im einfachsten Fall und zunächst nützlich ist die Ausgabe der Nachricht auf einer Konsole. Diese Nachricht wird dem Eventhandler per Parameter übergeben.
Die folgende schlichte Eventhandler-Funktion, kurz Eventhandler, gibt die eingetroffene Nachricht, den Parameter event, auf der Konsole aus. Somit kann diese Nachricht analysiert und Teile davon im zu implementierenden Eventhandler verwendet werden.
function myEventHandler(event) { // event ist die strukturierte Nachricht
let msg = JSON.stringify(event);
print(msg);
}
Der Parameter event beinhaltet eine Datenstruktur im sog. JSON-Format. Eine solche Struktur kann die print() Funktion nicht nativ ausgeben, weshalb sie vor der Ausgabe in eine Zeichenkette (String) umzuwandeln ist. Dies erfolgt per Aufruf von JSON.stringify(event). Danach liegt die Nachricht in der Variablen msg als String vor und kann von print() ausgegeben werden.
Obiger Code lässt sich auch kürzer fassen:
function myEventHandler(event) { // event ist die strukturierte Nachricht
print(JSON.stringify(event));
}
JSON.stringify(event) liefert den String zur Datenstruktur in event, welcher print() zwecks Ausgabe übergeben wird. Hierfür ist keine zusätzliche Variable erforderlich.
Wenn du diesen Eventhandler in einem Skript nutzen möchtest, muss noch dessen Registrierung erfolgen, ähnlich der E-Mail Adresse im obigen beispielhaften Vergleich. Hierfür stellt Allterco eine spezielle Funktion zur Verfügung - s.a. hier. Hier nun die einfachste Form einer solchen Registrierung:
Shelly.addEventHandler(myEventHandler);
Zum erstellen eines ersten bereits funktionstüchtigen Skript tue folgendes!
Notiere oder kopiere einfach den kompletten, obigen Eventhandler in ein selbst erstelltes, noch leeres Skript und füge darunter die Registrierung des Eventhandlers per Shelly.addEventHandler() ein! Dann speichere das Skript, starte es und warte auf ein Ereignis!
Das Ereignis kannst du irgendwie selbst auslösen - bevor du am Computer einschläfst 😉, indem du im Web-UI (Website) des Shelly einen Schaltknopf anklickst. Danach sollte im Konsolenfenster unter den Skriptfenster der Inhalt der Ereignis bezogenen Nachricht erscheinen. Viel Spaß bei der Analyse dieser Nachricht. 😊
Das gesamte erste, nutzbare Skript tut zwar noch nichts außer quatschen, aber es funktioniert bereits und dessen Gequatsche ist durchaus informativ.
Wem obiger Vergleich mit Logistikunternehmen und Zusteller etwas zu schwer verständlich erscheint, dem möchte ich einen sehr kurzen anderen Vergleich anbieten.
Du lebst in einer Wohngemeinschaft und bist auf dem Balkon beschäftigt. Einem eintreffenden Mitbewohner rufst du zu, er - oder sie - möge bitte Kaffee kochen. Und du teilst mit, dass du auf dem Balkon zu erreichen bist. Der Eingetroffene antwortet mit "Ok". In dieser kurzen Kommunikation ist zwischen den Aussagen unausgesprochen enthalten, dass du benachrichtigt werden willst, wenn der Kaffee fertig ist. Der Gesprächspartner meldet mit "Ok", dass er den Auftrag annimmt.
Das Ereignis ist der Abschluss des Kaffee Kochens. Der Aufruf des Eventhandlers ist der Zuruf in Richtung Balkon "Kaffee ist fertig". Du bist der Eventhandler und reagierst auf das Ereignis, d.h. du holst dir eine Tasse gekochten Kaffees. Falls du dazu neigst, den Kaffee in den Abfluss zu gießen, ist das eben deine spezifische Art des Eventhandlings. 😄
Bemerkung: Ich weiß selbstverständlich, dass mitunter zusätzliche Abbildungen einen Sachverhalt besser verdeutlichen als reiner Text. Vielleicht werde ich dies bei hinreichend Zeitreserve und Muße nachholen. Zunächst warte ich aber ab, welche Fragen oder Rückmeldungen ich erhalte. 😉