Timer beenden

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
AndRe5575
Beiträge: 73
Registriert: 8. Jun 2020 20:16
Answers: 0

Timer beenden

Beitrag von AndRe5575 »

Hallo zusammen,

ich wollte gerne, in Abhängigkeit von der länge eines Tastendrucks, unterschiedliche Kommandos ausführen.
Deswegen wollte ich eine Rule verwenden um einen langen Tastendrucks zu erkennen:

Code: Alles auswählen

rule "LongPress"
when
    Item CMD_up changed or Item CMD_down changed            
then
var Timer LongPressUp = null
        if(CMD_up.state == OPEN)
        {
            logInfo("Timer", "Timer Start")
            LongPressUp = createTimer(now.plusNanos(750000000)) [|
            logInfo("Timer", "Timer Ende")
            ]
        }
        else
        {
            logInfo("Timer", "Timer Abbruch gewünscht")
        }
end
Log bei langen Tastendruck:
Taste gedrückt
Log: Timer Start
Log: Timer Ende
Taste nach 1s logelassen
Log: Timer Abbruch gewünscht

Log bei kurzen Tastendruck
Taste gedrückt
Log: Timer Start
Taste nach 500ms logelassen
Log: Timer Abbruch gewünscht
Log: Timer Ende

Entsprechend wollte ich in der Else Schleife den Timer zurücksetzen. Leider habe ich dies bisher nicht gschafft.
Versucht habe ich es mit:

Code: Alles auswählen

        else
        {
            logInfo("Timer", "Timer Abbruch gewünscht")
	    LongPressUp.cancel()
	    LongPressUp = null
        }
von udo1toni » 2. Mai 2021 00:21
Das liegt daran, dass Du den Timer nicht beendest. :)

Zunächst aber mal ist der Trigger suboptimal. Es wäre die Frage, wie der Taster an openHAB angebunden ist (also z.B. welches Binding Du nutzt).

Code: Alles auswählen

var Timer tLongPressUp = null
rule "Verzögerung"
when
    Item CMD_up changed or
    Item CMD_down changed
then
    tLongPressUp?.cancel // Falls der Timer initialisiert ist, entferne den Timer aus dem Scheduler
    if(CMD_up.state == OPEN) {
        logInfo("Timer", "Timer Start")
        tLongPressUp = createTimer(now.plusNanos(750000000), [| // 0.75 Sekunden
            logInfo("Timer", "Timer Ende")
        ])
    } else {
        logInfo("Timer", "Timer Abbruch gewünscht 2")
    }
end
Wichtig hier: der Timer wird nicht nur gecancelt, wenn der Timer gestoppt werden soll, sondern auch, wenn er angelegt wird. Ansonsten wird der Zeiger auf den Timer gesetzt, unabhängig davon, ob schon ein Timer läuft.
Gehe zur vollständigen Antwort

AndRe5575
Beiträge: 73
Registriert: 8. Jun 2020 20:16
Answers: 0

Re: Timer beenden

Beitrag von AndRe5575 »

Nach weiterem rumspielen und testen habe ich es nun mit folgenden Code am laufen:

Code: Alles auswählen

var Timer LongPressUp
rule "Verzögerung"
when
    Item CMD_up changed or Item CMD_down changed            
then
        if(CMD_up.state == OPEN)
        {
            logInfo("Timer", "Timer Start")
            LongPressUp = createTimer(now.plusNanos(750000000)) [|
            if (LongPressUp != null)
            {
                logInfo("Timer", "Timer Ende")
                LongPressUp = null
            }
            ]
        }
        else if(LongPressUp != null)
        {
            logInfo("Timer", "Timer Abbruch gewünscht 2")
            LongPressUp = null
        }
end

AndRe5575
Beiträge: 73
Registriert: 8. Jun 2020 20:16
Answers: 0

Re: Timer beenden

Beitrag von AndRe5575 »

Leider führt die Änderung noch nicht ganz zum gewünschten Ergebnis. Durch mehrfaches drücken der Taste wird wieder das Ende des Timers erreicht.
Eigentlich sollte durch das loslassen der Timer beim zweiten drücken von vorne starten, dies passiert allerdings nicht.

