Taming a flapping sensor

I use an ibeacon with owntracks running on an Android phone for presence detection. Unfortunately, ibeacon on Android is not very reliable. Consequently, when the phone is at rest, i get something like this in the log

2017-09-06 21:52:54.353 [ItemStateChangedEvent     ] - PhoneBT changed from ON to OFF
2017-09-06 21:52:54.864 [ItemStateChangedEvent     ] - PhoneBT changed from OFF to ON
2017-09-06 21:55:04.337 [ItemStateChangedEvent     ] - PhoneBT changed from ON to OFF
2017-09-06 21:55:07.473 [ItemStateChangedEvent     ] - PhoneBT changed from OFF to ON

The correct state should have been ON.

The item is defined as follows:

Switch  PhoneBT  "Me @Home <bluetooth>    (gPresent)   { mqttitude="mosquitto:owntracks/me/event:Home" }

Is there any way to reduce this flapping behaviour?

Thanks

You can but it doesn’t come for free.

Essentially what you will do is create a proxy for Phone by , let’s call it PhoneBT_Proxy. Then create a rule that only changes the proxy when PhoneBT remains in the same state for a certain amount of time. It looks like you can do something as short as 1 second so to do this your cost will be a one second delay between actual changes in states (for example, it will flip the proxy item one second after you actually come home and the phone is detected).

To do this create a rule triggered by changes in PhoneBT. If there is already a timer cancel it. Create a timer for one second. In the body of the timer update the proxy item to match the state of the sensor item.

This is called debouncing.

I recommend considering using Expire Based Timers as they are simpler to work with than Timers.

Thanks for the idea. I cam up with the following.

Items

Switch  PhoneBT  "Me @Home <bluetooth>    (gPresent)   { mqttitude="mosquitto:owntracks/me/event:Home" }
Switch sw_PhoneBT_proxy  <bluetooth> (gPresent)
Switch timer_PhoneBT { expire="1s,command=OFF" }

Rule

rule "PhoneBT changed"
when
        Item PhoneBT changed
then
        logInfo("PhoneBT","Setting Timer on PhoneBT state:"+ PhoneBT.state.toString)
        save_PhoneBTState=PhoneBT.state as OnOffType
        timer_PhoneBT.sendCommand(ON) //start the timer 
end


rule "timer_PhoneBT.state expired"
when
    Item timer_PhoneBT received command OFF
then
    logInfo("PhoneBT","After timer expired PhoneBT state:"+ PhoneBT.state.toString)
    if (PhoneBT.state!=save_PhoneBTState)
    {
        sw_PhoneBT_proxy.postUpdate(PhoneBT.state)
    }
end

The logs show

2017-09-08 20:04:02.531 [INFO ] [lipse.smarthome.model.script.PhoneBT] - Setting Timer on PhoneBT state:OFF
2017-09-08 20:04:02.821 [INFO ] [lipse.smarthome.model.script.PhoneBT] - Setting Timer on PhoneBT state:ON
2017-09-08 20:04:04.579 [INFO ] [lipse.smarthome.model.script.PhoneBT] - After timer expired PhoneBT state:ON

and events

2017-09-08 20:04:02.529 [ItemStateChangedEvent     ] - PhoneBT changed from ON to OFF
2017-09-08 20:04:02.533 [ItemStateChangedEvent     ] - timer_PhoneBT changed from OFF to ON
2017-09-08 20:04:02.534 [ItemCommandEvent          ] - Item 'timer_PhoneBT' received command ON
2017-09-08 20:04:02.812 [ItemStateChangedEvent     ] - PhoneBT changed from OFF to ON
2017-09-08 20:04:02.822 [ItemCommandEvent          ] - Item 'timer_PhoneBT' received command ON
2017-09-08 20:04:04.577 [ItemStateChangedEvent     ] - timer_PhoneBT changed from ON to OFF
2017-09-08 20:04:04.578 [ItemCommandEvent          ] - Item 'timer_PhoneBT' received command OFF

I was wondering if a reentrant lock is required or not. Probably not. What do you think?

There are not two things going on at the same time so a lock isn’t needed.

The timer is set to ‘ON’ twice one after another (as seen in the events log), hence i was wondering.

That is by design. The proxy only switches one second after the last event. If multiple events occur within a second they each rescheduled the timer.

There is a bug in the code. Here is what happens:

  1. System start, proxy=OFF
  2. Say BT changed to OFF, save_PhoneBTState=OFF, Timer set to ON
  3. Timer End, BT state is OFF, thus (PhoneBT.state==save_PhoneBTState), proxy remains as OFF
  4. Say BT changed to ON, save_PhoneBTState=ON, Timer set to ON
  5. Timer End, BT state is ON, thus (PhoneBT.state==save_PhoneBTState), proxy still remain OFF

Thus proxy is never turned ON.

The proxy gets set to what ever state the sensor item is when the timer expires.

I don’t completely follow your other names but the way it is to be written is:

  1. Sensor triggers rule with change
  2. Rule sets a timer
  3. Timer expires
  4. Timer rule (since we are using expire binding) sets the proxy to the same value as the sensor

That is all there is to it. I don’t know what save_PhoneBTState is or what it is supposed to do but it is not needed.

I need to save the initial state because there is no reentrant lock. Thus in the timer expire rule, the proxy needs to be set whatever the initial state was. The following works:

rule "timer_PhoneBT.state expired"
when
    Item timer_PhoneBT received command OFF
then
    logInfo("PhoneBT","After timer expired PhoneBT state:"+ PhoneBT.state.toString)
    if (PhoneBT.state!=save_PhoneBTState)
    {
        sw_PhoneBT_proxy.postUpdate(PhoneBT.state)
    }
    else
    {
        sw_PhoneBT_proxy.postUpdate(save_PhoneBTState)
    }
end

This statement makes no sense.

First if all your rule is only being triggered by changes to one item and there is no thread sleep in the rule so there will basically never be a case where to copied of this rule will run at the same time.

Secondly, all a ReentrantLock does is prevent two copies of the role form executing at the same time. No matter whether you use a lock it not save_PhoneBTState will ALWAYS match the state of PhoneBT the last time the rule fired which will always be there same state that PhoneBT will be in when the timer expires. Thus you don’t need save_PhoneBTState.

Finally, you don’t care what state PhoneBT is in when your first rule triggers that sets the timer. You only care what state it is in when the timer expires because that is the last state PhoneBT received and represents the true state of the sensor.

Even if the roles are running multiple copies at the same time, which it isn’t, using save_PhoneBTState would be a problem because you don’t know which order the changes were processed. save_PhoneBTState might be the penultimate state, not the most recent. But PhoneBT will always represent the most recent state.

As currently written it works because only one instance if the rule runs at a time naturally so save_PhoneBTState never gets set to the wrong state, but it certainly isn’t adding anything.

Thanks. Maybe i am complicating this too much based on scenarios i was considering. I will see how the following works out:

rule "PhoneBT changed"
when
        Item PhoneBT changed
then
        logInfo("PhoneBT","Setting Timer on PhoneBT state:"+ PhoneBT.state.toString)
        timer_PhoneBT.sendCommand(ON) //start the timer 
end


rule "timer_PhoneBT.state expired"
when
    Item timer_PhoneBT received command OFF
then
    logInfo("PhoneBT","After timer expired PhoneBT state:"+ PhoneBT.state.toString)
    sw_PhoneBT_proxy.postUpdate(PhoneBT.state)  
end

I am a strong advocate of not fixing things until you know it is a problem.

The above looks like it should work.

BTW, you can see how I handle this with multiple sensors here: