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?
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.