Simple timer rule help

Gday,

First try at creating a rule to have a switch on the sitemap I can turn on and it stays on for 3 seconds and then turns off.
This will energise a garage door to open or close. Eventually via MQTT to a mysensors relay.

I have two items,
Switch GD (displayed on sitemap)
Switch EnergiseGD (to connect to MQTT broker)

rule "Garage Door"
    when
        Item GD changed to ON
        
    then
        {sendCommand(EnergiseGD, ON)}
        timer = Timer.create(now.plusSeconds(3) [|
        {sendCommand(EnergiseGD, OFF)}
        {sendCommand(EnergiseGD, OFF)}
        ]
end

Could someone point me in the right direction?

Kind Regards,
George

1 Like

I have a similar setup for my garage door and use

Thread::sleep(3000)

instead of a timer. Works fine so far.

rule "Garage"
when
Item Garage received command
then
QR1.sendCommand(ON)
Thread::sleep(3000)
QR1.sendCommand(OFF)
end

Edit: Also I would recommend to use a mapping for the switch on the sitemap so that you don’t have to turn off the switch again (or use a postUpdate in your rule to turn the switch off again):

Switch item=Garage mappings=[ON="Garage open/close"]

If you want to use timers, though, it would have to look like this:

import org.openhab.model.script.actions.Timer

var Timer timer = null    

rule "Garage Door"
when
    Item GD changed to ON      
then
    sendCommand(EnergiseGD, ON)
    timer = Timer.createTimer(now.plusSeconds(3) [|
        sendCommand(EnergiseGD, OFF)
        timer = null   // reset the timer
    ])
end

sihui, thanks for that works really well and is nice and simple.

Birger I would really like to understand how to use timers for other things down the track. When I load that code into the designer it gives me a red cross on this line
timer = Timer.createTimer(now.plusSeconds(3) [|
Is there an addon I need to add or something like that?

Cheers,
George

Aw, sorry I didn’t see that. The lines must be

timer = createTimer(now.plusSeconds(3)) [| ... ]

Basically a timer is just a piece of code that is executed at some point in the future. The createTimer() function takes two parameters: the point in time, and a lambda expression stating the code to execute. The code itself is started in a separate thread, so it can be executed even when the rule itself has already ended.

In the example above, we bind it to a variable outside the rule, so it stays in memory until the variable is somehow destroyed (by restarting openhab, reloading the rules file or by assigning timer = null once it has finished executing).

1 Like

If the designer complains about the Timer type, you must add a line on top of the rules file:
import org.openhab.model.script.actions.Timer

Birger

Thanks for that, still seems to give me an error. Am I doing something wrong?

Cheers
George

What happens if you don’t reset the timer with timer = null?

Thanks sipvoip, Birger & sihui

I have two working solutions to the task,

import org.openhab.model.script.actions.*

var Timer timer = null

    rule "Garage Timer"
    when
    	Item GD received command
    then
    	if(receivedCommand==ON) {
    		if(timer==null) {
    			sendCommand(EnergiseGD, ON)
    			sendBroadcastNotification("Garage door energised")
    			timer = createTimer(now.plusSeconds(3)) [|
    				sendCommand(EnergiseGD, OFF)
    				sendCommand(GD, OFF)
                                    timer = null
    			]
    		} 
    	}
    end

and

rule "Garage"

when
Item GD changed to ON

then
sendBroadcastNotification("Garage door energised")
sendCommand(EnergiseGD, ON)
Thread::sleep(3000)
sendCommand(EnergiseGD, OFF)
sendCommand(GD, OFF)

end

Not quite sure which one is best probably just different ways to do a task. Along the way I figured out the notifications via my.openhab which is a nice thing to have.

Thanks for the pointers, I am on a steep learning curve at the moment and it is great to understand how the basics work. Heaps more to learn but I can now see some amazing outcomes are possible.

Cheers,
George

2 Likes

Actually not too much. An unused timer object will stay in memory. I guess it will not take too much space, but it is always good practice to remove unused resources, because quite often openhab will run on limited hardware.
Since we are talking about Java, I assume you don’t even actually free the memory, you just create a hint for the garbage collector that it can free the memory if necessary.

Since it’s just a 3 second timer, I think both attempts are good.

I personally would not recommend using Thread::sleep() for longer intervals or more complex rules. Every time the rule is triggered it will be kept in memory entirely, just for the purpose of waiting and then executing a few more lines.

You are more flexible with timers when it comes to complicated timing (“one hour after sunset”, “three minutes after system startup”, etc.) or if you plan to re-schedule (“keep the lights on if the motion sensor reports presence”) or cancel timers (“raise alarm in 5 minutes, except someone enters the correct code on the keypad”).

1 Like

Interesting, but if your going to use the timer over and over does it matter if you free it?

One thing to watch is that the timer spawns a new thread so if your using locks that count on a rule finishing before the next one starts (Like I did with my generator start rule) the lock will unlock before your timer has finished.

Good question.
As long as you always assign it to the same variable I would expect it to be written to the same place in the memory (at least logically). So your memory consumption should not increase over time.
If you don’t plan to cancel or re-schedule it, you don’t even need to assign it to a variable. Then it will be garbage-collected as soon as it has run (or the rules file is refreshed, or the service is restarted, of course).

But I have to admit I don’t really know all those things. I just recall some useful facts I have learned about the JVM years ago and fill the gaps with clever i-would-have-developed-it-like-this-assumptions… :slight_smile:

Just found this post via google.
Seems as if this import statement is not enough.

I had the same problem. The timer did not work.
Changing this to

import org.openhab.*

removed the red lines and everything worked fine.

1 Like

Hello All,
I tried to adapt the example to my sonoff S20. But somehow it doesn’t work.
I can’t find the error in my code. Can someone please advise:

import org.openhab.*

var Timer timer = null

rule "Steckdose KĂĽche Timer"
    when
    	Item ki_plug1_SWITCH received command
    then
    	if(receivedCommand==ON) {
    		if(timer==null) {
    			timer = createTimer(now.plusSeconds(5)) [|
                publish("mosquitto:cmnd/sonoff_ki_plug1/POWER:OFF")
               timer = null
    			]
    		} 
    	}
    end

Thanks in Advance
Florian

If using openHAB2, imports with * are not allowed anymore. Fortunately you don’t need any imports for this rule.

1 Like

Hello Udo,
I changed the rule to the following:

import org.openhab.model.script.actions.Timer

var Timer timer = null

rule "Steckdose KĂĽche Timer"
    when
    	Item ki_plug1_SWITCH received command
    then
    	if(receivedCommand==ON) {
    		if(timer==null) {
    			timer = createTimer(now.plusSeconds(5)) [|
                sendCommand(ki_plug1_SWITCH, OFF)
               timer = null
    			]
    		} 
    	}
    end

Still no reaction.
@kisseler used a string in a different scenario. MQTT Switching with String
Is that the solution?

Thank you
Florian

If using openHAB2, you don’t need this import to use timers:

import org.openhab.model.script.actions.Timer

What’s the item definition? Does the item work at all in any way?

Yes, I use openHAB2.

The item is configured as follows:

Switch ki_plug1_SWITCH "KĂĽche Steckdose 1" <light> (LR,gLight)
    { mqtt=">[mosquitto:cmnd/sonoff_ki_plug1/POWER:command:*:default],<[mosquitto:stat/sonoff_ki_plug1/POWER:state:default]" }

I can switch it on and off manually on the sitemap.