Rule Countdown mit Möglichkeit zum Killen

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
bananajoe86
Beiträge: 5
Registriert: 5. Sep 2020 10:43
Answers: 0

Rule Countdown mit Möglichkeit zum Killen

Beitrag von bananajoe86 »

Hallo Gemeinde,
Ich könnte mal eure Unterstützung gebrauchen. Ich habe mir einen schönen Slider gebaut, um zu visualisieren, wie lange der Timer noch zu laufen hat. Soweit so gut, allerdings schaffe ich es nicht, den Countdown zu killen, damit er wieder neu startet. Mit der aktuellen Rule setz er den Count zwar kurzzeitig wieder auf 60, zählt aber von der letzten Stelle weiter runter. Ich möchte aber, wenn der Sprengler1 erneut ON schaltet, die Zeit wieder hochgesetzt wird.

rule "Bewässerung Vorgarten"
when

Item Sprengler1 changed to ON


then

val Integer TIMER_TIME = (Sprengler3.state as DecimalType).intValue


var count = TIMER_TIME
while(count >= 0) {
Sprengler3.postUpdate(count)
count = count - 1
Thread::sleep(1000)
}
end

Pepe1907
Beiträge: 167
Registriert: 1. Jun 2020 17:29
Answers: 2

Re: Rule Countdown mit Möglichkeit zum Killen

Beitrag von Pepe1907 »

bananajoe86 hat geschrieben:Hallo Gemeinde,
Ich könnte mal eure Unterstützung gebrauchen. Ich habe mir einen schönen Slider gebaut, um zu visualisieren, wie lange der Timer noch zu laufen hat. Soweit so gut, allerdings schaffe ich es nicht, den Countdown zu killen, damit er wieder neu startet. Mit der aktuellen Rule setz er den Count zwar kurzzeitig wieder auf 60, zählt aber von der letzten Stelle weiter runter. Ich möchte aber, wenn der Sprengler1 erneut ON schaltet, die Zeit wieder hochgesetzt wird.

rule "Bewässerung Vorgarten"
when

Item Sprengler1 changed to ON


then

val Integer TIMER_TIME = (Sprengler3.state as DecimalType).intValue


var count = TIMER_TIME
while(count >= 0) {
Sprengler3.postUpdate(count)
count = count - 1
Thread::sleep(1000)
}
end
Ich würde mit createTimer und den Timer dann ggf. Canceln wenn es gewünscht ist. Evtl. Braucht man dazu noch eine Variable dazu wird dir udo oder jemand anderes sicherlich weiterhelfen können. Da bei sleep die Regel nur pausiert hat man darüber meines Wissens keine Chance.

Gesendet von meinem SM-G981B mit Tapatalk


Benutzeravatar
udo1toni
Beiträge: 15248
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: Rule Countdown mit Möglichkeit zum Killen

Beitrag von udo1toni »

bananajoe86 hat geschrieben: 29. Sep 2020 20:04 Ich könnte mal eure Unterstützung gebrauchen. Ich habe mir einen schönen Slider gebaut, um zu visualisieren, wie lange der Timer noch zu laufen hat. [...]
Also, die Idee ist gaaanz schlecht. ;)

openHAB arbeitet ereignisorientiert. Eine Rule sollte im schlimmsten Fall unter eine Sekunde laufen, im besten Fall innerhalb weniger Millisekunden.
Ein Thread::sleep() hält den Thread einfach für die gewählte Zeit an, er steht nicht zur Verarbeitung anderer Rules zur Verfügung.
Besser:

Code: Alles auswählen

var Timer tWater = null                             // globale Variablen vor der ersten Rule einfügen
var Integer iWater = 61

rule "Bewässerung Vorgarten"
when
    Item Sprengler1 changed to ON
then
    tWater?.cancel                                  // falls noch ein Timer läuft, abbrechen
    iWater = 61                                     // Zähler zurücksetzen
    tWater = createTimer(now, [|                    // Timer anlegen und sofort ausführen
        iWater = iWater - 1                         // Zähler runterzählen
        Sprengler3.postUpdate(iWater)               // Zähleritem aktualisieren
        if(iWater > 0)                              // Falls Zähler größer 0
            tWater.reschedule(now.plusSeconds(1))   // Timer in einer Sekunde erneut ausführen
    ])
end
Die Rule legt den Timer an. Danach ist die Rule beendet und damit ist der Thread wieder frei. Dafür läuft nun einmal pro Sekunde ein Thread des Schedulers. Dieser Thread läuft allerdings nur wenige Millisekunden, da der Job ja auch schnell erledigt ist.
Die beiden Variablen werden für den Timer und den Zähler gebraucht. Da die Rule nicht dauerhaft läuft, müssen beide Variaben global definiert werden. Man könnte auch das Item als "Zählerquelle" nutzen, allerdings braucht das wesentlich mehr Prozessorzyklen :)

Ob das allerdings so funktioniert, wie Du Dir das vorstellst? Die UI ist nicht unbedingt dazu gedacht, im Sekundentakt upzudaten.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

bananajoe86
Beiträge: 5
Registriert: 5. Sep 2020 10:43
Answers: 0

Re: Rule Countdown mit Möglichkeit zum Killen

Beitrag von bananajoe86 »

