Perhaps this is caused by the behavior of your PIR. How often does it switch from OPEN to CLOSED and back when it detect movement? If it is almost immediately it could be the case that you end up with two copies of the rule running at the same time which would set up two timers if the timing falls just right.
You can avoid that by using a lock.
...
import java.util.concurrent.locks.ReentrantLock
val ReentrantLock lock = new ReentrantLock
rule "Garage PIR lighting"
when
Item ZONE9_GENERAL_STATUS changed to OPEN
then
lock.lock
try {
logDebug("Lighting", "Garage PIR activated")
...
}
catch(Throwable t) {
logError("Lighting", "Error processing ZONE9_GENERAL_STATUS update: " + t)
}
finally {
lock.unlock
}
end
The try/catch/finally is there so if there are any errors in your rule the lock will still get unlocked. Otherwise an error would basically kill this rule until you restart.
It this doesn’t work, it might be worth while looking at @bob_dickenson’s Proxy design pattern posted here.
It will provide a separation between the behavior of the PIR and the switching of your light so you can smooth out any erratic behavior caused by the PIR.