I would use a lock. When the rule triggers from your caldav switch, grab the lock, send the command, sleep for a sec or however long you need to to keep the commands from interfering with eachother, then release the lock. All the other copies of the rule or other rules that depend on that lock will have to wait until it is unlocked before continuing.
Unfortunately this won’t work. You can trigger a Rule based on the Group receiving an update but unfortunately the Group receives multiple updates for each single update to one of its members.
So your rule will have to have a trigger for each of your outlets.
But you can use the same Rule to process everything and use the lock to space out the commands to your switches. The requirement to have a custom delay for each switch raises a bookkeeping problem though.
There are three ways to deal with it.
- Put the delays in a separate Item with a similar name to the switch and pull them up as described here: Design Pattern: Associated Items
- Put the delays in a global var/val data structure which gets populated in a System started rule
- Create a separate rule for each switch and a lambda to implement the logic and pass the delay to the lambda
1 is nice in that I like storing state in Items where possible but it will be really awkward to add new outlets.
2 will also be a bit awkward but a little less so for the same reasons.
3 will be more code but I think easier to deal with in the long run.
I would go with 3 (after a long time of recommending and implementing 1 and 2) which would look something like this:
NOTE: this is written using OH 2, I think it will work as written in OH 1.8. But I’m also just typing this in so there will likely be some errors.
import org.eclipse.xtext.xbase.lib.Functions
import java.util.concurrent.locks.ReentrantLock
val ReentrantLock lock = new ReentrantLock
val Functions$Function4<SwitchItem, OnOffType, Float, ReentrantLock, Boolean> switchDelay = [switch, command, delay, lock |
try {
lock.lock // blocks until the local is unlocked
switch.sendCommand(command)
Thread::sleep(delay)
}
catch(Throwable t) {
logError("outlets", "Error in switchDelay: " + t.toString)
lock.unlock // shoudn't be necessary but I've seen inconsistant behavior with finally executing when there is an error
}
finally {
lock.unlock
}
true // return value
]
rule "Switch 1"
when
Item CalSwitch1 received command
then
switchDelay.apply(RealSwitch1, receivedCommand, 10.5, lock)
end
rule "Switch 2"
when
Item CalSwitch2 received command
then
switchDelay.apply(RealSwitch2, receivedCommand, 0.5, lock)
end
...