How can I trigger a rule only when the item has the new state for a certain time?

Hi,

I’m using the radiator modules form Homematic ( HM-CC-RT-DN).
They have a “window switch”. If it is on, the radiator close.

Now I have the following rule whtch close the radiator, if a door or a window is open.

rule "Fensterschaltung Thermostate"
	when Member of gWindow changed or Member of gDoor changed

	then
		switch triggeringItem.name.toString {

			//Bathroom
			case "Window_EG_Bad1_State" : {
				switch Window_EG_Bad1_State.state.toString {
					case "OPEN"  : sendCommand(Temp_EG_Bad_Window,ON)
					case "CLOSED" : sendCommand(Temp_EG_Bad_Window,OFF)
				}
			}
			case "Door_EG_Bad1_State" : {
				switch Door_EG_Bad1_State.state.toString {
					case "OPEN"  : sendCommand(Temp_EG_Bad_Window,ON)
					case "CLOSED" : sendCommand(Temp_EG_Bad_Window,OFF)
				}
			}

		}


end

This rule works immediately. But this is not necessary, If I only open the door/window for maybe 10 seconds to get in the bath or open the window for a short time.
The rule should mor cover the case if the door or window stays open too long (> 5 minutes).

I need a solution, how I can adjust the rule to cover this case. So the trigger only starts after the window/door is open for a certain time.

I think if you search “fridge door alarm” you should the right approach. It’s not about rule triggers, as you cannot displace those in time. Instead, you run a rule triggered by current events, and use the rule to manage a timer that schedules something to be done in future - like checking to see if door is still open.

2 Likes

I found your suggested rule.
But isn’t this a solution if you have only one contact?
I have tons of contacts :worried: So the rule will start in worst case several times in 5 minutes. And every new start overrules the previous start, or?

Alright, so for multiple independently managed doors you will need multiple timers. There are ways to manage per-Item timers.
Old example

1 Like

See [Deprecated] Design Pattern: Motion Sensor Timer if you want to implement this yourself or Open Reminder if you want to just install and configure a rule instead of needing to code this yourself. (Note that Open Reminder is discussed on the Design Pattern post.

1 Like

I use the old Max system from ELV and there is no rule needed in OH to close the thermostate valve when a window state is changed. The window contact is bound to the thermostat.
If there is no window contact the thermostate recognize the open window through the temperature drop.
According to the datasheet of your homematic HM-CC-RT-DN thermostate, this should be exactly the same.
And why shoul the thermostate wait 5 minutes to close the valve?

The HM-CC-RT-DN has the same “window switch”. I use it for this functionality.

I’m not only monitor the windows, I monitor the doors too. I have children and they often left the door open :frowning:
But if the open/closed state immediately send an update to the “window switch” of the HM-CC-RT-DN, then I get too much traffic für the BidCos network. Mostly you just open and close a door within 5 seconds to get into a room. For this scenario its not necessary to send an update to the HM-CC-RT-DN. And think about the battery life …

So I only want to update the “window switch” of the HM-CC-RT-DN, when the state of the door/window changes for a longer time :slight_smile:

My current solution (after the help from @rossko57 and @rlkoshak :kissing_heart: :kissing_heart: :kissing_heart:) :

val Map<String, Timer> timers = newHashMap

rule "A OPEN-CLOSE triggered"
when
    Member of gWindow changed or Member of gDoor changed 
then
	logInfo("TriggerEvent: ", "Trigger Timer für " + triggeringItem.name.toString + " beginnt")	
	
    if(timers.get(triggeringItem.name) === null || timers.get(triggeringItem.name).hasTerminated()){
        timers.put(triggeringItem.name, createTimer(now.plusMinutes(3), [|
			//Updates the Trigger Item now with the state of the original Item
			val ItemName = ScriptServiceUtil.getItemRegistry.getItem(triggeringItem.name.toString + "_Trigger")
			logInfo("TriggerEvent: ", "Folgendes Item bekommt den Trigger: " + triggeringItem.name.toString + "_Trigger" + " mit Status: " + triggeringItem.state.toString)
			switch triggeringItem.state.toString {
				case "OPEN" : {
					ItemName.sendCommand(OPEN)
				}
				case "CLOSED" : {
					ItemName.sendCommand(CLOSED)
				}
			}
            timers.put(triggeringItem.name, null)
        ]))
    }
    else {
		logInfo("TriggerEvent: ", "Trigger Rescedule für :" + triggeringItem.name.toString + " mit Status: " + triggeringItem.state.toString)
        timers.get(triggeringItem.name).reschedule(now.plusMinutes(3))
    }
end

rule "Fensterschaltung Thermostate"
	when Member of gWindowDoorTrigger changed

	then
		switch triggeringItem.name.toString {

			//Bathroom
			case "Window_EG_Bad1_State_Trigger" : {
				switch Window_EG_Bad1_State.state.toString {
					case "OPEN"  : Temp_EG_Bad_Window.sendCommand(ON)
					case "CLOSED" : sendCommand(Temp_EG_Bad_Window,OFF)
				}
			}
			case "Door_EG_Bad1_State_Trigger" : {
				switch Door_EG_Bad1_State.state.toString {
					case "OPEN"  : Temp_EG_Bad_Window.sendCommand(ON)
					case "CLOSED" : sendCommand(Temp_EG_Bad_Window,OFF)
				}
			}
...
...
...

         }
end

I’m not a coder … so there will be room for improvement but … it works for me :smiley:

In JRuby:

rule "Fensterschaltung Thermostate" do
  changed gWindow.members, gDoor.members, for: 5.minutes
  run do |event|
    next unless [Window_EG_Bad1_State, Door_EG_Bad1_State].cover?(event.item)

    Temp_EG_Bad_Window << event.item.open?
  end
end

Although I would just write it like this instead:

items_to_check = Window_EG_Bad1_State, Door_EG_Bad1_State
rule "Fensterschaltung Thermostate" do
  changed *items_to_check, for: 5.minutes
  run do |event|
    Temp_EG_Bad_Window << event.item.open?
  end
end

Or if you like one-liners:

changed(Window_EG_Bad1_State, Door_EG_Bad1_State, for: 5.minutes) { |event| Temp_EG_Bad_Window << event.item.open? }

No need to create timers, no need to create extra virtual items

1 Like