I’m trying to write a rule where if the “pir_port” item changes from OPEN to CLOSE and the item “arm_pir == OFF”
play the mp3 file, and wait a minute before playing it again, even if the “pir_porta” item changes its status
rule "pir_move"
when
Item pir_porta changed from OPEN to CLOSED
then
if (arm_pir.state==ON){
sendCommand(luce_scale, ON)
sendCommand(madia, ON)
}
if (arm_pir.state==OFF){
//else {
playSound("movimento_porta_rilevato.mp3")
Thread::sleep(60000) // 60 secondi
}
end
You have a whole lot of errors in these rules. Some major, some minor.
Always use the method on the Item instead of the Action when you know the Item in the Rule. For example, luce_scale.sendCommand(ON)
I’m not sure why you commented out the else. In a case like this where arm_pir can only have two valid states the else is the better approach. If for some reason arm_pir.state changes while the if(arm_pir.state == ON) is executing, both if statements will be run. Also, it is causing the Rule to do extra work.
You basically already have the code already. As written you just need to add the playSound after the Thread::sleep to play it again. That will cause the sound to be played again after one minute.
One thing to realize is that every time that an event occurs, in this case pir_porta changing from OPEN to CLOSED an instance of this Rule will be triggered and start running. So if pir_porta goes to OFF during the Thread::sleep it doesn’t matter to the Rule, it is already running. BUT, if pir_porta goes to CLOSED again within that minute then the whole Rule will run again and you will have two copies of this Rule running at the same time and the sound will be played again for that one. And if this happens five times in a row, it will mean that NO other Rules will be able to run until one of these stops running. See Why have my Rules stopped running? Why Thread::sleep is a bad idea
So to solve your basic problem without using Thread::sleep use a Timer to schedule the second playSound in a minute.
rule "pir_port changed to CLOSED"
when
Item pir_port changed from OPEN to CLOSED
then
if(arm_pir.state == OFF) {
playSound("movimento_porta_rilevato.mp3")
createTimer(now.plusMinute(1), [ | playSound("movimento_porta_rilevato.mp3") ])
}
end
rlkoshak
I have taken your rule and tried to modify it to send a command if the door is left open longer than 15 seconds. My failed attempt just completes my command 15 seconds after the door is “OPEN”, no matter if it is “CLOSED” before the timer completes. How can I get the timer to stop if the door is “CLOSED” and if the door is not “CLOSED” repeat the command every 15 seconds until the door is closed?
rule "DoorOpenTooLong"
when
Item PatioDoorSensor changed
then
if(PatioDoorSensor.state == OPEN) {
createTimer(now.plusSeconds(15), [ | executeCommandLine("flite -voice awb -f /Doors/ShutPatioDoor.txt") ])
logInfo("DOOR", "Patio Door is Still " + PatioDoorSensor.state)
}
else
if(PatioDoorSensor.state == CLOSED){
logInfo("DOOR", "Patio Door is finally " + PatioDoorSensor.state)
}
end
Then I created a rule to turn on that timer when the door opens. When the door closes, it sends an update to turn off the timer. It continues to repeat the command every 15 seconds until the door is shut.
Rules:
rule "DoorOpenTimerStart"
when
Item PatioDoorSensor changed from CLOSED to OPEN
then
PatioDoorTimer.postUpdate ("ON")
end
rule "DoorOpenTimerAlert"
when
Item PatioDoorTimer changed from ON to OFF
then
if (PatioDoorSensor.state == OPEN) {
executeCommandLine("flite -voice awb -f /Doors/ShutPatioDoor.txt")
logInfo("DOOR", "Patio Door Open longer than 15 seconds, reseting Timer")
PatioDoorTimer.postUpdate ("ON")
}
else
if (PatioDoorSensor.state == CLOSED) {
PatioDoorTimer.postUpdate ("OFF")
logInfo("DOOR", "Patio Door Closed, Timer OFF")
}
end