[SOLVED] Openhab 2 Contact Sensor Time Rule

Hey openhabians!

I’ve got the following piece of code in my rules file. I’ve got a simple contact sensor on our garage door and it sends out a notification every time it changes state (eg. Garage opens / closes = notification). I’ve also got a switch (SecuritySystem) where I can turn these notifications off!

//Garage Door Sensor Is Open

rule "Garage Door Sensor"
when
   Item MGarageDoorSensor1 received update OPEN
then
       if(SecuritySystem.state == ON)
       {
           sendBroadcastNotification("Garage Door OPEN")
       }
end


//Garage Door Sensor Is Closed
rule "Garage Door Sensor CL"
when
   Item MGarageDoorSensor1 received update CLOSED
then
       if(SecuritySystem.state == ON)
       {
           sendBroadcastNotification("Garage Door CLOSED")
       }
end

I wanted to have a rule where if the garage door has been left open for, lets say 10 minutes, it sends out a notification to everyone.

I’ve tried other solutions that have been posted in the forums but each time I add them in, none of the rules work!

Anyone have any idea?

Any help / guidance appreciated (I’m new to this)

Use the expire binding and another item:

Switch GarageDoor_Timer { expire="10m,command=OFF" }

Rules:
//Garage Door Sensor Is Open

rule "Garage Door Sensor"
when
    Item MGarageDoorSensor1 changed
