Seite 1 von 1
Timer korrekt einbauen
Verfasst: 18. Feb 2022 10:19
von SaschaQ
Hallo zusammen,
ich habe mal eine generelle Frage. Teilweise muss man in Rules mit Verzögerungen arbeiten.
Zu Beginn war für mich immer Thread sleep die erste Wahl, aber grundsätzlich sollte man ja eher die Timer verwenden.
Ich habe bei mir ein paar Timer eingebaut und vermute, dass ich die Syntax falsch verstanden habe.
Kann mir einer die Timer Syntax erklären wenn ich eine Rule verzögern will:
Zum Beispiel hier: Hier möchte ich wenn in die unten genannte IF Verzweigung gesprungen wird zwei mal die Rule um 3 Sekunden pausieren bzw. verzögern.
Passt das so oder habe ich da einen Denkfehler? Für mich würde das jetzt bedeuten, er lässt Alexa "Willkommen zuhause" sagen, macht 3 Sekunde Pause und setzt dann die Lautstärke auf 25 zurück.
Wenn ich das falsch verstanden habe, bin ich dankbar für eine Erklärung.
Danke
Code: Alles auswählen
if (all_schlafen.state==OFF && all_e_schlafen.state==OFF && ben_durchsagen_sperren.state==OFF){
createTimer(now.plusSeconds(3), [ |
echo_wohnzimmer_TTS.sendCommand('Willkommen zuhause')
])
createTimer(now.plusSeconds(3), [ |
echo_wohnzimmer_TTS_Volume.sendCommand(25)
])
}
Re: Timer korrekt einbauen
Verfasst: 18. Feb 2022 11:43
von int5749
Dies sollte prinzipiell so funktionieren, wenn Du nur ausschließlich eine Verzögerung erreichen möchtest.
Wenn Du den Timer manipulieren (reschedule) oder vorzeitig beenden (cancel) möchtest, benötigst Du einen Pointer zum Timer und dieser muß natürlich, wie jeder Pointer, eineindeutig sein.
Besser als ich es erklären könnte, steht es in der Doku von openHAB

=>
Timer
Re: Timer korrekt einbauen
Verfasst: 18. Feb 2022 15:21
von SaschaQ
Ich habe ja in meinem Beispiel 2 Timer drin. Eigentlich brauche ich ja nur 1 Pause von 3 Sekunden.
Wird die Rule an der Stelle angehalten? Oder wird der Rest der nicht innerhalb der Klammer ist noch ausgeführt?
Re: Timer korrekt einbauen
Verfasst: 18. Feb 2022 15:41
von udo1toni
Ja, Du machst da einen Denkfehler

