I am trying to achieve the same with the following rules, checked the remarks above but cannot find my error.
Aim is to get a notification if the garagedoor has been opened for more than a defined timeframe; if its closed within the timeframe, no notification shall be sent.
Please note, that the seconds are only used for testing, in reality I will change it to minutes.
Can you please advise?
Thanks so much,
db
import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*
var Timer extended_timer
var Timer unusual_timer
var EXTENDED_GARAGE_DOOR_TIME_SECONDS = 10
var UNUSUAL_GARAGE_DOOR_OPENED_SECONDS = 15
var SLEEP_TIME = 10
rule "Garage Door open for extended period of time sends notification"
when
Item zwave_device_XXX_node104_sensor_binary changed to ON
then
if (zwave_device_XXXnode104_sensor_binary.state == ON) {
extended_timer = createTimer(now.plusSeconds(EXTENDED_GARAGE_DOOR_TIME_SECONDS)) [|
pushover("Garage door has been open for an extended period of time");
]}
else {
if(extended_timer!=null) {
extended_timer.cancel
extended_timer = null
}
}
end
rule "Garage Door open for unusual period of time closes door and sends notification"
when
Item zwave_device_XXX_node104_sensor_binary changed to ON
then
if (zwave_device_XXX_node104_sensor_binary.state == ON) {
unusual_timer = createTimer(now.plusSeconds(UNUSUAL_GARAGE_DOOR_OPENED_SECONDS)) [|
pushover("Garage door has been open for an unusual period of time. Door has been automaticaly closed");
]
} else {
if(unusual_timer!=null) {
unusual_timer.cancel
unusual_timer = null
}
}
end ```
I get the following error:
2017-11-06 22:49:34.857 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model ‘garagedoor.rules’, using it anyway:
First thing, the [INFO] line in openhab.log: It says ‘The use of wildcard imports is deprecated.’ The meaning is, the first two lines in your rule file are wrong. Luckily you don’t need none of them any more, as they are now built in.
Second, your rule is triggered explicitly by Item zwave_device_XXX_node104_sensor_binary changed toON
So the rule will never be triggered to stop the timer.
You don’t need two rules either.
rule "Garage Door open for unusual period of time closes door and sends notification"
when
Item zwave_device_XXX_node104_sensor_binary changed
then
if (zwave_device_XXX_node104_sensor_binary.state == ON) { //Door is open
if(extended_timer!=null) //timer already exists, for whatever reason, so cancel it
extended_timer.cancel
extended_timer = createTimer(now.plusSeconds(EXTENDED_GARAGE_DOOR_TIME_SECONDS)) [| //start timer for extended message
pushover("Garage door has been open for an extended period of time") //message is sent if timer expires
]
if(unusual_timer!=null) //timer already exists, for whatever reason, so cancel it
unusual_timer.cancel
unusual_timer = createTimer(now.plusSeconds(UNUSUAL_GARAGE_DOOR_OPENED_SECONDS)) [| //start timer for unusual period message
pushover("Garage door has been open for an unusual period of time. Door has been automaticaly closed") //message is sent if timer expires
// closedoor.sendCommand(ON)
]
}
else { //Door is already closed, so cancel both timers
unusual_timer.cancel
unusual_timer = null
extended_timer.cancel
extended_timer = null
}
end
Of course the line // closedoor.sendCommand(ON) has to be changed to something meaningful, so that the door is closed automatically.
thanks for your help - I get the feeling, I´m getting closer to my goal…
I have modified it accordingly:
var Timer extended_timer
var Timer unusual_timer
var EXTENDED_GARAGE_DOOR_TIME_SECONDS = 10
var UNUSUAL_GARAGE_DOOR_OPENED_SECONDS = 15
var SLEEP_TIME = 10
rule "Garage Door open for unusual period of time closes door and sends notification"
when
Item zwave_device_XXX_node104_sensor_binary changed
then
if (zwave_device_XXX_node104_sensor_binary.state == ON) { //Door is open
if(extended_timer!=null) //timer already exists, for whatever reason, so cancel it
extended_timer.cancel
extended_timer = createTimer(now.plusSeconds(EXTENDED_GARAGE_DOOR_TIME_SECONDS)) [| //start timer for extended message
pushover("Garage door has been open for an extended period of time") //message is sent if timer expires
]
if(unusual_timer!=null) //timer already exists, for whatever reason, so cancel it
unusual_timer.cancel
unusual_timer = createTimer(now.plusSeconds(UNUSUAL_GARAGE_DOOR_OPENED_SECONDS)) [| //start timer for unusual period message
pushover("Garage door has been open for an unusual period of time. Door has been automaticaly closed") //message is sent if timer expires
// closedoor.sendCommand(ON)
]
}
else { //Door is already closed, so cancel both timers
unusual_timer.cancel
unusual_timer = null
extended_timer.cancel
extended_timer = null
}
end
For whatever reason, I still get the notified after the defined period of time, independantly if the door has been closed or not.
Any other thoughts? I checked various options and “played around” with timers but all of them didn´t work…
Your rule triggers when something happens at the door. After that it checks if the door is open. Then it starts a timer. When timer expires it sends a message. Nothing more. Add and if-clause after both timers to check door state. Something like:
if ( door.state == CLOSED ) {
timer.cancell
timer = null
break; // this line is for the first timer only when you want to stop
// rule execution and not get the later message if the door is closed
}
else {
send message()
}
( I’m on my mobile phone so hard to give final example but I think you’ll get the idea)
Edit
I read the whole topic through and to me it seems that you want someone to write the whole rule for you. Please don’t understand me wrong here because I’m not trying being rude. I just want to point out that reading docs and searching this forum most likely you’ll find the answear yourself and at the end of the day you have a working rule and have learned something new
No, the timer should be canceled by the rule instantly when the door is closed.
Please change the var definition:
var Timer extended_timer = null
var Timer unusual_timer = null
val int EXTENDED_GARAGE_DOOR_TIME_SECONDS = 10
val int UNUSUAL_GARAGE_DOOR_OPENED_SECONDS = 15
val int SLEEP_TIME = 10
As the three constants are, well… constant, they should be defined as constants (val vs. var) and it’s a good idea to set this to integer as well.
The timers should have an explicit default value either.
To ensure the rule works as expected, I would suggest to add a logInfo to the else part of the rule:
else { //Door is already closed, so cancel both timers
logInfo("myrules","Garage Door timers are canceled.")
unusual_timer.cancel
unusual_timer = null
extended_timer.cancel
extended_timer = null
}
This log line should appear in openhab.log the moment the door is closed.
timerX.cancel will cancel the timer if it currently waiting to run.
timerX = null just sets the variable timerX to null. The Timer that timerX used to point to will still be scheduled to run and will still run at the scheduled time.
You must use cancel to destroy the timer. Setting it to null can be optional. However most of use use if(timerX != null) to tell if there is a Timer currently scheduled to run in which case it is not optional.
So my take would be that I will always use timerX.cancel - as I understand this in effect will make a null of timerX.
Is there an obvious case where I should timerX=null? I understand that with this I plainly lose control of the actual timer. So I can reuse pointer timerX to create and manipulate next timer? But usecase does not come easy.
Incorrect. It just stops the Timer pointed to by timerX from executing. If that Timer has already executed the cancel will do nothing. But it will not set timerX to point to null. That is why you have to explicitly call timerX = null.
If you depend on any test for timerX === null you MUST call timerX=null.
Here is a simple alert when a door is left open for 5 minutes
var timer = null
rule "Timer rule"
when
Item MyDoor changed
then
if(MyDoor.state == OPEN){
// a Timer isn't already running
if(timer === null) {
timer = createTimer(now.plusMinutes(5), [|
// send alert
timer = null // rest the timer variable so we know the timer is no longer running
])
}
}
else if(MyDoor.state == CLOSED){
timer?.cancel // cancel the timer if it is running
timer = null
}
end
Would something like this work to cancel the notification as the door was closed before the timer ran out?
rule "Garage Door Sensor opened"
when
Item garageDoorContact changed from CLOSED to OPEN
then
sendBroadcastNotification("Garage Door " + triggeringItem.state.toString)
if (triggeringItem.state == OPEN) GarageDoor_Timer.sendCommand(ON) // Start timer
else GarageDoor_Timer.postUpdate(OFF) // Cancel the timer
end
rule "Garage Door Sensor closed"
when
Item garageDoorContact changed from OPEN to CLOSED
then
sendBroadcastNotification("Garage Door " + triggeringItem.state.toString) // for testing then should remove...
GarageDoor_Timer.postUpdate(CLOSED) // Post a closed upadate, hopefully to cancel the timer session???
end
rule "Garage Door Timer"
when
Item GarageDoor_Timer received command OFF
then
logInfo("Garage Door ", "Opened for 10 min.")
sendBroadcastNotification("Garage Door OPEN for 10 minutes")
end```
Uh, that depends on your definition of the item GarageDoor_Timer, but from what I see here, is that you use both OFF and CLOSED, which is not very intuitive to say the least.
In your first rule you don’t need the if ,else clause because your trigger is changed from CLOSED to OPEN, triggeringItem.state will always be OPEN
rule "Garage Door Sensor opened"
when
Item garageDoorContact changed from CLOSED to OPEN
then
sendBroadcastNotification("Garage Door " + triggeringItem.state.toString)
GarageDoor_Timer.sendCommand(ON) // Start timer
end
In your second rule, you need to send an OFF update to stop the timer
rule "Garage Door Sensor closed"
when
Item garageDoorContact changed from OPEN to CLOSED
then
sendBroadcastNotification("Garage Door " + triggeringItem.state.toString) // for testing then should remove...
GarageDoor_Timer.postUpdate(OFF) // Post a closed upadate, hopefully to cancel the timer session???
end
Third rule is fine.
You could combine your 2 first rules into one:
rule "Garage Door Sensor opened"
when
Item garageDoorContact changed
then
sendBroadcastNotification("Garage Door " + triggeringItem.state.toString)
if (triggeringItem.state == OPEN) {
GarageDoor_Timer.sendCommand(ON) // Start timer
} else {
GarageDoor_Timer.postUpdate(OFF) // Cancel timer
}
end