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
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.
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
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?
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
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