Problem mit einem Timer in einer Rule

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

violine21
Beiträge: 600
Registriert: 20. Sep 2019 05:49
Answers: 7

Re: Problem mit einem Timer in einer Rule

Beitrag von violine21 »

Ich habe noch eine Frage.
Ich möchte die Sperrzeit jetzt weiter erhöhen um noch mehr Ruhe in die Shellies zu bekommen und ihre Kontakte zu schonen.
Da schaut man dann schon gebannt auf die Anzeige und denkt, hat sich die Rule aufgehängt?
Leider gibt es keine einfache Methode, die Restlaufzeit eines Timers auszulesen.
Was hälst Du davon, die Laufzeit an der markierten Stelle im Code einem Item zuzuweisen?

Code: Alles auswählen

if(nVerbrauch > nPower) {
        t_Komfortfunktionen?.cancel
        t_Komfortfunktionen = null
        if(!bSperre)
            FHZ_Sperre.postUpdate(1)
    } else if (nVerbrauch < nPower && bSperre && t_Komfortfunktionen === null) {
        logInfo("Photovoltaik", "Timer Start")
        
>>>>>>>>>>> Restlaufzeit.postUpdate(aktuelle Uhrzeit)        
        
        t_Komfortfunktionen = createTimer(now.plusSeconds(120), [ | 
            FHZ_Sperre.postUpdate(0) 
            t_Komfortfunktionen = null
        ])
    }
In einer anderen Rule bei

Code: Alles auswählen

Item Restlaufzeit changed or
alle 10 Sekunden
die berechnete Restlaufzeit = Timer-Laufzeit - (aktuelle Zeit - Item-Zeit)
der Meldung im 10 Sek-Takt mitzugeben?

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

Re: Problem mit einem Timer in einer Rule

Beitrag von udo1toni »

Ganz ehrlich: davon halte ich nichts. Für den Testbetrieb wäre eine Meldung im Log schon ausreichend, da Du in frontail auch filtern kannst siehst Du dann den Zeitstempel und kannst Dir ausrechnen, wann die Sperre aufgehoben wird. Im Normalbetrieb wirst Du nicht auf die UI schauen wollen, wo ist also (außer dem Spieltrieb) der Benefit? Eine Rule, die alle 10 Sekunden triggert, belastet aber das System spürbar.
Natürlich kannst Du das trotzdem machen, allerdings würde ich dann einen anderen weg gehen. Lege zusätzlich zur Timer Variablen noch eine globale Integer Variable zum Zählen an. Vor dem ersten Timeraufruf setzt Du den Zähler z.B. auf 10 und startest den Timer mit 10 Sekunden Laufzeit. Wen der Timer abläuft, zählst Du den Zähler um eins runter und planst den Timer neu, es sei denn, der Zähler ist bei 0 angekommen, dann löst Du die Sperre. Dazu reicht also eine If-Abfrage innerhalb des Timers, der Befehl zum runterzählen und der Reschedule. Zusätzlich kannst Du die übrige Laufzeit aus Zähler mal Timerlaufzeit ausgeben. Ungefähr so:

Code: Alles auswählen

iCount = 10
myMessage.postUpdate("Noch 100 Sekunden")
tSperre = createTimer(now.plusSeconds(10),[|
    iCount --
    if(iCount > 0) {
        logInfo("sperre","Noch {} Sekunden",iCount*10)
        myMessage.postUpdate("Noch "+(iCount*10).toString+" Sekunden")
        tSperre.reschedule(now.plusSeconds(10))
    } else {
        myMessage.postUpdate("Sperre aufgehoben")
        FHZ_Sperre.postUpdate(0)
        tSperre = null
    }
])
Code ist wie immer ungetestet ;) und in diesem Fall natürlich nur der Teil mit dem Timer. global muss noch die Variable definiert werden, und zwar so:

Code: Alles auswählen

var Integer iCount = 0
Natürlich ist die Aktualisierung der UI nicht zwangsläufig sekundengenau, die Angabe ist also nur ungefähr zu verstehen, selbst wenn man die Aktualisierung sieht.
openHAB4.3.5 stable in einem Debian-Container (bookworm) (Proxmox 8.4.1, LXC), mit openHABian eingerichtet

violine21
Beiträge: 600
Registriert: 20. Sep 2019 05:49
Answers: 7

Re: Problem mit einem Timer in einer Rule

Beitrag von violine21 »

