Design Pattern: Motion Sensor Timer

ezMotionTimer needs to be declared above any rule in that file.

Add logging statements so you know whether the rule is triggering.

That was the problem, now it works great.
Thank you very much :slight_smile:

In this topic I’ll go forward with some more terms: Motion detection → lights on - if it’s dark and within time period, with timer - Help needed

I don´t want to make the variables as global variables.

Can i make this inside the rule as well?

If i put val and var to the top of my rules-file, it works. But if i put it inside the rule, nothing happens…

working:

var Timer md1Timer = null
val int timeoutMinutes = 5

// KG Garage Licht aus nach 5 Minuten

rule "KG Garage Licht auto off"
when
    Item Licht_KG_Garage_1 changed
then
	if (Licht_KG_Garage_1.state == ON) {
			md1Timer = createTimer(now.plusMinutes(timeoutMinutes), [|
				Licht_KG_Garage_1.sendCommand(OFF)
				md1Timer = null
			]
	}
    else {
			md1Timer = null
    }
end

not working:

// KG Garage Licht aus nach 5 Minuten

rule "KG Garage Licht auto off"
when
    Item Licht_KG_Garage_1 changed
then
        var Timer md1Timer = null
        val int timeoutMinutes = 5
	if (Licht_KG_Garage_1.state == ON) {
			md1Timer = createTimer(now.plusMinutes(timeoutMinutes), [|
				Licht_KG_Garage_1.sendCommand(OFF)
				md1Timer = null
			]
	}
    else {
			md1Timer = null
    }
end

By doing this you are defining local vs. global variables. Local in this case means (as in all programming languages) the scope and the existence of this variable is limited to one execution of the code block, being your rule. The Timer variable will be deleted when reaching end and recreated when executing the rule again.

Yes, i know this. I want to have this variable “var Timer md1Timer = null” only inside my rule. The rule will not reach “end” while the timer is running.

And when the timer is “null”, i don´t need it anymore.

But this doesn´t work with “var timer…” inside the rule. No error-message in the log-file. I made some logging and the rule will not get triggered, if i put var inside it.

Do you know the reasen, why it doenst´t work?

I don’t think you understand how Timers work. They do not block the rest of the execution of your Rule. Once created the timer runs in the background while the rest of your Rule continues to execute. So in the above your rule immediately exits once the Timer is created instead of waiting around for the timeout.

This is why you must store the timer variable as a global.

See the following:

Your rule above, “KG Garage Licht auto off”, could be removed and replaced with adding the expire binding to the item:

Switch Licht_KG_Garage_1 "KG Garage Licht" { yourbinding="..." or channel="...", expire="5m,command=OFF" }

I found this very useful, it allows you to have different timeout values for items as well which is a benefit.

HI @rlkoshak, I try to run your code but with error, I don’t know how to make it work,
do you mind gave a hand on it?

10:24:45.871 [ERROR] [.script.engine.ScriptExecutionThread] - Rule ‘A Motion Detector triggered’: org.eclipse.smarthome.core.library.items.SwitchItem

import java.util.Map

val Map<String, Timer> timers = newHashMap

rule "A Motion Detector triggered"
when
    Item MS_LivingRoom_MotionSensor1 received update MOTION or
    Item MS_LivingRoom_MotionSensor2 received update MOTION
then
    Thread::sleep(100) // give persistence time to save the update
    val sw =  gMotionSensor.members.sortBy[lastUpdate].last as SwitchItem
    logInfo("Motion.Sensor", "Motion Sensor Counter start")

    val timeoutMinutes = 3 // use an appropriate value

    if(timers.get(sw.name) == null){
        timers.put(sw.name, createTimer(now.plusMinutes(timeoutMinutes), [|
        	logInfo("Motion.Sensor", "Motion Sensor Counter works")
            sw.sendCommand(OFF)
            timers.put(sw.name, null)
        ]))
    }
    else {
        timers.get(sw.name).reschedule(now.plusMinutes(timeoutMinutes))
        logInfo("Motion.Sensor", "Motion Sensor Counter timer extend")
    }
    logInfo("Motion.Sensor", "Motion Sensor Counter finished")
end

What item types are you motion detectors. I’ve never seen an Item with a MOTION state. In the rule you cast then to a SwitchItem which only has the states of ON and OFF.

Do you get the first log statement in your logs?

You may need to filter out the items that have yet to be saved to persistence.

val sw =  gMotionSensor.members.filter.[s.lastUpdate != null].sortBy[lastUpdate].last as SwitchItem

I use mihome, which motion sensor announce MOTION when detect motion,
I set String type at items,

yesterday I have setup mapdb and have * : strategy = everyChange, restoreOnStartup in mapdb.persist
I remove restoreOnStartup from influx and I see item state restored after system startup,
so I assume value should have saved.

I really don’t know how to do coding, according to your last reply, does your code only able to apply to item type is switch?

My code as written expects the motion sensors to be SwitchItems. That is what the as SwitchItem means when you get the latest updated item.

Change that to StringItem and it might work.

Also note the was a bug that was preventing the use of Strings in the updated or changed to rule triggers. Perhaps this has been fixed…

Thanks, I will try again once I am back home,
you mention OH2 prevent update or changed to rule triggers on Strings type,
does that mean if item type is string will not get trigger in rules if it’s not been fixed?
if it is than no wonder why I can’t set a test rules which will light up when door open,
I tried it last night without success, I thought I was using wrong code in rules.

Item MyStringItem changed works.

Item MyStringItem changed to "Some String" currently broken (unless I missed an update with a fix).

Item MySwitxhItem changed to ON works.

gerat info, Thanks for let me know, it will save me lot of time on trying,
I will continue try on the code see which part goes wrong

if you don’t mind, would you just a short question,
will if(receivedCommand==OPEN){ works? or it should only works when ==ON?

If the item that triggers the rule is a Contact, OPENED. If it is a Switch, ON.

Each Item type has different state types. You have to use what is appropriate for the Item type.

Thanks, I think I need to study on Docs regarding item type,
It’s really a long way to go for me to make OH2 runs as I expecte

Hi @rlkoshak

change to StringItem still not works, rules get trigger without error but just no further action
I change to switch items with transform than it works :grinning:
your provide information helps me a lot, Thank you in deep.

As Watou said on Jan 11, addressing a state that has not been updated for a while works well with the expire binding.

Here is a tutorial I did on using expire binding to catch nodes that have not reported in for a while. The tutorial includes links to expire binding documentation by Watou.

3 Likes

Great tutorial! Thanks for sharing it.

Just a note that the Expire binding is the brainchild of Michael Wyraz; I just pushed it along a bit. :smile: