Hue Motion Sensor Rule - Timer Problems

Hello everybody!
Unfortunately, at least for me, I have inexplicable problems with my Rule for the motion detector.

To the constellation.
I have a Hue Motion Sensor with Hue lamps in use. Depending on the time (solved by cron), the lamps in my floor should switch on with a defined brightness.

The first start of the rule everything works without problems. The timer is extended as desired with each movement. But when I leave the room and come back in, sometimes (not always) the light does not come on again. Only after a certain time does the motion sensor react again.

I then get the following error message:

2019-10-08 19:51:27.444 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘WC Motion - Lights ON’: cannot invoke method public abstract boolean org.eclipse.smarthome.model.script.actions.Timer.cancel() on null

My code for the motion detector is:

var Timer timerfloor = null

rule "Vorraum Motion - Lights ON" 

when 
    Item Floor_Motion changed from OFF to ON
then

    if ((Floor_Illuminance.state < 15) ){
    logInfo("Motion Vorraum", "Helligkeit unter 15 Prozent")
    
        if ((Nightmodus.state == ON) && (timerfloor === null || timerfloor.hasTerminated)){
            timerfloor = null
            logInfo("Motion Vorraum - Nachtmodus EIN", "Lampen werden auf 15 % gesetzt")
            
            Floor_Lamp1_Brightness.sendCommand(15)
            Floor_Lamp2_Brightness.sendCommand(15)
            logInfo("Motion Vorraum - Nachtmodus EIN", "Bewegung erkannt")

        }

        if((Nightmodus.state == OFF) && (timerfloor === null || timerfloor.hasTerminated)){
            timerfloor = null
            logInfo("Motion Vorraum - Nachtmodus AUS", "Lampen werden auf 100 % gesetzt")

            Floor_Lamp1_Brightness.sendCommand(100)
            Floor_Lamp2_Brightness.sendCommand(100)
            logInfo("Motion Vorraum - Nachtmodus AUS", "Bewegung erkannt")
        }
    }
    
    else {
        timerfloor.cancel
        timerfloor = null
        logInfo("Motion Vorraum", "Bewegung erkannt, Timer wird gelöscht")
    }
end

rule "Vorraum Motion - Sensor OFF"

when
    Item Floor_Motion changed from ON to OFF
then
    if(Floor_Motion.state == ON){
        return;
        }
        
        logInfo("Vorraum Motion OFF", "Timer auf 10 Sekunden gesetzt")
        timerfloor = createTimer(now.plusSeconds(30), [ |
        
            timerfloor.cancel
            logInfo("Vorraum Motion OFF", "Timer canceln")

            timerfloor = null
            logInfo("Vorraum Motion OFF", "Timer NULL")

            Floor_Lamp1.sendCommand(OFF)
            Floor_Lamp2.sendCommand(OFF)
            logInfo("Vorraum Motion OFF", "Lampen wurden ausgeschaltet")
        ])
end

I would really appreciate it if you could help me in this regard. Thanks in advance!

Best regards
Christoph

There are cases where the Floor_Illuminance.state will be greater than equal to 15 but you have not yet created a Timer (i.e. timerfloor === null). You can’t cancel null. You need to check to see if timerfloor is not null before trying to call cancel() on it. Luckily there is an easy shortcut for doing this.

timerfloor?.cancel

On another note, it’s pointless to cancel a timer inside the Timer’s lambda. By the time the lambda is running the Timer has already terminated.

Hello rlkoshak,

thank you for your feedback!

Unfortunately that did not bring the solution. I’ve been trying now for ages to get my motion detector to work with a variety of rules, but i always have the following problems:

  • the light does not switch on
  • the light switches on delayed
  • the light switches off, I leave the room for a moment and enter it again and the light does not switch on again
  • the light goes out, although I am in the room and there is a movement

Again my configuration:

  • HUE motion detector (ON / OFF)
  • HUE brightness sensor
  • HUE light
  • night mode (ON / OFF)

It should be so that as soon as a certain brightness is reached and the motion detector detects a movement, the light remains switched on for the duration of the movement. There is a night mode (ON / OFF), which switches the lamps on each to a certain brightness. If the motion detector detects no movement for a certain time, the light should be switched off. If i go back into the room, the light should be switched on again immediately.