udo1toni hat geschrieben: 13. Apr 2020 21:08 wo ist also (außer dem Spieltrieb) der Benefit?
:P Ertappt. Genau der Spieltrieb brachte mich dazu, die Frage grundsätzlich anzugehen.
Meinen Ansatz hatte ich bereits umgesetzt und habe gemerkt, das es eigentlich ohne Wert ist. Zu dem betreffenden Zeitpunkt schaut man
sowieso nicht auf die Sitemap. Vielleicht während der Testphase.
Aber die Herangehensweise hat mich interessiert.
Danke für Dein Beispiel! Sehr interessant!

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

Re: Problem mit einem Timer in einer Rule

Beitrag von udo1toni »

violine21 hat geschrieben: 15. Apr 2020 19:20 Ertappt.
:D
openHAB4.3.5 stable in einem Debian-Container (bookworm) (Proxmox 8.4.1, LXC), mit openHABian eingerichtet

violine21
Beiträge: 600
Registriert: 20. Sep 2019 05:49
Answers: 7

Re: Problem mit einem Timer in einer Rule

Beitrag von violine21 »

Hallo,
ich habe hier noch ein kleines Problem mit einem Timer. Folgender Code in einer Rule wird minütlich getriggert:

Code: Alles auswählen

if((Komfortleistung.state as Number) >= 700) {
            SRelais_B2_Relay2Output.sendCommand(ON)
            if(t_FHZ_2 === null) {
                t_FHZ_2?.cancel    
                t_FHZ_2 = createTimer(now.plusSeconds(120), [ |
                FHZ_2_Freigabe.postUpdate(ON)            
                ] )  
            }
        }
Wenn die Komfortleistung >= 700 ist, soll "SRelais_B2" anziehen.
Ausserdem soll der Timer "t_FHZ_2" starten, wenn er noch nicht aktiv ist. Er soll also nur 1x starten und nach 120 Sek soll
das Item "FHZ_3_Freigabe" den Status ON annehmen.
Da der Timer länger läuft, wie die Triggerzeit und die "Komfortleistung" >= 700 ist, habe ich den Verdacht, das der Timer jedes Mal
neu erzeugt und gestartet wird.
Kann ich das damit umgehen?

Code: Alles auswählen

if(t_FHZ_2 === null) {
VG André

Darkwin101
Beiträge: 424
Registriert: 6. Mär 2019 11:19
Answers: 14

Re: Problem mit einem Timer in einer Rule

Beitrag von Darkwin101 »

Du könntest mit einer Hilfsvariablen arbeiten

Code: Alles auswählen

var Integer Startvariable = 0 // Am Anfang der Datei erstellen


if((Komfortleistung.state as Number) >= 700) {
            SRelais_B2_Relay2Output.sendCommand(ON)
            if(t_FHZ_2 === null && Startvariable = 0) {
                t_FHZ_2?.cancel
                Startvariable = 1    
                t_FHZ_2 = createTimer(now.plusSeconds(120), [ |
                FHZ_2_Freigabe.postUpdate(ON)            
                ] )  
            }
            }
 if((Komfortleistung.state as Number) < 700){ Startvariable = 0}
 
Wie du die Variable zurücksetzt bleibt dir überlassen soll hier einfach dem Beispiel dienen.

violine21
Beiträge: 600
Registriert: 20. Sep 2019 05:49
Answers: 7

Re: Problem mit einem Timer in einer Rule

Beitrag von violine21 »

Darkwin101 hat geschrieben: 19. Apr 2020 17:31 Du könntest mit einer Hilfsvariablen arbeiten
Das ist wohl die sicherste Methode.

Ich dachte :( es genügt, wenn ich den Timerzustand
t_FHZ_2 === null oder im umgekehrten Fall
t_FHZ_2 !== null
abfrage?

Was genau repräsentiert der Timer-Status (=== null / !==null) überhaupt?
Der Timer wurde erzeugt?
Die Timerzeit läuft?

Ehrlich gesagt bin ich mit der Verwendung von Timern noch nicht so richtig auf du und du.

Besten Dank für die schnelle Antwort.

VG André

Darkwin101
Beiträge: 424
Registriert: 6. Mär 2019 11:19
Answers: 14

Re: Problem mit einem Timer in einer Rule

Beitrag von Darkwin101 »

Also mit Sicherheit wird dir das Udo1Toni am besten erklären können. Da ich auch Anfänger bin verstehe ich das mal so, === null es gibt keinen Aktiven Timer mit diesem Namen.
Jetzt ist dein Timer abgelaufen und damit existiert wieder kein Aktiver Timer und somit ist das if wieder erfüllt.

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

Re: Problem mit einem Timer in einer Rule

Beitrag von udo1toni »

Die Timervariable ist ja ein Handle für den Zugriff auf den Timer. Zu Beginn ist die Variable mit null gefüllt. Wenn der Timer erzeugt wird, liefert die Funktion createTimer() den Handle zurück, der daraufhin in der Variablen gespeichert wird. Soweit, so gut
Was kann man nun mit dem Handle anfangen?

Zunächst einmal kann man den Timer entfernen (myTimer.cancel). Der Timer wird umgehend aus dem Scheduler gelöscht.
Man kann den Timer erneut einplanen, bzw, die Startzeit ändern (myTimer.reschedule(dateTime)). Aber Obacht, das geht nur, solange der Timer noch läuft.
Man kann prüfen, ob der Timer beendet wurde (myTimer.hasTerminated) oder ob er gerade ausgeführt wird (myTimer.isRunning) Damit ist allerdings gemeint, dass der Code gerade ausgeführt wird, nicht, dass gerade auf die Ausführung gewartet wird. Im Zweifel ist diese Eigenschaft also nur wenige Millisekunden true.
Wenn der Timer gerade ausgeführt wird, kann man den Timer auch noch mit reschedule erneut planen. Ein cancel funktioniert aber nicht mehr, der Code läuft ja schon.

Wenn der Timer abgelaufen ist, verliert der Handle seine Gültigkeit. Allerdings könnte es ja sein, dass man nachschauen möchte, ob der Timer ausgeführt wurde (hasTerminated) weshalb der Handle nicht gelöscht wird.

Möchte man also in einer Rule einen Timer nur anlegen, wenn er noch nicht existiert, muss man nicht nur auf null prüfen, sondern im Timer selbst die Variable zum Abschluss auch wieder auf null setzen. Der Timer muss also so aussehen:

Code: Alles auswählen

var Timer t_FHZ_2 = null // Am Anfang der Datei erstellen

[...]
if((Komfortleistung.state as Number) >= 700) {
    SRelais_B2_Relay2Output.sendCommand(ON)
    if(t_FHZ_2 === null) 
        t_FHZ_2 = createTimer(now.plusSeconds(120), [ |
            FHZ_2_Freigabe.postUpdate(ON)
            t_FHZ_2 = null
        ] )  
}
[...]
Mehr braucht es eigentlich nicht, um auf das Vorhandensein des Timers zu testen.

Der Befehl

Code: Alles auswählen

FHZ_2?.cancel
ist gleichbedeutend mit der Zeile

Code: Alles auswählen

if(FHZ_2 !== null) FHZ_2.cancel
Er ist also im Kontext (es ist sicher, dass FHZ_2 === null ist) sinnlos.
openHAB4.3.5 stable in einem Debian-Container (bookworm) (Proxmox 8.4.1, LXC), mit openHABian eingerichtet

violine21
Beiträge: 600
Registriert: 20. Sep 2019 05:49
Answers: 7

Re: Problem mit einem Timer in einer Rule

Beitrag von violine21 »

Allerbesten Dank Udo!!!

Nur noch mal zum Verständnis:
Wenn der Timer gestartet wurde, genügt eine simple Abfrage

Code: Alles auswählen

if(t_FHZ_2 === null)
damit bei erneuter Triggerung der Rule und Richtigkeit der if-Bedingung der Timer nicht noch einmal neu gestartet wird?
Das wäre wichtig z.B. bei langen Timerlaufzeiten.
Er läuft also bis zum Ablauf der Zeit unberührt von allen Bedingungen, es sei denn:
1. Er wird an anderer Stelle gecancelt

Code: Alles auswählen

t_FHZ_2?.cancel
2. Er wird neu geladen

Code: Alles auswählen

t_FHZ_2.reschedule(dateTime)
Zunächst einmal kann man den Timer entfernen (myTimer.cancel). Der Timer wird umgehend aus dem Scheduler gelöscht.
Wenn der Timer gerade ausgeführt wird, kann man den Timer auch noch mit reschedule erneut planen. Ein cancel funktioniert aber nicht mehr, der Code läuft ja schon.
Gibt es eine Möglichkeit, den Timer während er läuft abzubrechen und zu löschen? So wie ich es verstanden habe, geht da nur reschedule?
Damit würde er ja aber noch in den "Startlöchern stehen"?

VG André

Antworten