Background activity in rules

I have a light that I would like to let blink (sending on and offs to a SwitchItem) as a background process.

I can use a Timer with a infinite loop to do the blinking. This will make the light blink.
But to stop blinking I would like to cancel the Timer from another rule. Timer.cancel seem to cancel the scheduled time but not the code that it’s executing meaning as soon as the timer is due the code can not be stopped remotely. Even nulling the timer would not do it. How can I achieve something like this? In java this would be a Thread.

  • A lambda woud be nice that takes the item (the light) and a rate value for the blinking speed. After the lambda starts how could I communicate to it from another rule?
  • Could this be done with CreateTimerWithArguments?
  • Since rules can run in parallel, is it good practice to create a rule that will loop as long as the light should blink using a public variable to stop it?

any help is needed here, thanks.

Timers are not the right tool for this job. You want Thread::sleep.

Be aware that each rule executes in its own thread so in essence your rule is a Java Thread.

val stop = false

rule "start blinking"
when
    Item myTriggerItem received command
then
    if(myTriggerItem.state == ON) {
        while(!stop) {
            myLight.sendCommand(ON)
            Thread::sleep(5000)
            myLight.sendCommand(OFF)
            Thread::sleep(5000)
        }
        stop = false
    }
    else {
        stop = true
    }
end

Specific answers to your questions:

The only way to communicate with a lambda or a Timer after it starts running is through updates to an Item. If you make an Item that acts as a flag you can set it to ON when you start your loop and then sendCommand(OFF) and in your lambda or Timer check the state of the Item in the while conditional clause.

I’ve not much experience with createTimerWithArguments but I think the answer is no. That lets you pass arguments to the lambda but I don’t think it gives you access to the Timer’s running context.

That is how I would/did implement it. I see no reason why this would be a problem and it is, IMHO the most direct and simple approach. And if you are like me and prefer storing state in Items rather than global vars you still can, just turn stop into a Switch Item and use sendCommand to update it instead of an assignment.

Thanks so much. Using this it worked perfectly! Sometimes things can be done too simple :wink:

rule "Ctxt_Pause ON"
	when Item Ctxt_Pause received command
	then
	//ENTER PAUSE
	if (receivedCommand == ON) {
        ....
        }
        //LEAVE PAUSE
	if (receivedCommand == OFF) {
        ....        
        }
        //BLINK
	while (Ctxt_Pause.state == ON) {
			sendCommand(TF_L_TR_4_3, ON)
			try { Thread::sleep(1000) } catch(Exception e) {}
			sendCommand(TF_L_TR_4_3, OFF)
			try { Thread::sleep(1000) } catch(Exception e) {}
	}


I’m glad it worked. I find in OH in particular, if what you are trying to do isn’y this simple then there is often a better way.

1 Like