Currently i have the following rule in use, which also does not work reliably. According to the log file, i have no errors.

var Timer motion_timer_floor = null

rule "Vorraum Motion - Lights ON"

when
    Item Floor_Motion received update ON
then

    if (Floor_Illuminance.state < 15){
        logInfo("Motion Vorraum", "Helligkeit unter 15 Prozent")

        if ((Floor_Lamp1_Brightness.state == 0) && (Floor_Lamp2_Brightness.state == 0) && (Nightmodus.state == OFF)) {

            Floor_Lamp1_Brightness.sendCommand(100)
            Floor_Lamp2_Brightness.sendCommand(100)
            logInfo("Vorraum Motion", "Licht ein - Timer 2 Minuten")
       
            motion_timer_floor = createTimer(now.plusMinutes(3), [|
            logInfo("Vorraum Motion", "Timer vorüber - send OFF")
            Floor_Lamp1_Brightness.sendCommand(0)
            Floor_Lamp2_Brightness.sendCommand(0)
            motion_timer_floor = null
            logInfo("Vorraum Motion", "Motion Timer = null")
            ])
        }

        if ((Floor_Lamp1_Brightness.state == 0) && (Floor_Lamp2_Brightness.state == 0) && (Nightmodus.state == ON)) {

            Floor_Lamp1_Brightness.sendCommand(8)
            Floor_Lamp2_Brightness.sendCommand(8)
            logInfo("Vorraum Motion", "Licht ein - Timer 2 Minuten")
       
            motion_timer_floor = createTimer(now.plusMinutes(3), [|
            logInfo("Vorraum Motion", "Timer vorüber - send OFF")
            Floor_Lamp1_Brightness.sendCommand(0)
            Floor_Lamp2_Brightness.sendCommand(0)
            motion_timer_floor = null
            logInfo("Vorraum Motion", "Motion Timer = null")
            ])
        }
    }

else {

        motion_timer_floor.reschedule(now.plusMinutes(2))
        logInfo("Vorraum Motion", "Timer erneuert auf 2 Minuten")
    }

end

Unfortunately, the situation is really very disturbing when suddenly the lights go out, for example when dressing or showering. I would really appreciate it if you could help me in this regard.

Or maybe someone else still has a rule that works fine with the HUE system (motion detector in combination with brightness).

Thanks in advance!

best regards
Christoph

It is perhaps worth a little explaining here.
This line creates a timer and stores a handle, a reference to the timer, in the variable motion_timer_floor. That’s all.

There are non-obvious consequences to that.
If you run the line again, say two minutes later, it still does the same thing.
So the original 3-minute timer is still running in the background, and will go off and do whatever it was told.
But you’ve lost the handle to that timer, because you have overwritten your motion_timer_floor variable with a handle to a brand new timer.

If you need your rule to deal with existing timers, things like cancel or reschedule, you need to do it explicitly, and need the handle for that.
.
If you need your rule to check if a timer is already running before creating a new one (and I am certain that you do!), then again you must do explicitly in your code using the handle.

You might look over example rules again, paying attention to checks for handle===null tests, and when to set the handle null.

Hello,

some time has passed and in the meantime I have written a rule which (for me) works very well. However, I still have a problem with the brightness sensor.

The process should be such that the motion sensor detects movement, checks whether the brightness is below the value I have defined, if so, the light should switch on and the timer should be started. If a movement is detected, the timer should be deleted again until no more movement is detected.

It is currently the case that the timer is no longer deleted, since the first if-condition checks whether the brightness is below a certain value. However, this is no longer the case because the lamps have been switched on and according to my current code it is too bright for the timer to be reset. The result is that the timer is triggered once and then expires (despite movement).

Now to my question, is there a way to convert the rule (maybe with a loop) so that the brightness is only checked at the beginning, so that the lights stay on as long as motion is detected.

This is my current code:

