[SOLVED] Variable Scope Timer Rules

  • Platform information: 2.4

Hello World,

I’ve a trouble with a rules.

For understanding :
FF_FamilyRoom_MotionSensor_MotionStatus is a Xiaomi Motion Sensor (auto reset after 59s)
FF_FamilyRoom_Power is a Fibaro Switch

The following code should allow 2 things.
1 ° Operate the light in timer mode without interruption.
2 ° Return the light to the state preceding the timer mode.

It usually works fine, except that when I turn off the light manually before the end of the cycle, it turns on again after the cycle.

In previous versions the variables had a scope limited to the script file in which they were created.

Is this still true in OpenHab 2.4? I would like to force a timer cancel from another rules file.

var String FF_FamilyRoom_Power_PreviousState = null
var Timer FF_FamilyRoom_Timer = null

rule "Xiaomi Motion Sensor Salon"
when
	Item FF_FamilyRoom_MotionSensor_MotionStatus changed
then
	// FF_FamilyRoom_MotionSensor
	logInfo("Xiaomi","Motion Detected In Salon")
	if ( Daylight_Switch.state == OFF )
	{
		if(FF_FamilyRoom_Timer !== null)
		{ 
			FF_FamilyRoom_Timer.cancel()
		}
		else
		{
			FF_FamilyRoom_Power_PreviousState = FF_FamilyRoom_Power.state.toString()
			FF_FamilyRoom_Power.sendCommand("ON")
		}
		FF_FamilyRoom_Timer = createTimer(now.plusSeconds(300), [| 
			logInfo("Xiaomi","Auto OFF Salon")
			FF_FamilyRoom_Power.sendCommand(FF_FamilyRoom_Power_PreviousState)
			FF_FamilyRoom_Timer = null
		])
	}
end

Thanks in advance for your help.

Yes still true and will always be
In order to achieve this you may need to use the expire binding instead

Your timer creation was in the wrong if-else section
Try this:

var String FF_FamilyRoom_Power_PreviousState = null
var Timer FF_FamilyRoom_Timer = null

rule "Xiaomi Motion Sensor Salon"
when
    Item FF_FamilyRoom_MotionSensor_MotionStatus changed
then
    // FF_FamilyRoom_MotionSensor
    logInfo("Xiaomi","Motion Detected In Salon")
    if ( Daylight_Switch.state == OFF )
    {
        if(FF_FamilyRoom_Timer === null) { 
            FF_FamilyRoom_Power_PreviousState = FF_FamilyRoom_Power.state.toString()
            FF_FamilyRoom_Power.sendCommand("ON")
            FF_FamilyRoom_Timer = createTimer(now.plusSeconds(300), [ | 
                logInfo("Xiaomi","Auto OFF Salon")
                FF_FamilyRoom_Power.sendCommand(FF_FamilyRoom_Power_PreviousState)
                FF_FamilyRoom_Timer = null
            ])
        } else {
            FF_FamilyRoom_Timer.cancel()
            FF_FamilyRoom_Timer = null
        }
    }
end

Thank you for your answer, but I’m not sure if your rule does the same work as mine.

With yours, if the status of the motion detector changes before the end of the timer. The timer is canceled and destroyed.
But the light stays ON until a new motion is detected.

So if I go in a black room, the light comes ON for 300 seconds. If I go back into the room, the timer is canceled and destroyed and the lamp stays ON indefinitely. If I go back a third time, the timer is recreated and the light will turn OFF after 300 seconds unless I spend a fourth time, …

Mine is supposed to switch on the light for 300 sec, if another movement is detected, the timer must be resumed for a new period of 300 sec without shut OFF the light.

In summary, the light must stay ON for 300 seconds after the last motion detection.

But in my rules, after canceling the timer, I may have to put the timer to null. that may be where part of my problem lies.

For the other part of the problem, manually turning off the light before the end of the timer.
In the same file, I could write this:

rule "Manual Light OF Salon"
when
    Item FF_FamilyRoom_Power change to OFF
then
    // Timer Salon Cancel and Destroy
    if (FF_FamilyRoom_Timer !== null) { 
        FF_FamilyRoom_Timer.cancel()
        FF_FamilyRoom_Timer = null
    }
end

What do you think about this solution ?

rule "Xiaomi Motion Sensor Salon"
when
    Item FF_FamilyRoom_MotionSensor_MotionStatus changed
then
    // FF_FamilyRoom_MotionSensor
    logInfo("Xiaomi","Motion Detected In Salon")
    if ( Daylight_Switch.state == OFF )
    {
        if(FF_FamilyRoom_Timer === null) { 
            FF_FamilyRoom_Power_PreviousState = FF_FamilyRoom_Power.state.toString()
            FF_FamilyRoom_Power.sendCommand("ON")
            FF_FamilyRoom_Timer = createTimer(now.plusSeconds(300), [ | 
                logInfo("Xiaomi","Auto OFF Salon")
                FF_FamilyRoom_Power.sendCommand(FF_FamilyRoom_Power_PreviousState)
                FF_FamilyRoom_Timer = null
            ])
        } else {
            FF_FamilyRoom_Timer.reschedule(now.plusSeconds(300))
        }
    }
end
1 Like

Many thanks Vincent,

Your solution work fine, I did not know this function .reschedule but for the Xiaomi Motion Detector I’ve changed the trigger

From (Switch)

Item FF_FamilyRoom_MotionSensor_MotionStatus changed

To (String with a DateTime value)

Item FF_FamilyRoom_MotionSensor_LastMotion received update

Because the LastMotion change also when the switch stay in the same state.

And to manualy OFF, I use this rules in the same file.

rule "Manual Light OFF Salon"
when
	Item FF_FamilyRoom_Power changed to OFF
then
	logInfo("Xiaomi","Manual OFF Salon")
	// Timer Salon Cancel and Destroy
	if (FF_FamilyRoom_Timer !== null) { 
		FF_FamilyRoom_Timer.cancel()
		FF_FamilyRoom_Timer = null
	}
end
1 Like