then
    if(SecuritySystem.state == ON) {
        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 Timer"
when
    Item GarageDoor_Timer received command OFF
then
    sendBroadcastNotification("Garage Door OPEN for 10 minutes")
end

I condensed your 2 rules into one and added a timer item and rule when it expires

1 Like

You’re a legend!!! Thanks heaps! I’ll give it a test tomorrow!

To make this more generic you can use something like what I use. I think I’ve posted this in a DP but I can’t remember so just reposting it here.

Group:Contact:OR(OPEN,CLOSED) gDoorSensors "The doors are [MAP(en.map):%s]" <door>
Group:Switch:OR(ON, OFF) gDoorsTimers

Contact vGarageOpener1 "Garage Door Opener 1 is [MAP(en.map):%s]" <garagedoor> (gDoorSensors)
Switch vGarageOpener1_Timer (gDoorsTimers, gResetExpire) { expire="1h,command=OFF" }

Contact vGarageOpener2 "Garage Door Opener 2 is [MAP(en.map):%s]" <garagedoor> (gDoorSensors)
Switch vGarageOpener2_Timer (gDoorsTimers, gResetExpire) { expire="1h,command=OFF" }

Contact vFrontDoor "Front Door is [MAP(en.map):%s]" <door> (gDoorSensors)
Switch vFrontDoor_Timer (gDoorsTimers, gResetExpire) { expire="1h,command=OFF" }

Contact vBackDoor "Back Door is [MAP(en.map):%s]" <door> (gDoorSensors)
Switch vBackDoor_Timer (gDoorsTimers, gResetExpire) { expire="1h,command=OFF" }

Contact vGarageDoor "Garage Door is [MAP(en.map):%s]" <door> (gDoorSensors)
Switch vGarageDoor_Timer (gDoorsTimers, gResetExpire) { expire="1h,command=OFF" }

Pay special attention to the Group memberships and the naming conventions. Not shown is gResetExpire which is used in a System started rule to retrigger the expire bindings on OH restart.

val logName = "entry"

rule "Set door timer"
when
  Member of gDoorSensors changed
then
  if(previousState == NULL) return; // we don't care about changes from NULL

  val name = triggeringItem.name
  val state = triggeringItem.state

  // 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
  }

  // Alert if necessary
  if(alert){
    msg.append("!")
    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

Theory of Operation:
Create a Timer for each sensor named using Design Pattern: Associated Items and place them in Groups.

When any of the door sensors changes state the first Rule triggers. This Rule sets the Expire timer if the door is OPEN and cancels the timer if it is CLOSED. See Design Pattern: Expire Binding Based Timers. We construct the name of the Timer Item using Associated Items naming conventions.

Finally, we construct the message. We only alert the users of the door opening/closing at night time (see Design Pattern: Time Of Day). Alerting is centralized using Design Pattern: Separation of Behaviors.

The second rule gets triggered when any of the door Timers goes off (i.e. receives command OFF). We use Design Pattern: Human Readable Names in Messages to convert the Item name into something more human friendly and then send the alert. If it is night time we reschedule the alert to go off again. During the day we only get the one alert.

An approach like this will work with all your door Items with just these two Rules and you can add new doors just by adding them to the right Group.

1 Like

Hey Vincent,

I just tried adding your code - the notifications for when the door status changes work 110% but with the timer for the door being open for 10 mins, it send a notification whether the door is open or not.

EG. Door opens and closes within 1 min, 9 mins later i get a notification saying the garage has been open for more than 10 mins even tho its closed!

Any ideas?

Hi Rich,

Thanks so much for this. Not going to lie looks a bit daunting at first but I’ll have a play around with it and let you know how I go! Thanks so much for sharing!

Yes, I made a typo. postUpdate not PostUpdate

rule "Garage Door Sensor"
when
    Item MGarageDoorSensor1 changed
then
    if(SecuritySystem.state == ON) {
        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

Works beautifully!! Amazing how something so small can make a difference!

Thanks so much for all your help!

Coolio, please like and mark the solution post. Thanks

Vincent

I tried your rule and I’m not getting the OFF command?

This is what I have so far:

rule "Garage Door Sensor"
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```


And then this for the 10min notification


```csv

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```

And I have this in my items file:


```csv
    Switch GarageDoor_Timer { expire="10m,command=OFF" }

Any thoughts?

Did you install the expire binding?

Nope? Missed that crucial piece. :roll_eyes:
Doing it now

Any idea why I’m getting duplicate notifications, using : sendBroadcastNotification()
I get two for every one?

Nope
Logs, please

Hi,

I like your code and tried to implement this rule. But, openhab and my VS code complains for the following lines:
Member - no viable alternative at input ‘Member’

Configuration model 'doors.rules' has errors, therefore ignoring it: [12,3]: no viable alternative at input 'Member'

the method or field is undefined for the following triggeringItem variables:

val name = triggeringItem.name
val state = triggeringItem.state

Cannot figure out what’s wrong :confused:
I am using OH2.2. I wondered if there are some imports required, but rather not as haven’t found any answer to that.

my testing code is as follows:

rule "Set door/gate timer"
  when
    Member of gEntrance_Sensors changed
  then
    if(previousState == NULL) {
      return
     }
      // we don't care about changes from NULL

    val name = triggeringItem.name
    val state = triggeringItem.state

    // Set the timer if the door is open, cancel if it is closed
    if(state == OPEN && Night.state == "OFF") sendCommand(name+"_Timer", "ON")
    else postUpdate(name+"_Timer", "OFF")

    // Set the message
    val msg = new StringBuilder
    msg.append(transform("MAP", "entrances.map", name) + " sa ")
    msg.append(if(state == OPEN) "otwarte" else "zamkniete")

    //val morningStart = now.withTimeAtStartOfDay.plusHours(6).millis 
    /*var alert = false
    if(Night.state.toString == "ON" ) {
      msg.append(" a jest noc")
      alert = true
    }
    if(vPresent.state == OFF) {
      msg.append(" and no one is home")
      alert = true
    }

    // Alert if necessary
    if(alert){
      msg.append("!")
      sendNotification("krzysztof_rrr@wp.pl", msg.toString)
    }*/
    // Log the message if we didn't alert
    //else {
    logInfo("rules", msg.toString)
    //}
  end

Any hint?

What version of openHAB are you running?

2.2

Member of was introduced in 2.3

ah, not good :frowning:
I have bunch of knx items that’s why I am a bit resistant to move to 2.3. Unless I can somehow keep my KNX1 and still move to 2.3? Maybe.

Then change the rule trigger:
Put in there all the members of the group

That will solve your triggeringItem problem at the same time

rule "Set door/gate timer"
  when
    Item Sensor1 changed or
    Item Sensor2 changed or
    ....
  then
1 Like