Aber Du befindest Dich in guter Gesellschaft.
Es ist wichtig, zu verstehen, wie das mit den Timern funktioniert.
createTimer(a,b) ist eine Funktion. Diese Funktion tut exakt eine Sache: Sie legt einen Timer an. Dauer für diese Aktion: etwa 0.001 Sekunden (+/-)
Dein Code legt also zwei Timer an, innerhalb etwa zwei Millisekunden, die beide drei Sekunden später fast exakt zeitgleich (Abstand vielleicht eine Millisekunde) auslösen.
Die Ausführung der gesamten Rule dauert etwa zwei Millisekunden, das ist der Witz an Timern.
Es gibt verschiedene Möglichkeiten:
Code: Alles auswählen
createTimer(now.plusSeconds(3), [ |
echo_wohnzimmer_TTS.sendCommand('Willkommen zuhause')
])
createTimer(now.plusSeconds(6), [ |
echo_wohnzimmer_TTS_Volume.sendCommand(25)
])
Der Code legt also zwei Timer an, der erste wird nach drei Sekunden ausgeführt, der zweite nach sechs Sekunden (also drei Sekunden nach dem ersten Timer).
Etwas komplexer und hier nur zweite Wahl (weil es nur um zwei Timer geht):
Code: Alles auswählen
// Globale Variablen ganz am Anfang der Rule-Datei anlegen
var Timer tMyTimer = null // Objekt für den Timer
var Integer iMyTimer = 0 // Zähler für den Timer
...
tMyTimer?.cancel // Timer löschen, falls gerade einer läuft
if(tMyTimer === null) // alternativ prüfen, ob der Timer nicht existiert
iMyTimer = 0 // globale Variable auf einen definierten Anfangswert setzen
tMyTimer = createTimer(now.plusMillis(10), [| // Timer anlegen und dem Objekt zuordnen
iMyTimer += 1 // Zähler erhöhen
switch(iMyTimer) { // welcher Schritt ist gerade aktiv
case 2: { // zweiter Durchlauf
echo_wohnzimmer_TTS.sendCommand('Willkommen zuhause')
}
case 3: { // dritter Durchlauf
echo_wohnzimmer_TTS_Volume.sendCommand(25)
}
}
if(iMyTimer < 3) { // falls noch nicht dreimal gelaufen
tMyTimer.reschedule(now.plusSeconds(3)) // Timer erneut ausführen
} else { // ansonsten
tMyTimer = null // Objekt leeren
}
])
Der Witz an diesem Code ist, dass es nur einen Timer braucht, egal wie viele Schritte in einer Abfolge benötigt werden. Benötigt man unterschiedliche zeitliche Abstände, kann der Reschedule auch individuell pro Schritt gesetzt werden.
Man sollte allerdings darauf achten, dass es immer einen sicheren Ausstieg aus dem Timer gibt (hier der if-Teil).
Re: Timer korrekt einbauen
Verfasst: 19. Feb 2022 11:11
von SaschaQ
Okay, danke für deine Erklärung.
Ich dachte immer die Rule pausiert an der Stellen.
Wenn die Rule nun an der Stelle:
createTimer(now.plusSeconds(3), [ |
echo_wohnzimmer_TTS.sendCommand('Willkommen zuhause')
])
ankommt.
Wird 3 Sekunden pausiert und dann der Code in der Klamme ausgeführt korrekt?
Was passiert mit dem Code, der nicht in dieser Klammer ist aber nach dem Timer kommt, läuft der dann weiter ?
Re: Timer korrekt einbauen
Verfasst: 19. Feb 2022 15:08
von udo1toni
Nein, da gibt es kein Pausieren. createTimer ist etwas komplett anderes als Thread::sleep(), sozusagen sogar das Gegeteil.
Wie oben erklärt, bewirkt createTimer() exakt eine Sache, nämlich, im Scheduler einen Eintrag anzulegen.
Der Eintrag besteht aus einem Zeitstempel und dem auszuführenden Code (vermutlich in Form eines Zeigers auf einen Speicherbereich, in den der Code vorher geschrieben wurde).
Nochmal: Keine Pause.
Der Scheduler ist ein Thread, der im Hintergrund ausgeführt wird. Er kümmert sich darum, Code zu bestimmten Zeiten auszuführen. Mehr gibt es dazu eigentlich nicht zu sagen.
Ach so, doch... Weil es offensichtlich oben nicht deutlich genug wurde. Der ausgeführte Code hat überhaupt nichts mit der Rule zu tun.
Die Rule führt exakt die Befehle createTimer() aus, sonst nichts.
Re: Timer korrekt einbauen
Verfasst: 20. Feb 2022 10:55
von SaschaQ
Hallo Udo1toni.
Danke nochmals.
Vielleicht habe ich meine Frage nicht klar genug ausgedrückt.
Wenn ich eine Rule habe und es kommt an einer bestimmten Stelle der Timer mit seinem Code. Dann wird alles was nach dem Timer kommt weiter ausgeführt und durchläuft die Rule bis zum Ende?
Re: Timer korrekt einbauen
Verfasst: 20. Feb 2022 15:00
von int5749
Ja,
„Nur“ der code in dem Timer wird ausgeführt, sobald die Zeit des Scheduler Eintrags erreicht ist.
Übertragen gesehen ist ein Timer wie ein Wecker und der Code wird dann abgearbeitet.
Wenn Du einen Timer in einer Rule erstellst, machst Du nichts anderes als den Wecker für den enthaltenen Code stellen
Re: Timer korrekt einbauen
Verfasst: 20. Feb 2022 15:38
von udo1toni
SaschaQ hat geschrieben: ↑20. Feb 2022 10:55
Hallo Udo1toni.
Danke nochmals.
Vielleicht habe ich meine Frage nicht klar genug ausgedrückt.
Wenn ich eine Rule habe und es kommt an einer bestimmten Stelle der Timer mit seinem Code. Dann wird alles was nach dem Timer kommt weiter ausgeführt und durchläuft die Rule bis zum Ende?
Ja, aber Nein. Selbst auf die Gefahr, hier Verwirrung zu stiften...
Der Punkt, auf dem ich bestehen muss: Es gibt
innerhalb der Rule
keinen Timer! Es gibt lediglich einen Befehl, der einen Eintrag im Scheduler erzeugt (umgangssprachtlich wird also ein Timer erzeugt).
Es ist wirklich wichtig, das zu verstehen! Wenn Du mal dahinter gekommen bist, dass der Timercode innerhalb der Rule
überhaupt nichts mit der Rule selbst zu tun hat, sondern
vollkommen unabhängig von dieser existiert, wird es klar. Ich könnte das Ganze auch so schreiben:
Code: Alles auswählen
val a = now.plusSeconds(3)
val c = a.plusSeconds(3)
val b = [mein Code für den ersten Timer]
val d = [mein Code für den zweiten Timer]
createTimer(a,b)
createTimer(c,d)
Im Fall von b und d klappt das natürlich nicht wirklich, weil das Lamba anders definiert wird, aber es handelt sich wirklich nur um ein Funktion, der zwei Parameter übergeben werden. Die Funktion legt nur einen Eintrag im Scheduler an, sie führt nichts aus, sie wartet nicht, sie benötigt keine Zeit (jedenfalls keine wesentliche Zeit), sie wird aufgerufen und liefert fast unmittelbar einen Rückgabewert, den man auch verwerfen kann, that's it.