Timer countdown vsible in human reading format

I made some slight modifications and it works. Appriciate your support very much @JimT
How can we make it in the format of 01:20:59 ?

var Timer motionDelayTimer = null
var RuleFlag = null
val int timeoutMinutes = 20

rule "Office Motion Sensor ON" 

when 
    Item Office_Multisensor_6_Motion_Alarm changed from OFF to ON 
then
    if (RuleOfficeLight.state == ON){
        RuleFlag = true
        if(motionDelayTimer === null || motionDelayTimer.hasTerminated) {
            motionDelayTimer = null
            Office_FIBARO_Double_Switch.sendCommand(ON)
            Office_FIBARO_Dimmer.sendCommand(2)
            logInfo("Motion Office", "Movement recognised -> Light ON")
        }
        else {
            logInfo("Motion Office", "Movement recognised -> Timer stop.")
            motionDelayTimer.cancel
            motionDelayTimer = null
            CountdownItem.postUpdate(0)
        }
    }
    else{
        logInfo("Motion Office", "Rule deactivated")
    }

end

rule "Office Motion Sensor OFF"

when
    Item Office_Multisensor_6_Motion_Alarm changed from ON to OFF
then
    if(RuleFlag == true) { 
        CountdownItem.postUpdate(timeoutMinutes * 60) // reset the timeout
        logInfo("Motion Office", "No more movement -> Timer start.")
        RuleFlag = null
        motionDelayTimer = createTimer(now.plusSeconds(1), [ |
        
        val timeout = (CountdownItem.state as QuantityType).intValue 
        if (timeout == 0) {
            motionDelayTimer.cancel
            motionDelayTimer = null
            Office_FIBARO_Double_Switch.sendCommand(OFF)
            logInfo("Motion Office", "Timer elapsed -> Light OFF")
        } 
        else {
            CountdownItem.postUpdate(timeout - 1)
            motionDelayTimer.reschedule(now.plusSeconds(1))
          }
        ])
    }
    else{
        logInfo("Motion Office", "Rule deactivated already")
    }
end

Instead of giving you the answer, I’ll tell you how I got the answer:

If you go to openhab docs Configuration Guide → Items and scroll down to “State”:

you’ll notice a link to Java formatter syntax

Click it, and you’ll go to it, then you read through it… or just do an in-page search for “time format”.

thank you. Appriciate that. I will let you know my results

Ok got it.
The issue is:
If I define the state description to %tS seconds are counted properly from 60 down to 0

As soon as I define the state description with %tM:%tS displayed values are in common seconds.
Not min:sec

UPDATE!:
The proper formatting will be %tT

I have two more problems:

  1. Sometimes I receive this warning. Is it because the Item is updated every second?
2023-03-28 15:45:01.925 [WARN ] [d4j.internal.RRD4jPersistenceService] - Failed to open rrd4j database 'timerOfficeLight' to store data (java.lang.IllegalStateException: request interrupted for file:///var/lib/openhab/persistence/rrd4j/timerOfficeLight.rrd)
  1. If I want to display the countdown in HABPanel I can not format it to the wished format
<div class="countdown">{{itemValue('timerOfficeLight') | date:'HH:mm:SS'}}</div>

seconds are being displayed. What might be wrong?

I can not format Number:Time item in HABPanel widget! I am getting crazy on that.
I tried few suggestions from here but nothing worked.

I wouldn’t think so.

I have no idea what timerOfficeLight is and how it relates to anything else. This is the first time I’ve seen it - you haven’t mentioned it above I think.

Unfortunately I have zero knowledge about HABPanel. I have never used it. Have you tried reading the documentation? That’s what I would do before scouring the forums.

timerOfficeLight is an Number:Time Item
I changed your Timeout item and rename it to timerOfficeLight
In the item language it would be like that:

Number:Time timerOfficeLight "Timer countdown"

In the item configuration the pattern for the State Description is %tT this gives me a nice format.
Unfortunately I do not know how to format it into javascript recognised by the HABPanel widgets. Neither %tT nor HH:mm:SS work :frowning:

does the rrd error happen every second?

No it appears after a bunch of messages.

In addition I see this failure as well:

2023-03-29 08:49:48.461 [WARN ] [ore.internal.scheduler.SchedulerImpl] - Scheduled job '<unknown>' failed and stopped
java.lang.NullPointerException: cannot invoke method public boolean org.openhab.core.model.script.actions.Timer.cancel() on null
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1177) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1167) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1153) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:1098) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:878) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:243) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:475) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:251) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:488) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:267) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:475) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:251) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:213) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:47) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:30) ~[?:?]
	at com.sun.proxy.$Proxy424.apply(Unknown Source) ~[?:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$12(SchedulerImpl.java:191) ~[?:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$1(SchedulerImpl.java:88) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]

for the NPE:

var Timer motionDelayTimer = null
var RuleFlag = null
val int timeoutMinutes = 20

rule "Office Motion Sensor ON" 

when 
    Item Office_Multisensor_6_Motion_Alarm changed from OFF to ON 
then
    if (RuleOfficeLight.state == ON){
        RuleFlag = true
        if(motionDelayTimer === null) {
            Office_FIBARO_Double_Switch.sendCommand(ON)
            Office_FIBARO_Dimmer.sendCommand(2)
            logInfo("Motion Office", "Movement recognised -> Light ON")
        } else {
            logInfo("Motion Office", "Movement recognised -> Timer stop.")
            motionDelayTimer.cancel
            motionDelayTimer = null
            CountdownItem.postUpdate(0)
        }
    } else{
        logInfo("Motion Office", "Rule deactivated")
    }

end

rule "Office Motion Sensor OFF"

when
    Item Office_Multisensor_6_Motion_Alarm changed from ON to OFF
then
    if(RuleFlag == true) { 
        CountdownItem.postUpdate(timeoutMinutes * 60) // reset the timeout
        logInfo("Motion Office", "No more movement -> Timer start.")
        RuleFlag = null
        motionDelayTimer = createTimer(now.plusSeconds(1), [ |
        
        val timeout = (CountdownItem.state as QuantityType).intValue 
        if (timeout == 0) {
            motionDelayTimer = null
            Office_FIBARO_Double_Switch.sendCommand(OFF)
            logInfo("Motion Office", "Timer elapsed -> Light OFF")
        } else {
            CountdownItem.postUpdate(timeout - 1)
            motionDelayTimer.reschedule(now.plusSeconds(1))
          }
        ])
    }
    else{
        logInfo("Motion Office", "Rule deactivated already")
    }
end

For the rrd errors, I don’t know.

Do I see properly that the only condition as a part of code has been changed/removed?

.... || motionDelayTimer.hasTerminated)

not just that.

this appears usually after 290 sec. from timer kick off. Sometimes it comes twice in the timer period.
Timer is set to 1200sec.

I know this isn’t addressing the issue, but you should probably NOT persist that item anyway. What’s the point of persisting it?

What item do you exactly mean? What persistence?

Some more explanation…
I have an office room without the wall switches (they are physically but have been placed behind the furniture) The only way to lighten the office is movement recognition and time controlled lighting.
I know it is not the best way but only this one i was concentrating on.

By the way I very appreciate your support. You were able to help me in resolving quite big part of the problem. I am not a developer so I would not be able to resolve that issues without your support. Thanks for that again!

I don’t use rrd4j persistence, and I don’t really know how the “default” settings are and where / how to change it. Apparently openhab is shipped with rrd4j by default and it persists every item by default. @rlkoshak do you know how to exclude one particular item from the “default” rrd4j config?

Here’s the documentation and explanation about persistence:

and

Yeah, I know they have the same title… confusing even to me, but they are two different articles / pages.

I am using the following rule to display a String in the HABPANEL.

rule "CD val"
when
    Item cd_val changed
then
    val_now = (cd_val.state as Number).intValue
    
    var sec = val_now % 60
    var min = (val_now / 60) % 60
    var hrs = (val_now / (60*60)) % 24
    var day = val_now / (60*60*24)

    var String str 
        
    if ( day > 0 ) 
        str = String::format("%1$02d days, %2$02d:%3$02d:%4$02d", day, hrs, min, sec)
    else 
        str = String::format("%1$02d:%2$02d:%3$02d", hrs, min, sec)
        
    cd_str.postUpdate(str)        
end

this is what I was afraid of.
I can assume because the item is a Number:Time type we need to parse value to the single days. Hovewer, what is confusing me that for the same item I use state description %tT and it is working in the UI.

BTW. I opened a new post dedicated to this problem. To not confuse subjects with Timers and HABPanel.

Only by creating and defining an rrd4j.persist file where you define specifically those Items you do want to save. There is no way to say “all but this one Item”. It’s either all Items or only those items listed that get saved.

You could also just post "20 min" and OH will convert to seconds or hours or whatever as required. One of the purposes of units is that we do not need to convert between compatible units ourselves.

HABPanel is, relatively speaking, old. There were minimal updates made to it between OH 2 and OH 3. It doesn’t know anything about the State Description Pattern. I never used HABPanel either so I don’t know it if handles the pattern when defined on the Item’s label, but for that I think you might need to define the Items in text files.