I use the following Rule. Note this is made generic for all my doors.
rule "Keep track of the last time a door was opened or closed"
when
Member of gDoorSensors changed
then
if(previousState == NULL) return;
val name = triggeringItem.name
val state = triggeringItem.state
// Update the time stamp
postUpdate(name+"_LastUpdate", now.toString)
// Set the timer if the door is open, cancel if it is closed
if(state == OPEN) sendCommand(name+"_Timer", "ON")
else postUpdate(name+"_Timer", "OFF")
// Set the message
val msg = new StringBuilder
msg.append(transform("MAP", "en.map", name) + " was ")
msg.append(if(state == OPEN) "opened" else "closed")
var alert = false
if(vTimeOfDay.state.toString == "NIGHT" || vTimeOfDay.state.toString == "BED") {
msg.append(" and it is night")
alert = true
}
if(vPresent.state == OFF) {
msg.append(" and no one is home")
alert = true
}
msg.append("!")
// Alert if necessary
if(alert){
aAlert.sendCommand(msg.toString)
}
// Log the message if we didn't alert
else {
logInfo(logName, msg.toString)
}
end
rule "Timer expired for a door"
when
Member of gDoorsTimers received command OFF
then
val doorName = transform("MAP", "en.map", triggeringItem.name)
aAlert.sendCommand(doorName + " has been open for over an hour")
if(vTimeOfDay.state.toString == "NIGHT" || vTimeOfDay.state.toString == "BED") {
triggeringItem.sendCommand(ON) // reschedule the timer
}
end
See [Deprecated] Design Pattern: Time Of Day (vTimeOfDay), Generic Presence Detection (naming scheme of Items so I can update and command related Items based on triggeringItem.name), Design Pattern: Separation of Behaviors (centralized alerting), Design Pattern: Human Readable Names in Messages (converting Item names to more human friendly names for use in alerts and logs) and Design Pattern: Expire Binding Based Timers (door open timers). These tow Rules are a great example showing how DPs are not intended to be used in isolation.
All of my doors are a member of gDoorSensors. Any time one of them changes the first Rule triggers.
First I update a DateTime Item to record when the door opened/closed.
If the door opened I start a Timer. If the door closed I cancel the Timer.
Finally, I generate a message to log and potentially alert. I will generate an alert immediately if it is night or bed time or no one is home.
The second Rule triggers when a door Timer expires and generates an alert. If it is night or bed time I reschedule the timer.
The one thing the Rules above don’t show is how to handle OH restarts. All of my door sensors are DIY and will respond with the door’s current state when I send a certain message. So I have a System started Rule that publishes that message which causes the sensors to publish their current states and if those states differ from what was restoreOnStartup the Rules above run.
Remember, Rules are event triggered, not state triggered. When you set up a cron trigger, you are scheduling events based on time. So if you do something like
0 0 20-23,0-6 ? * * * // I don't know if this is correct but the intent is to be between 20:00 and 06:100:
what you are doing is scheduling an event to occur at 20:00, 21:00, 22:00 and so on.