NEWS
setTimeout innerhalb if-Ausführungsblock
-
Hallo Leute,
ich bin immer noch damit zugange meine Müll-Signallampe irgendwie zum Blinken zu bekommen, wenn mehrere Müllsorten (Leichtverpackungen, Bioabfall, Restmüll etc.) an die Straße zu stellen sind. @MCU hatte mir ja freundlicherweise schon ein Blockly zusammengestellt, nichts desto trotz würde ich das gerne auch in JavaScript versuchen irgendwie zustande zu bekommen.Dabei festgestellt hatte ich, dass wenn ich das mit einem "Do Loop until" versuche, dass die JavaScript-Instanz abgeschaltet wird. Ok, dann habe ich mir, wie ich es auch schon zuvor mal überlegt hatte, eine For-Next-Schleife zu bestimmten Zeiten durchlaufen zu lassen. Innerhalb der For-Next-Schleife soll dann per If-Abfrage geprüft werden ob z.B. gelber Sack für morgen im Kalender steht und wenn ja, dann soll 10 Sekunden die Lampe gelb leuchten. Dann wird die nächste Müll-Sorte abgefragt.
Hier mal mein bisheriger Code:
// Markus Patten - 11-April-2021 // Das folgende Skript wurde erstellt um, in Abhängigkeit von Kalenderereig- // nissen für die Müllentsorgung des Folgetages eine RGB-Farblampe, welche // über einen BroadLink-Adapter mit ioBroker gekoppelt ist, anzusteuern und // so die bevorstehende Müllsortenabholung zu signalisieren. // // Hierbei werden folgende Farbfestlegungen und Müllsortenbezeichnungen ver- // wendet: // // Leichtverpackungen = gelbes Licht // Papiertonne = blaues Licht // Bioabfallbehaelter = grünes Licht // Restmuelltonne = viollettes Licht // Problemmuell = rotes Licht // // Für die Steuerung der Lampe wurden die betreffenden Farbcodes als Szene im // Broadlink-Adapter angelernt und entsprechend der vorstehenden Müllsortenbe- // zeichnung benamt. // // Weiter wurde hierzu über den ical-Adaplter der Entsorgungskalender mit den // betreffenden Abholterminen verknüpft. Im Kalender finden die vorstehenden // Müllsortenbezeichnung ebenso Anwendung. // // In der ical-Instanz werden hierzu entsprechend gleichlautendende Filter ge- // setzt, welche die jeweiligen Abholtermine unter ical.0.events.1.'Müllsorte' // anzeigen, bzw. das bevorstehende Ereignis mit 'true' ankündigen. // // Die Lichtsteuerung erfolgt zu vordefinierten Abfragezeiten, welche bei Be- // darf auf die persönlich, individuellen Zeiten angepasst werden können. // Weiter wird ein Lichtwechsel auf eine bestimmte Anzahl von Abfolgen begrenzt // da ein Loop-Ereignis zur Inaktivsetzung der JS-Instanz führen würde. Auch // diese Anzahl kann im Parameter entsprechend angepasst werden. // Grundeinstellungen const logging = true; // erweitere Logs ausgeben const praefix = "javaskript.0.Muelllicht"; // Grundpfad für Skript DPs var LightsOn = 10000; // Dauer des jeweiligen Farbzeichens const SignHour_1 = 10; // Stunde des ersten Lichtsignals const SignHour_2 = 16; // Stunde des zweiten Lichtsignals const SignHour_3 = 20; // Stunde des dritten Lichtsignals const Durchlauf = 10; // Anzahl der Farbdurchlaeufe var Zeit = new Date(); // Zeitopbejkt für den Startzeitpunkt // Ab hier nichts mehr ändern !!! // Einlesen der Kalenderdaten für den Folgetage je Muellsorte log("Starte Muelllicht " + Zeit); // Logeintrag Start let Leichtverpackungen = getState('ical.0.events.1.Leichtverpackungen').val; let Papiertonne = getState('ical.0.events.1.Papiertonne').val; let Bioabfallbehaelter = getState('ical.0.events.1.Bioabfallbehaelter').val; let Restmuelltonne = getState('ical.0.events.1.Restmuelltonne').val; let Problemmuell = getState('ical.0.events.1.Problemmuell').val; log("Leichtverpackungen: " + Leichtverpackungen + " Papiertonne: " + Papiertonne + " Biotonne: " + Bioabfallbehaelter + " Restmüll: " + Restmuelltonne + " Problemmuell: " + Problemmuell); // Alle Lichtsignal-Szenen zurücksetzen setState("broadlink2.0.Scenes.Leichtverpackungen", false); setState("broadlink2.0.Scenes.Papiertonne", false); setState("broadlink2.0.Scenes.Bioabfallbehaelter", false); setState("broadlink2.0.Scenes.Restmuelltonne", false); setState("broadlink2.0.Scenes.Problemmuell", false); log("Lichtsignalszenen zurückgesetzt"); // Logeintrag Lichtszenen zurückgesetzt var ZeitHour = Zeit.getHours(); // Auslesen der aktuellen Stunde // Abfrage ob gesetzte Stunde erreicht ist log("Erinnerungszeit: " + ZeitHour); // Logeintrag Erinnerungszeit if((ZeitHour == SignHour_1) || (ZeitHour == SignHour_2) || (ZeitHour == SignHour_3)) { // Starten der Schleife log("Schleifenstart:"); // Log-Einstrag Schleifenstart for (i = 0; i < Durchlauf; i++) { log("Schleife-Nr.: " + i); // Logeintrag Schleifenzähler // Starten der Lichter // Gelb für Leichtverpackungen if(Leichtverpackungen == true) { setState("broadlink2.0.Scenes.Leichtverpackungen", true); setTimeout(function() {log("Warteschleife")}, 10000); log("Licht gelb"); // Logeintrag gelb setState("broadlink2.0.Scenes.Leichtverpackungen", false); clearTimeout; } // Blau für Papiertonne if(Papiertonne == true) { setState("broadlink2.0.Scenes.Papiertonne", true); setTimeout(function() {log("Warteschleife")}, 10000); log("Licht blau"); // Logeintrag blau setState("broadlink2.0.Scenes.Papiertonne", false); clearTimeout; } // Grün für Bioabfallbehaelter if(Bioabfallbehaelter == true) { setState("broadlink2.0.Scenes.Bioabfallbehaelter", true); setTimeout(function() {log("Warteschleife")}, 10000); log("Licht gruen"); // Logeintrag gruen setState("broadlink2.0.Scenes.Bioabfallbehaelter", false); clearTimeout; } // Violett für Restmuelltonne if(Restmuelltonne == true) { setState("broadlink2.0.Scenes.Restmuelltonne", true); setTimeout(function() {log("Warteschleife")}, 10000); log("Licht violett"); // Logeintrag violett setState("broadlink2.0.Scenes.Restmuelltonne", false); clearTimeout; } // Rot für Problemmuell if(Problemmuell == true) { setState("broadlink2.0.Scenes.Problemmuell", true); setTimeout(function() {log("Warteschleife")}, 10000); log("Licht rot"); // Logeintrag rot setState("broadlink2.0.Scenes.Problemmuell", false); clearTimeout; } } setState("broadlink2.0.Scenes.Lampe aus", true); setTimeout(function() {setState("broadlink2.0.Scenes.Lampe aus", false)},5000); clearTimeout; }
Nun aber mein Problem:
Die programmierte setTimeout wird nicht innerhalb des If-Anweisungsblockes in der For-Next-Schleife ausgeführt - laut Protokoll kommen die "Warteschleifen alle hinterher. Hier mal ein paar Screens aus der log-Datei:
Zwischen diesen beiden Auszügen stehen noch gefühlt hunderte Einträge wie folgt, deren Herkunft ich überhaupt nicht nachvollziehen kann:
Die sollten aber erst einmal "nebensächlich sein".
Frage: Warum wird die setTimeout nicht innerhalb des if-Anweisungsblockes ausgeführt? Stattdessen leuchten die betreffenden Farben zwar ein paar mal abwechselnd (z.B. grün und blau) aber dann kommen auch wieder Farben, deren Müllsorte eigentlich nicht dran ist
Die Abfrage nach Müllsorte erfolgt ja auch im Vorfeld und wird in der Log entsprechend richtig angezeigt?!
Gruß
Markus -
Nach nochmaliger und umfassender Überlegung bin ich insoweit zur Lösung gekommen - ich stand mir da wohl ein bisschen auf der Leitung. Aber hier die Lösungen:
-
Die richtige if-Abfrage - wenn ich prüfen will, ob die boolsche Variable den Wert true inne hat, dann benötige ich drei Gleichheitszeichen (===).
-
Das setTimeout - und da hatte ich den Gedankenfehler - unterbricht ja an der Stelle nicht das Einlesen des Programmcodes sondern führt nur die betreffende Passage entsprechend verzögert aus. Das heißt, wenn ich eben mehrere Abfolgen habe, deren zeitliche Abfolge von den vorausgegangenen abhängig sein soll, dann muss sich deren Verzögerungszeit entsprechend aufsummieren. Es ist eben nicht, dass Licht A nach 10 Sekunden ausgeht und Licht B nach weiteren 10 Sekunden ausgeht - ich muss dem setTimeout entsprechend zu Licht A 10 Sekunden geben und eben für Licht B 20 Sekunden usw.
Hier nun der vollständige und soweit "richtige" Code, für die, die es interessiert. Gewiss ist dieser Quellcode nicht nach irgendwelchen DIN-normierten Standards oder "Gepflogenheiten" geschrieben worden (ich bin ein absoluter Anfänger in Sachen JavaSkript). Ich nehme daher gerne konstruktive Kritik für zukünftige Projekte oder ggf. auch einer Zweitauflage dieser "Müll-Lichtorgel" entgegen. Auch bin ich offen für Methoden, welche den Text in sich sicherlich verkürzen können (Arbeiten mit Array etc.). Aber Bitte, wem es nicht gefällt oder die Art und Weise wie ich nun "programmiert" habe nicht gefällt - dem sei so - dann bitte ich darum einfach kommentarlos weiterzugehen... ich weiß, dass dieses NICHT PERFEKT ist - dies war für den Anfang aber auch nicht mein Anspruch.
Abschließend bräuchte ich nur noch eine Idee, wie ich das ganze triggern kann (aktuell habe ich es nur manuell gestartet gehabt). Leider bekommen ich bei ical.0.data.counttomorrow nicht den richtigen Wert angezeigt. Wie zu sehen ist, sind zwar unten zwei Events mit "true" gesetzt, aber unter dieser Position steht immer noch "0" anstelle "2". Wenn man das irgendwie ans Laufen bekommen würde könnte ich diesen Wert wunderbar als Trigger nehmen und die For-Next-Schleife noch ein bisschen anpassen. Habt Ihr dazu eine Idee?
Hier nun aber der Quellcode (die ganzen Log-Zeilen habe ich schon rausgenommen - die waren nur für mich um das ganze besser nachvollziehen zu können):
// Markus Patten - 11-April-2021 // Das folgende Skript wurde erstellt um, in Abhängigkeit von Kalenderereig- // nissen für die Müllentsorgung des Folgetages eine RGB-Farblampe, welche // über einen BroadLink-Adapter mit ioBroker gekoppelt ist, anzusteuern und // so die bevorstehende Müllsortenabholung zu signalisieren. // // Hierbei werden folgende Farbfestlegungen und Müllsortenbezeichnungen ver- // wendet: // // Leichtverpackungen = gelbes Licht // Papiertonne = blaues Licht // Bioabfallbehaelter = grünes Licht // Restmuelltonne = viollettes Licht // Problemmuell = rotes Licht // // Für die Steuerung der Lampe wurden die betreffenden Farbcodes als Szene im // Broadlink-Adapter angelernt und entsprechend der vorstehenden Müllsortenbe- // zeichnung benamt. // // Weiter wurde hierzu über den ical-Adaplter der Entsorgungskalender mit den // betreffenden Abholterminen verknüpft. Im Kalender finden die vorstehenden // Müllsortenbezeichnung ebenso Anwendung. // // In der ical-Instanz werden hierzu entsprechend gleichlautendende Filter ge- // setzt, welche die jeweiligen Abholtermine unter ical.0.events.1.'Müllsorte' // anzeigen, bzw. das bevorstehende Ereignis mit 'true' ankündigen. // // Die Lichtsteuerung erfolgt zu vordefinierten Abfragezeiten, welche bei Be- // darf auf die persönlich, individuellen Zeiten angepasst werden können. // Weiter wird ein Lichtwechsel auf eine bestimmte Anzahl von Abfolgen begrenzt // da ein Loop-Ereignis zur Inaktivsetzung der JS-Instanz führen würde. Auch // diese Anzahl kann im Parameter entsprechend angepasst werden. // Grundeinstellungen const logging = false; // erweitere Logs ausgeben const praefix = "javaskript.0.Muelllicht"; // Grundpfad für Skript DPs var LightsOn = 2000; // Dauer des jeweiligen Farbzeichens var LightsOnNew = 0; // Rechenvariable const SignHour_1 = 12; // Stunde des ersten Lichtsignals const SignHour_2 = 16; // Stunde des zweiten Lichtsignals const SignHour_3 = 20; // Stunde des dritten Lichtsignals const Durchlauf = 10; // Anzahl der Farbdurchlaeufe var Zeit = new Date(); // Zeitopbejkt für den Startzeitpunkt // Ab hier nichts mehr ändern !!! // Einlesen der Kalenderdaten für den Folgetage je Muellsorte let Leichtverpackungen = getState('ical.0.events.1.Leichtverpackungen').val; let Papiertonne = getState('ical.0.events.1.Papiertonne').val; let Bioabfallbehaelter = getState('ical.0.events.1.Bioabfallbehaelter').val; let Restmuelltonne = getState('ical.0.events.1.Restmuelltonne').val; let Problemmuell = getState('ical.0.events.1.Problemmuell').val; // Alle Lichtsignal-Szenen zurücksetzen setState("broadlink2.0.Scenes.Leichtverpackungen", false); setState("broadlink2.0.Scenes.Papiertonne", false); setState("broadlink2.0.Scenes.Bioabfallbehaelter", false); setState("broadlink2.0.Scenes.Restmuelltonne", false); setState("broadlink2.0.Scenes.Problemmuell", false); var ZeitHour = Zeit.getHours(); // Auslesen der aktuellen Stunde // Abfrage ob gesetzte Stunde erreicht ist if((ZeitHour == SignHour_1) || (ZeitHour == SignHour_2) || (ZeitHour == SignHour_3)) { // Starten der Schleife LightsOnNew = LightsOn for (i = 0; i < Durchlauf; i++) { // Starten der Lichter // Gelb für Leichtverpackungen if(Leichtverpackungen === true) { setState("broadlink2.0.Scenes.Leichtverpackungen", true); setTimeout(function() { setState("broadlink2.0.Scenes.Leichtverpackungen", false)}, LightsOnNew); clearTimeout; LightsOnNew += LightsOn; } // Blau für Papiertonne if(Papiertonne === true) { setState("broadlink2.0.Scenes.Papiertonne", true); setTimeout(function() { setState("broadlink2.0.Scenes.Papiertonne", false)}, LightsOnNew); clearTimeout; LightsOnNew += LightsOn; } // Grün für Bioabfallbehaelter if(Bioabfallbehaelter === true) { setState("broadlink2.0.Scenes.Bioabfallbehaelter", true); setTimeout(function() { setState("broadlink2.0.Scenes.Bioabfallbehaelter", false)}, LightsOnNew); clearTimeout; LightsOnNew += LightsOn; } // Violett für Restmuelltonne if(Restmuelltonne === true) { setState("broadlink2.0.Scenes.Restmuelltonne", true); setTimeout(function() { setState("broadlink2.0.Scenes.Restmuelltonne", false)}, LightsOnNew); clearTimeout; LightsOnNew += LightsOn; } // Rot für Problemmuell if(Problemmuell === true) { setState("broadlink2.0.Scenes.Problemmuell", true); setTimeout(function() { setState("broadlink2.0.Scenes.Problemmuell", false)}, LightsOnNew); clearTimeout; LightsOnNew += LightsOn; } } setTimeout(function() {setState("broadlink2.0.Scenes.Lampe aus", false)},LightsOnNew); clearTimeout; LightsOnNew = 0; }
Gruß
Markus -
-
@mathopa1973 sagte: Idee, wie ich das ganze triggern kann
schedule('0 12,16,20 * * *', function() { // Mülllicht });
Zeilen 43, 63 und 66 entfallen damit.
@mathopa1973 sagte in setTimeout innerhalb if-Ausführungsblock:
clearTimeout;
ist so nicht anwendbar: Man muss eine Timer-Variable übergeben.
Die for-Schleife wird innerhalb weniger Millisekunden abgearbeitet. Damit erreichst Du nicht, was Du möchtest.
-
Die folgende Funktion bildet eine Schleife mit Berücksichtigung der Einschaltdauer:
function muelllicht() { if(cnt < 5 * Durchlauf) { let id = ''; if(cnt % 5 == 0 && Leichtverpackungen) id = 'broadlink2.0.Scenes.Leichtverpackungen'; else if(cnt % 5 == 1 && Papiertonne) id = 'broadlink2.0.Scenes.Papiertonne'; else if(cnt % 5 == 2 && Bioabfallbehaelter) id = 'broadlink2.0.Scenes.Bioabfallbehaelter'; else if(cnt % 5 == 3 && Restmuelltonne) id = 'broadlink2.0.Scenes.Restmuelltonne'; else if(cnt % 5 == 4 && Problemmuell) id = 'broadlink2.0.Scenes.Problemmuell'; cnt++; if(id) { setState(id, true); // Licht ein setTimeout(function() { setState(id, false); // Licht aus muelllicht(); }, LightsOn); } else muelllicht(); } }
-
@paul53 Danke vielmals.
Kannst Du mir vielleicht den Quellcode kurz erklären? Verstehe ich das richtig, dass hier die Kalenderabfrage am Anfang Dr if-Anweisung steht? Aber wo erfolgt konkret die Verbindung zum Kalender? Oder ist CNT der Zähler unter iCal.0.data.counttomorrow der bei mir immer 0 zeigt auch wenn 2 oder 3 Events True sind?
Auf jeden Fall ist der Code schon um Welten kürzer als der meinige.
-
@mathopa1973 sagte: Kalenderabfrage am Anfang Dr if-Anweisung steht?
Nein, die Kalenderabfrage muss vor Aufruf der Funktion stattfinden und das Ergebnis steht in den 5 Variablen Leichtverpackungen, ...
Variable cnt muss vor Funktionsaufruf auf 0 initialisiert werden und zählt die Zyklen (0 bis 49), da 5 Farben mal 10 Durchläufe. -
@paul53 sagte in setTimeout innerhalb if-Ausführungsblock:
Nein, die Kalenderabfrage muss vor Aufruf der Funktion stattfinden und das Ergebnis steht in den 5 Variablen Leichtverpackungen, ...
Ist das ein Teil meines Codes, den ich dazu übernehmen kann? Oder gibt das dann sowas wie "id[1] = if(getState(ical.0.event.1.Leichtverpackungen) === true);" ?
Variable cnt muss vor Funktionsaufruf auf 0 initialisiert werden und zählt die Zyklen (0 bis 49), da 5 Farben mal 10 Durchläufe.
Reicht da "var ctn = 0;" ?
Sorry für die vielen Fragen - das sind, wie geschrieben, meine ersten Gehversuche in JavaSkript.
Und der Trigger kommt dann automatisch durch die Schedule-anweisung, die ich dann ganz an den Anfang des Skripte und ich "starte" dann einfach das Skript oder muss das Schedule in ein eigenes Skript, was dann das Skript Muelllicht aufruft?
-
@mathopa1973
So könnte das gesamte Skript aussehen:const Durchlauf = 10; const LightsOn = 2000; var cnt, Leichtverpackungen, Papiertonne, Bioabfallbehaelter, Restmuelltonne, Problemmuell; function muelllicht() { if(cnt < 5 * Durchlauf) { let id = ''; if(cnt % 5 == 0 && Leichtverpackungen) id = 'broadlink2.0.Scenes.Leichtverpackungen'; else if(cnt % 5 == 1 && Papiertonne) id = 'broadlink2.0.Scenes.Papiertonne'; else if(cnt % 5 == 2 && Bioabfallbehaelter) id = 'broadlink2.0.Scenes.Bioabfallbehaelter'; else if(cnt % 5 == 3 && Restmuelltonne) id = 'broadlink2.0.Scenes.Restmuelltonne'; else if(cnt % 5 == 4 && Problemmuell) id = 'broadlink2.0.Scenes.Problemmuell'; cnt++; if(id) { setState(id, true); // Licht ein setTimeout(function() { setState(id, false); // Licht aus muelllicht(); }, LightsOn); } else muelllicht(); } } schedule('0 12,16,20 * * *', function() { Leichtverpackungen = getState('ical.0.events.1.Leichtverpackungen').val; Papiertonne = getState('ical.0.events.1.Papiertonne').val; Bioabfallbehaelter = getState('ical.0.events.1.Bioabfallbehaelter').val; Restmuelltonne = getState('ical.0.events.1.Restmuelltonne').val; Problemmuell = getState('ical.0.events.1.Problemmuell').val; cnt = 0; muelllicht(); });
-
@paul53 genial, vielen Dank für die Hilfe, es funktioniert wie gewollt... und das mit sooo wenig Quellcode. Klasse.
Ich hab nur eine kleine Änderung/Ergänzung virgenommen:
Bisher hatte ich es so, dass die broadlinkszenen die Befehle "Lampe an, 1000," + den Sendebefehl für die Farbe enthielten. Dies habe ich aufgelöst und nun nur noch den betreffenden Farbcode drin und eine eigene Szene für das Einschalten der Lampe mit Farbe weiss gesetzt.Im "Schedule-Anweisungsblock" sende ich dann gleich den Befehl für das Einschalten der Lampe mit, damit dann in der Farbwechsel-Funktion nur noch das Umschalten zwischen den Farben erfolgt. Das Ausschalten will ich bewusst manuell halten - als Erinnerungsstütze weil man vielleicht nicht immer in der Küche steht wenn die Lampe angeht.
EDIT: Da ich ja ich den Schefule-Part das Einschalten der Lampe mit reingekommen habe, würde ja folglich die Lampe zu den Schedule-Zriten angehen - unabhängig davon ob überhaupt ein Entsorgungsrermin ansteht oder nicht.
schedule('0 12,16,20 * * *', function() { Leichtverpackungen = getState('ical.0.events.1.Leichtverpackungen').val; Papiertonne = getState('ical.0.events.1.Papiertonne').val; Bioabfallbehaelter = getState('ical.0.events.1.Bioabfallbehaelter').val; Restmuelltonne = getState('ical.0.events.1.Restmuelltonne').val; Problemmuell = getState('ical.0.events.1.Problemmuell').val; cnt = 0; muelllicht();
Um das zu verhindern habe ich hier noch eine if-Abfeage eingebaut, welche dann zu den Schefule-Zeiten als erstes prüft, ob eine der Events überhaupt ein True hat. Wenn ja, dann wird die Funktion aufgerufen oder eben nicht.
schedule('0 14,17,20 * * *', function() { Leichtverpackungen = getState('ical.0.events.1.Leichtverpackungen').val; Papiertonne = getState('ical.0.events.1.Papiertonne').val; Bioabfallbehaelter = getState('ical.0.events.1.Bioabfallbehaelter').val; Restmuelltonne = getState('ical.0.events.1.Restmuelltonne').val; Problemmuell = getState('ical.0.events.1.Problemmuell').val; cnt = 0; if(Leichtverpackungen === true || Papiertonne === true || Bioabfallbehaelter === true || Restmuelltonne === true || Problemmuell === true) { setState("broadlink2.0.Scenes.Lampe an", true); muelllicht(); }
Nochmals vielen, vielen Dank.
Gruß
Markus