Zum testen habe ich den Timer auf 5Sek geändert:
  • Taste gedrückt (CMD_up.state=OPEN)
  • Taste nach 1 Sek logelassen (CMD_up.state=CLOSED)
  • Taste nach 2 Sek wieder gedrückt (CMD_up.state=OPEN)
  • Timer ist nach 2 Sek beendet
:-(

Des Weiteren ist mir nun folgendes aufgefallen: Seit ich nun timer in meiner Rule verwende, bekomme ich Warnungen, sobald ich in Visual Studio Code mit der Maus über die Timer gehe

Code: Alles auswählen

[Error - 17:45:19] Request textDocument/hover failed.
  Message: Internal error.
  Code: -32603 
java.util.concurrent.CompletionException: java.lang.IndexOutOfBoundsException: Position [
  line = 22
  character = 15
] text was : var Timer LongPressUp
var Timer LongPressDn
rule "Verzögerung"
when
    Item CMD_up changed or Item CMD_down changed            
then
        if(CMD_up.state == OPEN)
        {
            logInfo("Timer", "Timer Up Start")
            LongPressUp = createTimer(now.plusSeconds(5)) [|
            if (LongPressUp != null)
            {
                logInfo("Timer", "Timer Up Ende")
                LongPressUp = null
            }
            ]
        }
        if(CMD_up.state != OPEN)
        {
            logInfo("Timer", "Timer Up Abbruch gewünscht")
            LongPressUp = null
        }
end
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:331)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:346)
	at java.base/java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:704)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
	at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2088)
	at org.eclipse.xtext.ide.server.concurrent.AbstractRequest.logAndCompleteExceptionally(AbstractRequest.java:73)
	at org.eclipse.xtext.ide.server.concurrent.ReadRequest.lambda$doRun$0(ReadRequest.java:69)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.IndexOutOfBoundsException: Position [
  line = 22
  character = 15
] text was : var Timer LongPressUp
var Timer LongPressDn
rule "Verzögerung"
when
    Item CMD_up changed or Item CMD_down changed            
then
        if(CMD_up.state == OPEN)
        {
            logInfo("Timer", "Timer Up Start")
            LongPressUp = createTimer(now.plusSeconds(5)) [|
            if (LongPressUp != null)
            {
                logInfo("Timer", "Timer Up Ende")
                LongPressUp = null
            }
            ]
        }
        if(CMD_up.state != OPEN)
        {
            logInfo("Timer", "Timer Up Abbruch gewünscht")
            LongPressUp = null
        }
end
	at org.eclipse.xtext.ide.server.Document.getOffSet(Document.java:62)
	at org.eclipse.xtext.ide.server.hover.HoverService.hover(HoverService.java:53)
	at org.eclipse.xtext.ide.server.LanguageServerImpl.lambda$hover$31(LanguageServerImpl.java:714)
	at org.eclipse.xtext.ide.server.WorkspaceManager.doRead(WorkspaceManager.java:438)
	at org.eclipse.xtext.ide.server.LanguageServerImpl.hover(LanguageServerImpl.java:713)
	at org.eclipse.xtext.ide.server.LanguageServerImpl.lambda$hover$30(LanguageServerImpl.java:700)
	at org.eclipse.xtext.ide.server.concurrent.ReadRequest.lambda$doRun$0(ReadRequest.java:66)
	... 5 more
Die Timer an sich funktionieren aber, nur dass ich diese nicht beenden kann. Ich vermute einmal, dass er nur keinen Status des Timers in VSCode anzeigen kann.

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

Re: Timer beenden

Beitrag von udo1toni »

Das liegt daran, dass Du den Timer nicht beendest. :)

Zunächst aber mal ist der Trigger suboptimal. Es wäre die Frage, wie der Taster an openHAB angebunden ist (also z.B. welches Binding Du nutzt).

Code: Alles auswählen

var Timer tLongPressUp = null
rule "Verzögerung"
when
    Item CMD_up changed or
    Item CMD_down changed
then
    tLongPressUp?.cancel // Falls der Timer initialisiert ist, entferne den Timer aus dem Scheduler
    if(CMD_up.state == OPEN) {
        logInfo("Timer", "Timer Start")
        tLongPressUp = createTimer(now.plusNanos(750000000), [| // 0.75 Sekunden
            logInfo("Timer", "Timer Ende")
        ])
    } else {
        logInfo("Timer", "Timer Abbruch gewünscht 2")
    }
end
Wichtig hier: der Timer wird nicht nur gecancelt, wenn der Timer gestoppt werden soll, sondern auch, wenn er angelegt wird. Ansonsten wird der Zeiger auf den Timer gesetzt, unabhängig davon, ob schon ein Timer läuft.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

AndRe5575
Beiträge: 73
Registriert: 8. Jun 2020 20:16
Answers: 0

Re: Timer beenden

Beitrag von AndRe5575 »

Perfekt, vielen Dank. Wie so oft funktioniert es sobald man es richtig macht :-D

Evtl. könntest Du mir hierzu ein paar Pkt. erklären:

1. Du hast für das Erstellen des Timers folgende Zeile verwendet:

Code: Alles auswählen

tLongPressUp = createTimer(now.plusNanos(750000000), [| /*Befehlskette */
 ])
Bei mir sah es so aus:

Code: Alles auswählen

LongPressUp = createTimer(now.plusNanos(750000000)) [| /*Befehlskette */
]
In wie fern wirkt sich das Komma und das Schließen der Klammer an der anderen Stelle aus? Der Timer an sich hatte bei mir ja auch funktioniert, nur das ausschalten hatte ich falsch realisiert.

2.
Du hast den Timer mittels

Code: Alles auswählen

tLongPressUp?.cancel
beendet, ich hingegen versuchte es mit

Code: Alles auswählen

tLongPressUp.cancel()
(so hatte ich es in diversen anderen Skripts gefunden). Müsste das Abbrechen des Timers in der Else Schleife nicht den gleichen Effekt haben?

Die Anbindung bei diesen Taster erfolgt über MQTT (Shellys), aber für andere Funktionen wollte ich für meine Lichtsteuerung noch HUE Taster und Widget Buttons verwenden.

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

Re: Timer beenden

Beitrag von udo1toni »

AndRe5575 hat geschrieben: 2. Mai 2021 15:01 1. Du hast für das Erstellen des Timers folgende Zeile verwendet:
Ein Stück weit ist das Geschmacksache. Das Lambda ist letztlich ein Parameter der Funktion createTimer(), durch die Schreibweise, die ich verwende, wird dieser Umstand etwas deutlicher. Die andere Schreibweise funktioniert ebenfalls.
AndRe5575 hat geschrieben: 2. Mai 2021 15:01 2. Du hast den Timer mittels

Code: Alles auswählen

tLongPressUp?.cancel
beendet, ich hingegen versuchte es mit

Code: Alles auswählen

tLongPressUp.cancel()
(so hatte ich es in diversen anderen Skripts gefunden).
Du hast in Deinem Code überhaupt kein cancel ausgeführt, Du hast lediglich die Variable genullt. :)
Weiterhin bedeutet das ?, dass der Befehl .cancel nur ausgeführt wird, wenn der Zeiger tLongPressUp nicht null ist. Man könnte statt

Code: Alles auswählen

tLongPressUp?.cancel
auch

Code: Alles auswählen

if(tLongPressUp !== null) tLongPressUp.cancel
schreiben.
AndRe5575 hat geschrieben: 2. Mai 2021 15:01 Müsste das Abbrechen des Timers in der Else Schleife nicht den gleichen Effekt haben?
Ja, aber.

Ich habe ja geschrieben, dass Du den Timer unbedingt auch dann löschen musst, wenn Du ihn anlegst. Es könnte sonst passieren, dass der Timer zweimal (oder sogar noch häufiger) angelegt wird. Und da Du nur eine Timer Variable nutzt, verweist diese nur auf den letzten angelegten Timer, die übrigen kannst Du dann nicht mehr stoppen. Bei einem Timer, der weniger als eine Sekunde läuft, ist das vermutlich irrelevant, dennoch sollte man das im Hinterkopf behalten.
Wenn man den Timer so oder so beenden muss, wenn die Rule feuert, kan man das dann auch außerhalb der bedingten Verzweigung einmalig erledigen.
AndRe5575 hat geschrieben: 2. Mai 2021 15:01 Die Anbindung bei diesen Taster erfolgt über MQTT (Shellys), aber für andere Funktionen wollte ich für meine Lichtsteuerung noch HUE Taster und Widget Buttons verwenden.
Ah. Du musst halt mit den Triggern aufpassen, nicht dass da Kuddelmuddel passiert...
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten