Seite 1 von 1

Timer verlängern

Verfasst: 10. Nov 2022 20:48
von galaxisspatz
Moin,
ich lasse über einen Bewegungsmelder einen Schalter einschalten, nach ablauf eines Timers soll der Schalter aus gehen. Wenn innerhalb des Timer der Bewegungsmelder wieder ausslöst soll der Timer verlängert werden.
Der Bewegungsmelder gibt ON bei Bewegung und schaltet nach 60s auf OFF.
Leider funktioniert die Verlängerung nicht, der Timer startet immer neu.

Vieleicht findet jemand von euch den Fehler.

Danke und Gruß
Olaf

Code: Alles auswählen

var Timer tTest = null

//Test rule
     rule "testen"

    when
        Item BewegungHelloweenPresence changed to ON       //Bewegungsmelder löst aus
    then
        if(tTest !== null){                                     //prüft ob Timer läuft
            logInfo("test", "Bewegung Timer verlängert")
            tTest.reschedule(now.plusSeconds(120))              //Timer läuft und wird umgeplant
        }
        else {                                                  //Timer läuft nicht
            logInfo("test", "Bewegung Timer läuft")
            Testschalter.sendCommand(ON)                        //Schalter ein
            tTest = createTimer(now.plusSeconds(180), [|        //Timer starten
            Testschalter.sendCommand(OFF)                      //Timer abgelaufen, Schalter aus
            logInfo("test", "Bewegung Timer abgelaufen")
            ])
            tTest = null                                        //Timer Variable auf "null"
        }
    end 

Re: Timer verlängern

Verfasst: 11. Nov 2022 02:12
von udo1toni
Der Fehler ist einfach: Du definierst einen Timer und nutzt eine Variable, um den Zeiger auf den Timer zu speichern. Unmittelbar danach löschst Du die Variable wieder.

Das ist ein sehr gern genommenes Missverständnis im Zusammenhang mit createTimer. Der Code im Lambda (das ist der Teil zwischen [ und ]) wird dem Scheduler übergeben und es geht unmittelbar weiter nach dem createTimer(), da gibt es keine Millisekunde Abstand.
Deshalb muss der Code so aussehen:

Code: Alles auswählen

var Timer tTest = null

//Test rule
rule "testen"
 when
    Item BewegungHelloweenPresence changed to ON         // Bewegungsmelder löst aus
 then
    if(tTest !== null){                                  // prüft ob Timer läuft
        logInfo("test", "Bewegung Timer verlängert")
        tTest.reschedule(now.plusSeconds(120))           // Timer läuft und wird umgeplant
    } else {                                             // Timer läuft nicht
        logInfo("test", "Bewegung Timer läuft")
        Testschalter.sendCommand(ON)                     // Schalter ein
        tTest = createTimer(now.plusSeconds(180), [|     // Timer starten
            Testschalter.sendCommand(OFF)                // Timer abgelaufen, Schalter aus
            logInfo("test", "Bewegung Timer abgelaufen")
            tTest = null                                 // Timer Variable auf "null"
        ])
    }
 end 
Der kleine, aber feine Unterschied: Die Timer Variable wird innerhalb des Timers auf null gesetzt, nicht außerhalb. Das ist auch völlig logisch, denn solange der Timer läuft, darf der Zeiger keinesfalls gelöscht werden, sonst kann man ja gar nicht mehr auf den Timer zugreifen. Als Folge werden lauter neue Timer angelegt, jeder einzelne davon läuft nach drei Minuten ab und schaltet das Licht aus.

Ansonsten hilft die "korrekte" Einrückung, den Code besser zu verstehen. Alle Befehle auf einer Ebene laufen als Block ab.
Die Einrückung ist dabei aber nicht die Ursache für die Blockbildung, sondern dient lediglich der optischen Struktur.

Eine andere Variante der Rule (ohne logging):

Code: Alles auswählen

var Timer tTest = null

//Test rule
rule "testen"
 when
    Item BewegungHelloweenPresence changed to ON   // Bewegungsmelder löst aus
 then
    tTest?.cancel                                  // Timer abbrechen, falls existent
    var Integer iTime =  120                       // Zeit für Verlängerung
    if(Testschalter.state != ON) {                 // Falls Licht aus
        Testschalter.sendCommand(ON)               // Schalter ein
        iTime =  180                               // Startlänge
    }
    tTest = createTimer(now.plusSeconds(iTime), [| // Timer starten
        Testschalter.sendCommand(OFF)              // Timer abgelaufen, Schalter aus
    ])
 end 
Der Timer wird in diesem Fall nicht verlängert, sondern erneut angelegt. Wenn man auf die unterschiedliche Länge verzichtet, kann man natürlich auf die zweite Variable iTime verzichten und damit drei Zeilen einsparen (da nur ein Befehl durch das if gesteuert werden muss, kann man auf die geschweiften Klammern verzichten).

Re: Timer verlängern

Verfasst: 11. Nov 2022 21:45
von galaxisspatz
Hallo Udo,
wie immer perfekt, vielen Danke für deine Hilfe und die Erklärungen.

Gruß
Olaf

Re: Timer verlängern

Verfasst: 12. Nov 2022 14:47
von udo1toni
Immer gerne :)