rule "floor_light_on"
when 
Item hue_floor_motionsensor changed from OFF to ON
then
if (hue_floor_motionsensor_illuminance.state > 15){
    return;}
    if (timer_floor_motion === null || timer_floor_motion.hasTerminated) {
        timer_floor_motion = null

        if(nightmodus.state == ON) {
            hue_floor_lamp1_brightness.sendCommand(20)
            hue_floor_lamp2_brightness.sendCommand(20)
            hue_floor_lamp1_color.sendCommand(100)
            hue_floor_lamp2_color.sendCommand(100)
            logInfo("floor_light_on", "motion_night -> 20 percent")
        }

        if(nightmodus.state == OFF) {
            hue_floor_lamp1_brightness.sendCommand(100)
            hue_floor_lamp2_brightness.sendCommand(100)
            hue_floor_lamp1_color.sendCommand(1)
            hue_floor_lamp2_color.sendCommand(1)
            logInfo("floor_light_on", "motion_day -> 100 percent")
        }
    }

    else {
        timer_floor_motion.cancel
        timer_floor_motion = null
        logInfo("floor_light_on", "motion -> delete timer")
    }
end

rule "floor_light_off"
when
    Item hue_floor_motionsensor changed from ON to OFF
then
    if (hue_floor_lamp1_brightness.state == 0 && hue_floor_lamp2_brightness == 0){
        return;}
        logInfo("floor_light_off", "no motion -> start timer")
        timer_floor_motion = createTimer(now.plusSeconds(120), [ |
            timer_floor_motion.cancel
            timer_floor_motion = null
            hue_floor_lamp1_brightness.sendCommand(0)
            hue_floor_lamp2_brightness.sendCommand(0)
            sendBroadcastNotification("Gang aus")
            logInfo("floor_light_off", "timer finish -> all off")

        ])
end

By the way, without this line, the rule works fine and as desired:

if (hue_floor_motionsensor_illuminance.state > 15){
    return;}

Thanks in advance!

best regards
Christoph

What kind of Item is hue_floor_motionsensor_illuminance.state ?

I’m guessing that Philips Hue binding provides a Number:Illuminance type channel.
You can’t compare a Quantity Type, a value with units, with just a number. 15 what? Candles, lux?

Hello @rossko57

thanks for your answer and hint.

That’s right, it’s a Number: Illuminance channel type. However, I defined the item as a number, so this had no effect on me. In the meantime I have adapted the channel type and the rule (… | “lx”).

Unfortunately, this did not bring the desired success either, because it is due to the rule itself. I will briefly describe it again:

  • A movement is detected and the motion detector changes from OFF to ON.
  • Then it is checked whether the brightness is greater than 12 (lx). If this is the case, the process is canceled. If this is not the case, the status of the “Nightmode” switch is checked (ON / OFF) and the lamps are switched on with the appropriate brightness.

Now the real problem arises. If a movement is now recognized, the timer should actually be reset. However, this is not the case because the rule checks at the beginning whether the brightness is greater than 12 (lx) - (which is the case due to the lamps being switched on) - and as a result the timer is not reset and expires.

I hope I was able to describe the problem in a reasonably understandable way…

Got to wonder “why”. You should check in openHAB log to see what state your Item actually takes up. Defining “just” a Number does not stop it being updated as a Quantity Type.

Number test1 "test one"

I can postUpdate that with units (and so can a binding channel)

2020-06-25 10:30:31.821 [vent.ItemStateChangedEvent] - test1 changed from NULL to 1.0
2020-06-25 10:30:51.248 [vent.ItemStateChangedEvent] - test1 changed from 1.0 to 2.0 km
2020-06-25 10:31:39.864 [vent.ItemStateChangedEvent] - test1 changed from 2.0 km to 3.0 °C
2020-06-25 10:31:53.325 [vent.ItemStateChangedEvent] - test1 changed from 3.0 °C to 4.0 lx

Okay, you will need to change your rule’s logic.Reschedule is I think the magic word here for your timer.

Got to wonder “why”. You should check in openHAB log to see what state your Item actually takes up. Defining “just” a Number does not stop it being updated as a Quantity Type.

You are absolutely right. According to my log the unit “lx” is displayed, so … | “lx”) works now perfectly for me.

Okay, you will need to change your rule’s logic.Reschedule is I think the magic word here for your timer.

I have now modified the rule a bit and used a “reschedule” for the timer. Unfortunately, there are still problems with the timer.

rule "FLOOR"
when
    Item hue_floor_motionsensor received update ON
then
    if(timer_floor_motion === null && hue_floor_motionsensor.state == ON && hue_floor_motionsensor_illuminance.state <= 10 | "lx" && nightmodus.state == OFF) {
    logInfo("FLOOR", "(DAY) Setting to ON and creating timer")
    hue_floor_lamp1_color.sendCommand(0)
    hue_floor_lamp1_brightness.sendCommand(100)
    hue_floor_lamp2_color.sendCommand(0)
    hue_floor_lamp2_brightness.sendCommand(100)
    timer_floor_motion = createTimer(now.plusSeconds(120), [|
        logInfo("FLOOR", "(DAY) Timer expired and setting to OFF")
        hue_floor_lamp1_brightness.sendCommand(OFF)
        hue_floor_lamp2_brightness.sendCommand(OFF)
        timer_floor_motion = null
    ])
    } 
    if(timer_floor_motion === null && hue_floor_motionsensor.state == ON && hue_floor_motionsensor_illuminance.state <= 10 | "lx" && nightmodus.state == ON) {
    logInfo("FLOOR", "(NIGHT) Setting to ON and creating timer")
    hue_floor_lamp1_color.sendCommand(100)
    hue_floor_lamp1_brightness.sendCommand(25)
    hue_floor_lamp2_color.sendCommand(100)
    hue_floor_lamp2_brightness.sendCommand(25)
    timer_floor_motion = createTimer(now.plusSeconds(120), [|
        logInfo("FLOOR", "(NIGHT) Timer expired and setting to OFF")
        hue_floor_lamp1_brightness.sendCommand(OFF)
        hue_floor_lamp2_brightness.sendCommand(OFF)
        timer_floor_motion = null
    ])
    } 
    else if (timer_floor_motion !== null) {
        logInfo("FLOOR", "Timer rescheduled")
        timer_floor_motion.reschedule(now.plusSeconds(60))  
    }
    else {
        logInfo("FLOOR","Motion detected, but state.DAY or illuminance > 10: nothing to do")
    }
end

According to my log files, the rule does everything right so far. At the beginning, the brightness and the night switch are used to check whether the light should be switched on and, if so, with which brightness level.

If the timer is now running, the timer is also reset when moving using “reschedule”. This works one to a few times and suddenly the light is switched off, although there is still movement. Unfortunately I cannot reproduce the behavior clearly, except that the light will go out at some point, even though I am still in the room.

You’ll need to examine the breadcrumb trail that you created with your logInfo() statements in your openhab.log, and the interaction with Item updates as revealed in your events.log
You could share the relevant parts for advice.

I’d be looking hard at your sensor updates. Different sensors do different things. What will happen if your particular sensor stays ON all the time while motion is detected?

We can make your if() a bit easier to comprehend;

when
    Item hue_floor_motionsensor received update ON
then
    if(timer_floor_motion === null && hue_floor_motionsensor.state == ON && hue_floor_motionsensor_illuminance.state <= 10 | "lx" && nightmodus.state == OFF) {
...

Okay, so your rule runs when motion sensor updates ON (even if it’s already ON), that’s good.
But no point at all checking inside the if() to see if motion sensor ON - you already know it is, because it has to be to run the rule.

Okay, so your rule runs when motion sensor updates ON (even if it’s already ON), that’s good.
But no point at all checking inside the if() to see if motion sensor ON - you already know it is, because it has to be to run the rule.

Yes, that makes sense. I just changed that.

I’d be looking hard at your sensor updates. Different sensors do different things. What will happen if your particular sensor stays ON all the time while motion is detected?

I have now tested this again and I think that is exactly the problem. If the motion sensor detects motion, it switches to the ON state. If there is continuous motion from this point on, the motion detector remains in the ON state and the timer expires.

I think I should inquire within the rule whether the status is still ON and then reset the timer. I tried this in if () and else if () but it didn’t work.

if (hue_floor_motionsensor == ON) {
    timer_floor_motion.reschedule(now.plusSeconds(60))
    logInfo("FLOOR", "Timer motionsensor == ON rescheduled")  
}

The definitive answer is in your events.log, we cannot see it.

What I do in these cases is split the functions.
You want to turn the lights ON when motion begins. Have a rule do that.
It can also look to see if there is timer already running, and cancel it if there is.
You don’t really want to run a timer until motion stops. Have a rule do that, rescheduling if already exists.