Set last tripped/alarm date, or last action date to an item - best practice?

Actually it does take a little bit for persistence to catch up. You can add a Thread::sleep(250) at the start of your rule and see if that makes a difference.

Hi, i added this to my light items. Now i can see, when a light was triggered the last time.

Now i want to make a rule, when some lights are on for a very long time, so they will be switched off.

How can i get the time how long the light is on?
Do i need to make a new number-item for each light e.g. “light_on_duration” where i can store the time or is there a better way to do this?

And second:
If i want to get the date/time of the last switching of the light (ON and OFF), how do i have to change the rule?

With this rule shown above, i only get the date/time of the last switching to ON-state.

Can i simply add a second “if” with

 if(sensor.state == OFF) {...

???

The usual way would be to start a timer when the lights are switched ON, that when it expires turns the lights OFF. Not really related to storing last timestamp.
See


and many similar.

I recommend using the Expire binding (which didn’t exist when the above posts were written).

It would look something like:

Switch Light 1 { blah blah blah, expire="1h,command=OFF" }
Contact Sensor1 { blah blah blah }
rule "Motion sensor triggered"
when
    Item Sensor1 changed
then
    Light1.sendCommand(ON)
end

The expire binding sets a timer when the Light1 receives a command ON and reschedules it upon each subsequent ON. After the indicated time passes without an ON command it turns the light OFF.

Thank you! With expire binding it works without any additional rule.


But now i want to check something else:

I want to check the time of my window contacts. If a window is opened too long and outside temperature is very low i want to get a notification on my smartphone.

Can i do that with your example also?

How can i measure the time, a windows is opened? Do i have to use timers for this?

You can use the Expire binding for this as well, but will want a separate Timer Item.

Here is an example from my rules (slightly simplified).

Contact vFrontDoor "Front Door is [MAP(en.map):%s]"
  { mqtt="<[chimera:entry_sensors/main/front_door:state:default]" }

Switch vFrontDoor_Timer
  { expire="1h,command=OFF" }
rule "Set Door Open Timer"
when
  Item vFrontDoor changed 
then
  if(vFrontDoor.state == OPEN) vFrontDoor_Timer.sendCommand(ON)
  else vFrontDoor_Timer.postUpdate(OFF)
end

rule "Timer expired for a door"
when
  Item vFrontDoor_Timer received command OFF
then
  aAlert.sendCommand("The front door has been open for over an hour")
  
  if(vTimeOfDay.state.toString == "NIGHT" || vTimeOfDay.state.toString == "BED") {
  	timer.sendCommand(ON) // reschedule the timer
  }
end

If you have a lot of doors and windows you want to track, you might find my full entry rules to be informative. Note that the rules below require persistence to be set up with everyChange to work.

You can find my Time of Day rules and Items here and my Alerting Items and Rules here though the names of my Items have changed since I wrote that last one.

For an explanation of how I access the Timer and LastUpdate Items from the Door Item’s name see this.

Group:Contact:OR(OPEN,CLOSED) gDoorSensors "The doors are [MAP(en.map):%s]"

Group:DateTime:MAX gDoorsLast "The last door event was [%1$tm/%1$td %1$tH:%1$tM]"

Group:Switch:OR(ON, OFF) gDoorsTimers

Switch aGarageOpener1 "Garage Door Opener 1"
  
Contact vGarageOpener1 "Garage Door Opener 1 is [MAP(en.map):%s]"
  (gDoorSensors)
  { mqtt="<[chimera:entry_sensors/main/garage/door1:state:default]" }
  
Switch vGarageOpener1_Timer
  (gDoorsTimers)
  { expire="1h,command=OFF" }
  
DateTime vGarageOpener1_LastUpdate "Garage Door Opener 1 [%1$tm/%1$td %1$tH:%1$tM]"
  (gDoorsLast)
  
Switch aGarageOpener2 "Garage Door Opener 2"
  
Contact vGarageOpener2 "Garage Door Opener 2 is [MAP(en.map):%s]"
  (gDoorSensors)
  { mqtt="<[chimera:entry_sensors/main/garage/door2:state:default]" }

Switch vGarageOpener2_Timer
  (gDoorsTimers)
  { expire="1h,command=OFF" }

DateTime vGarageOpener2_LastUpdate "Garage Door Opener 2 [%1$tm/%1$td %1$tH:%1$tM]"
  (gDoorsLast)
  
Contact vFrontDoor "Front Door is [MAP(en.map):%s]"
  (gDoorSensors)
  { mqtt="<[chimera:entry_sensors/main/front_door:state:default]" }

Switch vFrontDoor_Timer
  (gDoorsTimers)
  { expire="1h,command=OFF" }
  
DateTime vFrontDoor_LastUpdate "Front Door [%1$tm/%1$td %1$tH:%1$tM]"
  (gDoorsLast)
  
Contact vBackDoor "Back Door is [MAP(en.map):%s]"
  (gDoorSensors)
  { mqtt="<[chimera:entry_sensors/main/back_door:state:default]" }

Switch vBackDoor_Timer
  (gDoorsTimers)
  { expire="1h,command=OFF" }

DateTime vBackDoor_LastUpdate "Back Door [%1$tm/%1$td %1$tH:%1$tM]"
  (gDoorsLast)
  
Contact vGarageDoor "Garage Door is [MAP(en.map):%s]"
  (gDoorSensors)
  { mqtt="<[chimera:entry_sensors/main/garage_door:state:default]" }

Switch vGarageDoor_Timer
  (gDoorsTimers)
  { expire="1h,command=OFF" }
  
DateTime vGarageDoor_LastUpdate "Garage Door [%1$tm/%1$td %1$tH:%1$tM]"
  (gDoorsLast)
import org.eclipse.xtext.xbase.lib.Functions

val logName = "entry"

val Functions$Function1<SwitchItem, Boolean> openGarage = [ opener |
	var topic = "NA"
	switch opener.name{
		case "aGarageOpener1": topic = "actuators/garage1"
		case "aGarageOpener2": topic = "actuators/garage2"
	}
	
	logInfo("entry", "Publishing ON to " + topic)
	publish("chimera", topic, "ON")
	
	// TODO send an alert if cerberos is down
	true	
]
 
rule "Garage Opener 1 Triggered"
when
  Item aGarageOpener1 received command
then
  openGarage.apply(aGarageOpener1)
end

rule "Garage Opener 2 Triggered"
when
  Item aGarageOpener2 received command
then
  openGarage.apply(aGarageOpener2)
end

rule "Keep track of the last time a door was opened or closed"
when
  Item vGarageOpener1 changed or
  Item vGarageOpener2 changed or
  Item vFrontDoor changed or
  Item vBackDoor changed or
  Item vGarageDoor changed
then
  Thread::sleep(100)
  val door = gDoorSensors.members.filter[s|s.lastUpdate("mapdb") != null].sortBy[lastUpdate("mapdb")].last as ContactItem
  
  // Update LastUpdate
  val last = gDoorsLast.members.filter[dt | dt.name == door.name+"_LastUpdate"].head as DateTimeItem
  last.postUpdate(new DateTimeType)

  // Set/cancel the Timer  
  val timer = gDoorsTimers.members.filter[t | t.name == door.name+"_Timer"].head as SwitchItem
  if(door.state == OPEN) timer.sendCommand(ON)
  else timer.postUpdate(OFF)
  
  // Log and alert
  val StringBuilder msg = new StringBuilder
  val doorName = transform("MAP", "en.map", door.name)
  
  msg.append(doorName)
  msg.append(" was")
  msg.append(if(door.state == OPEN) " opened" else " closed")
  
  var alert = false
  if(vTimeOfDay.state.toString == "NIGHT" || vTimeOfDay.state.toString == "BED"){
  	alert = true
  	msg.append(" and it is night")
  }
  
  if(vPresent.state == OFF) {
  	alert = true
  	msg.append(" and no one is home")
  }
  
  if(alert){
  	msg.append("!")
  	aAlert.sendCommand(msg.toString)
  }
  
  logInfo(logName, msg.toString)
end

rule "Timer expired for a door"
when
  Item vGarageOpener1_Timer received command OFF or
  Item vGarageOpener2_Timer received command OFF or
  Item vFrontDoor_Timer received command OFF or
  Item vBackDoor_Timer received command OFF or
  Item vGarageDoor_Timer received command OFF
then
  Thread::sleep(100)
  val timer = gDoorsTimers.members.sortBy[lastUpdate("mapdb")].last as SwitchItem
  val doorName = transform("MAP", "en.map", timer.name)  

  aAlert.sendCommand(doorName + " has been open for over an hour")
  
  if(vTimeOfDay.state.toString == "NIGHT" || vTimeOfDay.state.toString == "BED") {
  	timer.sendCommand(ON) // reschedule the timer
  }
end

Oh… This is a little bit too much for me…

//
import org.openhab.core.library.types.*   
import org.openhab.core.types.Command
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import java.lang.Math
import java.util.Calendar
import java.util.Date
import java.util.TimeZone
import java.text.SimpleDateFormat
import java.util.Map
//

// DateTime speichern bei letzter Änderung
rule "Date + Time Fensterkontakte zuletzt geöffnet"
when
        Item Kontakt_EG_WC changed
then
    // Get the Contact that was triggered
        gFensterkontakte?.members.filter(contact|contact.changedSince(now.minusSeconds(1))).forEach[ contact |
                 if(contact.state == OPEN) {
						gKontakteZeit?.members.filter(dt|dt.name == contact.name+"_last_opened").head.postUpdate(new DateTimeType)
				}
		]
end

I used the same rule like i did with my lighting, only thing is i changed the Group-names and changed light.state to contact.state, contact.name and so on.

Naming of the items is ok and also persistence for both groups is active.

Here are some of my items:

Group:Contact:OR(OPEN, CLOSED)gFensterkontakte   "Fensterkontakte [%d]" <contact>
Group gKontakteZeit

Contact  Kontakt_EG_WC          	"EG WC [MAP(de.map):%s]"				(gFensterkontakte)				{ knx = "5/1/4" }


DateTime Kontakt_EG_WC_last_opened		"EG WC [%1$td.%1$tm., %1$tH:%1$tM]"			(gKontakteZeit)

I don´t get an error mesage, rule is not triggered. Nothing happens if i open the windows. I tested with expire, this works. It´s very much to write down if i want to do the expire check for every windows…

I need this rule with last opened for another thing too.

I tested another example from rlkoshak for my problem: (i´m on oh 1.8.3)

Here my rule:


rule "Fensterkontakte State Changed"
when
		Item gFensterkontakte received update // NOTE: the rule will trigger multiple times per event
then
		gFensterkontakte.members.forEach[ sensor |
				// Get the associated DateTime Item
				val dtStr = sensor.name + "_last_opened"
				val assocDT = gKontakteZeit.members.filter[dt|dt.name == dtStr].head as DateTimeItem

				// Update assocDT with the window's lastUpdate
				assocDT.postUpdate(new DateTimeType(sensor.lastUpdate))
		]
end

And here the error message:

2017-01-12 13:06:23.625 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Fensterkontakte State Changed': Could not invoke constructor: org.openhab.core.library.types.DateTimeType.DateTimeType(java.util.Calendar)

For the error, there is a millis or getMillis method on the Calendar object. That should solve the error:

assocDT.postUpdate(new DateTimeType(sensor.lastUpdate.millis))

For the rule:

  • I strongly recommend against using the ?. If there is a problem because something is null the ? tells the Rules DSL to ignore the error and fail silently.

  • I’ve encountered problems with filter on persistence values (lastUpdate, changedSince, etc.) when the Item is not persisted in the DB yet. You can work around this by filtering out those that are null (see below).

  • If you are unlikely to ever have contacts change within a second of each other you can use lastUpdate to get the Contact that triggered

  • It can take a few hundred milliseconds for persistence to catch up with the change so it is possible the new state isn’t saved to the DB yet when this rule runs.

  • Are you certain the rule is not triggering? Did you add a logInfo to confirm? I suspect the rule is triggering but just not doing anything due to one or more of the issues above.

  • Break it down step by step and make log statements to verify that each part of that long string of method calls on members is working.

Thread::sleep(300) // give persistence time to catch up
val haveHistory = gFensterkontakte.members.filter[c|c.lastUpdate != null]
logInfo("Test", "There are " + haveHistory.size + " contacts that have a last update")

val mostRecent = haveHistory.sortBy[lastUpdate].last
if(mostRecent == null) logError("Test", "Failed to find most recent")
else if(mostRecent.state == OPEN){
    val dt = gKontakteZeit.members.filter[dt|dt.name == mostRecent.name+"_last_opened").head
    if(dt == null) logError("Test", "Failed to find " + mostRecent.name+"_last_opened")
    else dt.postUpdate(new DateTimeType)
}

If you have errors the above will reveal them.

The rule with the ? was from youir example - see 2nd post in this thread.

Now i included your last example. But nothing happens.

I get many log-messages if i open a window, but all with the same text:

2017-01-12 19:37:12.902 [INFO ] [c.internal.ModelRepositoryImpl] - Refreshing model 'fensterkontakte.rules'
2017-01-12 19:37:44.301 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:37:44.309 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:37:44.309 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:37:44.324 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:34.216 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:34.247 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:34.327 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:34.343 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:34.347 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:41.542 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:41.601 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:41.614 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:41.646 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:41.680 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:41.684 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:41.699 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:41.780 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:41.795 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:45.196 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:38:45.206 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update

I’ve learned a lot in the past year. And I will continue to learn, as will you.

Given the lack of errors it looks like mostRecent is not OPEN. Time for more logging:

Thread::sleep(300) // give persistence time to catch up
val haveHistory = gFensterkontakte.members.filter[c|c.lastUpdate != null]
logInfo("Test", "There are " + haveHistory.size + " contacts that have a last update")

val mostRecent = haveHistory.sortBy[lastUpdate].last
logInfo("Test", "Most recent contact is " + mostRecent.name + " and its state is " + mostRecent.state)
if(mostRecent == null) logError("Test", "Failed to find most recent")
else if(mostRecent.state == OPEN){
    val dt = gKontakteZeit.members.filter[dt|dt.name == mostRecent.name+"_last_opened").head
    if(dt == null) logError("Test", "Failed to find " + mostRecent.name+"_last_opened")
    else dt.postUpdate(new DateTimeType)
}
else {
    logInfo("Test", mostRecent.name + " is not OPEN")
}

logfile:

2017-01-12 19:59:25.018 [INFO ] [c.internal.ModelRepositoryImpl] - Refreshing model 'fensterkontakte.rules'
2017-01-12 19:59:55.236 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:59:55.241 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:59:55.926 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:59:55.931 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 19:59:57.189 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_EG_WC and its state is CLOSED
2017-01-12 19:59:57.192 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_EG_WC and its state is CLOSED
2017-01-12 19:59:57.333 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_EG_WC and its state is CLOSED
2017-01-12 19:59:57.493 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_EG_WC and its state is CLOSED
2017-01-12 19:59:58.209 [INFO ] [org.openhab.model.script.Test ] - Kontakt_EG_WC is not OPEN
2017-01-12 19:59:58.221 [INFO ] [org.openhab.model.script.Test ] - Kontakt_EG_WC is not OPEN
2017-01-12 19:59:58.321 [INFO ] [org.openhab.model.script.Test ] - Kontakt_EG_WC is not OPEN
2017-01-12 19:59:58.329 [INFO ] [org.openhab.model.script.Test ] - Kontakt_EG_WC is not OPEN

I´ve only one datetime item for Kontakt_EG_WC for testing. Rest of contact items there are no additional datetime items.

Next test, now it seems to work…

Now i opened the windows and let it open, on the last tests i opened the windows only for 2-3 seconds and closed it.

2017-01-12 20:08:36.521 [INFO ] [c.internal.ModelRepositoryImpl] - Refreshing model 'fensterkontakte.rules'
2017-01-12 20:08:46.924 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:46.932 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:46.933 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:47.052 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:47.235 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:48.426 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:48.426 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:48.509 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:48.595 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:48.698 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:49.311 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:49.319 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:49.327 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:49.413 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:49.420 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:52.407 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:52.518 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:52.522 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:52.524 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:52.545 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:52.591 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:52.596 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:52.613 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:52.615 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:52.659 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:52.679 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:52.731 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:52.736 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:52.764 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:52.766 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:52.772 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:52.773 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:52.775 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:52.776 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:52.775 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:52.776 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:52.775 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:52.782 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:52.783 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:52.786 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:52.796 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:52.798 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:56.105 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:56.127 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:08:56.155 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:56.157 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:08:56.172 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_OG_Kizi_W_Nord and its state is CLOSED
2017-01-12 20:08:56.175 [INFO ] [org.openhab.model.script.Test ] - Kontakt_OG_Kizi_W_Nord is not OPEN
2017-01-12 20:09:10.806 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:09:10.851 [INFO ] [org.openhab.model.script.Test ] - There are 16 contacts that have a last update
2017-01-12 20:09:10.976 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_EG_WC and its state is OPEN
2017-01-12 20:09:11.025 [INFO ] [org.openhab.model.script.Test ] - Most recent contact is Kontakt_EG_WC and its state is OPEN

The multiple triggers of the rule you are seeing and the fact that the state takes awhile to become OPEN are not problems with the Rules and not something I can correct short of assuring you that the rule as written works just fine with these multiple triggers.

I changed my lighting rule to the same and there is also the same behavior. If i switch the light on and immediately off again, the state-changing will not be triggered and i get no new datetime.

So i can´t do anything about that?

What do you think is the problem here? Will it be better if i put every item to the “when” part of the rule instead of the group-item?

@rlkoshak I like how clean your rules are with the item naming convention. What does N_D stand for? I’m assuming D = Door but N = ?

I kind of want to adopt your naming scheme :slight_smile:

Ha! I just abandoned that naming scheme. I came up with it in the beginning but found myself not using it consistently and finding special cases where it didn’t fit.

But for completeness, my old naming convention was:

// Naming Conventions:
//  - Groups all start with a lowercase g
// 	- Items are all capitalized camel case
//  - Takes the form of X_X_Name
//	- The first letter denotes the Item type:
//		None	Internal utility
//		'N'		Sensor
//		'S'		Switch
//		'T'		Trigger (switch without a state)
//		'W'		Weather
//	- The second letter denotes the object type
//		None	Internal utility
//		'C'		Controller
//		'D'		Door
//		'I'		Input
//		'L'		Light
//		'V'		Value
//		'W'		Window

The fact that I had to document my naming scheme in my Items file in a comment should have been my first clue this approach was untenable.

I’ve since vastly simplified this scheme:

// Naming Convention: Starts with
// - g : Group
// - v : Value/Sensor
// - a : Actuator
// - t : Timer using Expire binding

What is after that initial letter is kind of free form. I usually do camel case first letter capitalized after that for an Item. Associated Items are named with a “_” followed by the what it is.

The one exception I have is Timers that are associated Items do not start with “t” and instead start the same as the “parent” Item and end with “_Timer”.

For an example from my current rewrite of my rules:

Group:Contact:OR(OPEN,CLOSED) gDoorSensors "The doors are [MAP(en.map):%s]"

Group:DateTime:MAX gDoorsLast "The last door event was [%1$tm/%1$td %1$tH:%1$tM]"

Group:Switch:OR(ON, OFF) gDoorsTimers

Switch aGarageOpener1 "Garage Door Opener 1"
  
Contact vGarageOpener1 "Garage Door Opener 1 is [MAP(en.map):%s]"
  (gDoorSensors)
  { mqtt="<[chimera:entry_sensors/main/garage/door1:state:default]" }
  
Switch vGarageOpener1_Timer // Gets set to ON when vGarageOpener1's state changes to OPEN, gets set to OFF (i.e. timer canceled) when vGarageOpener1's state changed to CLOSED, triggers an alerting rule when receives OFF command
  (gDoorsTimers)
  { expire="1h,command=OFF" }
  
DateTime vGarageOpener1_LastUpdate "Garage Door Opener 1 [%1$tm/%1$td %1$tH:%1$tM]"
  (gDoorsLast)

...
Group:Switch:OR(ON,OFF) gPresent

Switch vPresent "Presence [MAP(en.map):%s]" 
  <present>

Switch tPresent { expire="5m,command=OFF" } // when it goes OFF it fires a rule to set vPresent to OFF, gets set to ON when gPresent goes to OFF

I’m not super happy with my treatment of Timers but it is a minor concession to make writing my rules slightly easier. It is a whole lot easier to just append “_Timer” than it is to parse out the name of an Item and replace the first character. But not massively so so I might end up doing that eventually. After I get my system back up and running fully.

Thank you for that!
I agree on your first part where having to document all those abreviations would mean something. Your new simple approach looks much better! :slight_smile:

Quick question, if you look at your 2nd post in this thread you have a rule that loops though gDoorSensors to create a timestamp whenever the state changes. Do you run this rule in OH2?

I’m running OH2B5 and i find that after a few executions it seems to break OH2 and none of my rules function. Only way to fix it is a restart. I’ve since removed that code and went to a non-automated approach inside each individual rule… Just curious if you have the same problem with that code.

Thanks!

Yes.

I’ve had no similar problem. All I can say is it works just fine for me.

Hmm ok. I upgraded off the Beta to the snapshot #717 and still same issue. Its very strange. The same snip of code you use after a few executes or edits of .rules file will cause ALL rules to stop running.

The Rule:

rule "A Door's State Changed. Log Timestamp"
when
        Item vHouseDoor changed or
        Item vPatioDoor1 changed or
        Item vGarageDoor changed
then
{
//***********************************************************************************************************************************************
// 													DETERMINE WHAT DOOR OPENED FROM GROUP gDoorSensors	 										*
//***********************************************************************************************************************************************
   	gDoorSensors?.members.filter(door|door.changedSince(now.minusSeconds(1))).forEach[ door |
   		logInfo("RULE.DOORSENSOR", "[INFO] Door state changed: {}", door.name)
        
//***********************************************************************************************************************************************
// 														SET TIMESTAMP WHEN DOOR OPENS	 														*
//***********************************************************************************************************************************************	
		if(door.state == 1) {
			gDoorSensorsTime?.members.filter(dt|dt.name == door.name+"_LastUpdate").head.postUpdate(new DateTimeType)
			logInfo("RULE.DOORSENSOR", "[NOTICE] Setting OPEN timestamp for door: {} ", door.name)
		}
    ]
}
end

Debug logs don’t show much. I’ve enabled debug logs via:

openhab> log:set DEBUG org.eclipse.smarthome
openhab> log:set DEBUG  org.openhab.model.rule

And when i re-saved the .rule the logs looked like this when the rule execution failed:

2017-01-14 23:17:56.008 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model '04-doorsensors_dimmers.rules'
2017-01-14 23:17:56.167 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model '04-doorsensors_dimmers.rules'
2017-01-14 23:17:57.900 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'ON' to DecimalType '1' for item 'Kitchen_Window_PIR'
2017-01-14 23:17:57.902 [DEBUG] [ntime.internal.engine.RuleEngineImpl] - Executing rule 'Kitchen Window PIR'
2017-01-14 23:17:57.910 [INFO ] [del.script.RULE.MOTION.KitchenWindow] - --> Motion Detected
2017-01-14 23:17:59.227 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'ON' to DecimalType '1' for item 'vGarageDoor'
2017-01-14 23:17:59.230 [DEBUG] [ntime.internal.engine.RuleEngineImpl] - Executing rule 'A Door's State Changed. Log Timestamp'
2017-01-14 23:18:01.437 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'OFF' to DecimalType '0' for item 'vGarageDoor'
2017-01-14 23:18:01.525 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'OFF' to DecimalType '0' for item 'vGarageDoor'
2017-01-14 23:18:01.885 [DEBUG] [thome.io.rest.core.item.ItemResource] - Received HTTP PUT request at 'items/alexa_phone/state' with value 'OFF'.
2017-01-14 23:18:01.888 [DEBUG] [thome.io.rest.core.item.ItemResource] - Received HTTP PUT request at 'items/chris_phone/state' with value 'ON'.
2017-01-14 23:18:03.480 [DEBUG] [ntime.internal.engine.RuleEngineImpl] - Executing rule 'Garage Door State Changed'
2017-01-14 23:18:03.490 [DEBUG] [ntime.internal.engine.RuleEngineImpl] - Executing rule 'Alexa Presence Check/Counter'
2017-01-14 23:18:03.495 [DEBUG] [ntime.internal.engine.RuleEngineImpl] - Executing rule 'A Door's State Changed. Log Timestamp'
2017-01-14 23:18:03.499 [DEBUG] [ntime.internal.engine.RuleEngineImpl] - Executing rule 'Garage Door State Changed'
2017-01-14 23:18:03.515 [DEBUG] [ntime.internal.engine.RuleEngineImpl] - Executing rule 'Chris Presence Check/Counter'
2017-01-14 23:18:03.553 [INFO ] [arthome.model.script.RULE.DOORSENSOR] - [INFO] Door state changed: vGarageDoor
2017-01-14 23:18:03.644 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'ON' to DecimalType '1' for item 'vGarageDoor'
2017-01-14 23:18:03.732 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'ON' to DecimalType '1' for item 'vGarageDoor'
2017-01-14 23:18:07.411 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'OFF' to DecimalType '0' for item 'vGarageDoor'
2017-01-14 23:18:09.083 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'ON' to DecimalType '1' for item 'vGarageDoor'

You can see the rule refresh happening at the top. Then at the bottom the rule executing, only half of it… not the setting timestamp to the item… And right after that i opened and closed the sensor a few times and no rules fire:

2017-01-14 23:18:03.553 [INFO ] [arthome.model.script.RULE.DOORSENSOR] - [INFO] Door state changed: vGarageDoor
2017-01-14 23:18:03.644 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'ON' to DecimalType '1' for item 'vGarageDoor'
2017-01-14 23:18:03.732 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'ON' to DecimalType '1' for item 'vGarageDoor'
2017-01-14 23:18:07.411 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'OFF' to DecimalType '0' for item 'vGarageDoor'
2017-01-14 23:18:09.083 [DEBUG] [clipse.smarthome.core.items.ItemUtil] - Converting OnOffType 'ON' to DecimalType '1' for item 'vGarageDoor'