Mega, das funkt wie ich es mir vorgestellt habe. Besten Dank für die Unterstützung.

Studzi
Beiträge: 1
Registriert: 9. Dez 2022 11:13
Answers: 0

Re: Rule Countdown mit Möglichkeit zum Killen

Beitrag von Studzi »

Hallo,

ich bin leider etwas unwissend. Gibt es bei der Rule ein Möglichkeit den Countdown von einem Number:Item loslaufen zu lassen?

Also nicht bei einer fixen Zahl.

Danke

Benutzeravatar
udo1toni
Beiträge: 15248
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: Rule Countdown mit Möglichkeit zum Killen

Beitrag von udo1toni »

Ja, das geht. Aber weil ich immer auf Krümel achte: Es gibt kein Number:Item :) Es gibt Number Items. Wenn Du den Doppelpunkt anhängst, handelt es sich um ein UoM Item und hinter dem Doppelpunkt steht dann die Messgröße, also z.B. Number:Temperature. Solche Items übergeben nicht nur den Zahlenwert, sondern zusätzlich auch noch die Einheit, in der sie angegeben ist, also z.B. °F oder K. Und der Witz an der Sache: Du kannst für die Ausgabe eine beliebige passende Einheit erzwingen, also der Channel übergibt z.B. 20 °C und Du erzwingst °F, dann gibt das Item 68 °F aus, oder wenn Du K erzwingst, 293,15 K, und das komplett ohne sich mit irgendwelchen Formeln zu beschäftigen, also eigentlich eine sehr coole Funktion. Leider muss man dann in Rules sehr genau aufpassen, wie man diese Werte weiterverarbeitet :) aber irgendwas ist ja immer...

Zurück zu Deiner Anforderung: Als Beispiel mag der Code von oben gelten, in leicht abgeänderter Form:

Code: Alles auswählen

var Timer tCountdown = null                                                // globale Variablen vor der ersten Rule einfügen

rule "Count down"
when
    Item Countdown received command                                        // Item hat Befehl empfangen
then
    if(!(receivedCommand instanceof Number)) {                             // war Befehl eine Zahl?
        logWarn("countdown","Command ist ungültig! ({})",receivedCommand)  // Falls nein, Fehlermeldung
        return;                                                            // und Abbruch
    }
    if(!(receivedCommand as Number).intValue > 0) {                        // war Zahl größer 0?
        logWarn("countdown","Command ist kleiner 1, Abbruch.!")            // Falls nein, Fehlermeldung
        return;                                                            // und Abbruch
    }
    tCountdown?.cancel                                                     // falls noch ein Timer läuft, abbrechen
    tCountdown = createTimer(now.plusSeconds(1), [|                        // Timer anlegen und nach einer Sekunde ausführen
        val iCd = (Countdown..state as Number) - 1                         // Wert auslesen und herunterzählen
        Countdown.postUpdate(iCd)                                          // Zähleritem aktualisieren
        if(iCd > 0)                                                        // Falls Zähler größer 0
            tCountdown.reschedule(now.plusSeconds(1))                      // Timer in einer Sekunde erneut ausführen
    ])
end
Das Item Countdown wird als Item zum Runterzählen verwendet. Sobald es einen Befehl empfängt, wird dieser auf Gültigkeit geprüft und gegebenenfalls die Rule abgebrochen. Ist es eine gültige Zahl über 0, wird der Timer gestartet und die Rule ist beendet.

Nach einer Sekunde läuft der Timer ab und der Scheduler startet den hinterlegten Code. Dieser liest den aktuellen Wert aus dem Item und zieht gleich 1 ab.
Anschließend wird der neue Wert ins Item geschrieben. Ist der neue Wert größer 0, wird der Timer erneut geplant.

Limitierung in dieser Form: Wenn Du über die UI den Zahlenwert eingibst, geschieht dies in den meisten Fällen über plus/minus. Jeder einzelne Tastendruck führt nun zu einem Befehl. Das bedeutet, um Werte über 1 einstellen zu können, musst Du mehrmals pro Sekunde den Wert erhöhen, sonst fängt der Timer umgehend an zu arbeiten und zieht die von Dir erhöhten Werte gleich wieder ab :)

Sinnnvoller wäre es also, entweder über Selection vorgegebene Werte in das Item zu laden (also meinetwegen einen Knopf mit dem hinterlegten Wert 120, ein weiterer mit 300 und noch einer mit 600, dann kannst Du auf Knopfdruck den Timer auf 2, 5 oder 10 Minuten setzen und der Countdown startet.
Oder man erstellt ein Start Item, welches den Countdown startet und nutzt das Number Item nur zum Einstellen und Anzeigen des Countdowns, nicht aber zum Start des Countdowns.

Wichtig ist in dem Zusammenhang, den Unterschied zwischen Command und Update zu verstehen. Command sendet einen Befehl (deshalb sendCommand), Update ändert lediglich den Status des Items (das geschieht meist automatisch nach einem Befehl, deshalb postUpdate - nur so als Eselsbrücke) Eingaben in der UI (also über Pages oder die Sitemap) lösen gewöhnlich immer einen Befehl aus, den das betreffende Item empfängt.
In den Rules gibt es Trigger für beide Ereignisse, changed für den Status, received command für einen durch das Item empfangenen Befehl.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten