I can not write this rule.
There are 2 switches sw1 and sw2. Sw1 is changing its state ocasionally. Sw2 changes state on the base of sw1:
when sw1 become ON -> sw2 become ON but this state of sw2 lasts at least 10min regardles what happens with sw1 state during this time. After 10 min when sw1 is still ON sw2 remains ON as long as sw1 remains ON.
then when sw1 changes to OFF, sw2 changes to OFF as well, but this state of sw2 lasts at least 5min regardles what happens with sw1 state during this time. After 5min when sw1 is still OFF sw2 remains OFF as long as sw1 remains OFF.
Summarizing sw2 min. ON time is 10min and min OFF time is 5min.
This sounds a whole lot like you are trying to control a light based on a motion sensor. Have you looked at any of the motion sensor examples, such as Design Pattern: Motion Sensor Timer?
Ultimately you need to use a Timer.
var Timer timer = null
rule "Sw1 changed to ON"
when
Item Sw1 changed
then
// if the timer is not null we ignore the change in Sw1
if(timer == null) {
// The two switches have different states and since there isn't a Timer running we know that Sw1
// changed states which will cause Sw2 to change as well
if(Sw1.state != Sw2.state) {
// how long to set the timer for
val time = if(Sw1.state == ON) 10 else 5
// change Sw2's state to match Sw1's
Sw2.sendCommand(Sw1.state)
// create a timer to update Sw2 after the timeout if necessary
timer = createTimer(now.plusMinutes(time), [|
if(Sw1.state != Sw2.state) Sw2.sendCommand(Sw1.state)
timer = null
])
}
}
end
I just typed in the above, something may be wrong.
Thank you for reference link and code example, especially for comments which pointed me out what is happening here! Your code is working perfectly but not exactly how I want, please correct me.
In your code:
If Sw1.state changes after timer is set, after the timeout Sw1.state -> Sw2.State and timer -> null.
Because timer is null after timeout we can immediately change state of Sw2 … but I want to wait.
It seems that to fulfill my assumptions after timeout of 1st timer I have to set another timer, and over and over for next cycles.
I spent last few hours trying to solve this problem, but without a success. Per analogia coding does not work
What I wrote matches your original set of requirements. I don’t understand what you are describing now.
Are you saying that you want there to be a five or 10 minute block in setting Sw2 every time it changes? In other words that after 10 minutes and Sw1 doesn’t match Sw2 we send the command to Sw2 to make them match but then it needs to be another 5 or ten minutes (depending on the state) before Sw2 can be changed again?
That is a completely different problem from what you originally stated and in a lot of ways a simpler problem. However, it has a tricky nested timers problem because you would need to create the Timer from inside the Timer (turtles all the way down).
This could be implemented with a lambda but I’m going to use Expire Based Timers.
rule "Sw1 changed"
then
Item Sw1 changed
then
// If either Timer is on, the Group Sw2_Timers state will be ON
if(Sw2_Timers.state == ON){
// The two switches are in different states
if(Sw1.state != Sw2.state) {
// Send the command to synchronize the switches
Sw2.sendCommand(Sw1)
// Set the timer
if(Sw1.state == ON) Sw2_Ten_Timer.sendCommand(ON)
else Sw2_Five_Timer.sendCommand(ON)
}
}
end
rule "Sw2 Timer went off"
when
Item Sw2_Five_Timer received command OFF or
Item Sw2_Ten_Timer received command OFF
then
// If Sw1 doesn't match Sw2, make them match and reset the timer
if(Sw1.state != Sw2.state){
// Send command to sync Sw2 with Sw1
Sw2.sendCommand(Sw1.state)
// Reset the Timer
if(Sw1.state == ON) Sw2_Ten_Timer.sendCommand(ON)
else Sw2_Five_Timer.sendCommand(ON)
}
end
Rich, thank you for your time, example code and comments! Now it works as expected.
Sorry about poor explanation of my problems. This is because I am beginner, my Engish isn’t fluent as well.
Just for others: there are few typos in the “Sw1 changed” rule. Below find rule with my corrections:
rule "Sw1 changed"
when //was then
Item Sw1 changed
then
if(Sw2_Timers.state == OFF){ //state was ON, should be OFF I think
if(Sw1.state != Sw2.state) {
Sw2.sendCommand(Sw1.state) //was Sw1 instead of Sw1.state
if(Sw1.state == ON) Sw2_Ten_Timer.sendCommand(ON)
else Sw2_Five_Timer.sendCommand(ON)
}
}
end
Once more thank you for sharing your knowledge and it would be interesting to see solution with a lambda.
Your corrections are correct. The forum has been unresponsive all day and it is easy to miss things on the phone. Search the forum for Cascading Timers for a lambda example. I don’t recommend its approach. At a high level it creates a lambda that creates the Timer for you. Then from your Rule and from inside the Timer you call this lambda to recreate the Timer.
It’s clever but overly complicated when compared to the Expire Binding Example. It is much cleaner to just sendCommand(ON) to set a timer than have a lambda that creates a lambda that can call itself.