Yes it’s normal (from a technical stand point) but there are of course ways around that. @MikeJMajor refered to the following solution I suppose. It’s reported to be quite reliable between many devices, including Androids and iPhones in doze/deepsleep mode:
Not convinced! … or beg to differ…
I run this set-up and it does not switch to ‘not present’, due to ARP retaining the IP.
… even (two) days later…
I’ve not done enough experiments to prove it, but I think hoping combined with Network binding might be a viable approach. I noticed when I was playing with it that periodically hpinging the iPhone made the Network Item linked to its ip work more reliably.
Also, if I remember correctly doesn’t the script first clear the arp table before doing the hping?
Very inspiring. Will try to imitate.
Thanks!
Based on this conversation, I decided to change my script to that from SeaSide, because it loops through multiple IPs. Tested this arvo, and it works; also, and yes, because of clearing the arp entry for the relevant IP. Nice.
Also adopted the MQTT publish approach, as this is what I will be using (Architecturally) whenever possible.
From a rights perspective I had to use sudo in front of the arp entry deletion, and add openhab to the sudoers without password.
No network binding used for this.
So basically, the shell script is triggered by a rule.
The script publishes to mosquitto topic;
OH subscribes to mosquitto topic
@Max_G
Glad it could help someone. I prefer to not invoke the polling to see if a device is available from within openhab, since
I run it every two minutes for several devices, IMO it’s better suited to be run outside openhab in a crond-job or similar.
You don’t have to give openhab permissions to all commands in the sudoers table you can add
username ALL=(ALL) NOPASSWD: /sbin/ip
to allow allow username to be able to execute ip (for flushing that is). I’m sure you are aware of this, but just writing it since it seems a lot of people allow openhab to execute just about anything.
Regards, S
Just because I’m curious: With the two iPhones in my house, as soon as I integrate the arp flush, the script doesn’t work reliable. Without this line, it’s pretty solid and only misses a beat from time to time.
When you guys say it works for you, do you also use iPhones or only Android?
@jaydee73
One iphone 6 and two android devices Oneplus 3 and Onplus one.
The oneplus 3 is also pretty good at sleeping, and turning wireless network off, so I need a timeout.
For iphone I have 19 mins and 11 mins for android.
I have basically followed @rlkoshak post about presence.
I have:
val String LOG_NAME = "PRESENCE"
var Timer mJPhoneIPTimer = null
rule "JPhoneIPChange"
when
Item JPhoneIPMqtt changed from ON to OFF
then
val int sleepTimerJ = (JPhoneIPSleepTimer.state as DecimalType).intValue
if (PresenceOverride.state != ON) {
logInfo(LOG_NAME, "J Phone is not home after setting timer to delay: " + sleepTimerJ)
try {
mJPhoneIPTimer = createTimer(now.plusMinutes(sleepTimerJ), [|
logInfo(LOG_NAME, "J Phone is not home after " + sleepTimerJ + " mins")
JPhoneIP.sendCommand(OFF)
NotifyPresence.postUpdate("J is not home on IP Phone time: " + sleepTimerJ)
mJPhoneIPTimer = null
])
} catch (Exception x) {
logInfo(LOG_NAME,"Could not set value for sleep timer")
}
}
end
items:
Number JPhoneIPSleepTimer "Oneplus 3 Sleep Timer [%d min]" <clock> (gRestore)
Switch JPhoneIPMqtt "OnePlus 3 Network Mqtt [%s]" <network> { mqtt="<[mosquitto:presence_sensors/network/j:state:default]" }
Switch JPhoneIP "OnePlus 3 Network [%s]" <network> (gJPresent, gPresent,gRestore)
S
Sitemap:
Setpoint item=JPhoneIPSleepTimer minValue=1 maxValue=60 step=1
I think the example in the wiki doesn’t take advantage of the powerful groups. I use:
Group:Switch:OR(ON, OFF) group_presence "Gruppe zur Anwesenheitserkennung"
Group:Switch:OR(ON, OFF) group_movement "Gruppe der Bewegungsmelder" (group_presence)
rule "Zyklische Anwesenheitserkennung"
when
Time cron "0 */5 * * * ?"
then
if (presence.state == ON) {
if (group_presence.state == OFF) {
if (!group_presence.changedSince(now.minusMinutes(5)) sendCommand(presence, OFF)
}
}
else {
if (group_presence.state == ON) sendCommand(presence, ON)
else if (presence.state == NULL) sendCommand(presence, OFF)
}
end
rule "Eventbasierte Anwesenheitserkennung"
when
Item group_presence changed from OFF to ON
then
if (presence.state != ON) sendCommand(presence, ON)
end
which is really easy to understand…
iPhones – actually forgot my Android… will test some day…
No I wasn’t Thank you for mentioning it.
In the end, you could use Present as the timer so long as ON keeps getting sent to it while you are present every <n minutes where n is the timer length.
I did just that. My presence detection is based on the Fritz!Box (router) TR065 binding. The binding updates presence items (MAC addresses of iPhones) once per minute. So there is my “every x minutes” trigger to keep the timers running.
The Fritz!Box presence detection is generally very reliable. However, there are two catches: Sometimes a MAC will be falsely reported as being absent for a short period of time. Especially at night, when the phones are on standby. I have learned from experience that this generally happens within a timeframe of less than five minutes. Secondly, the moment a MAC becomes (really) absent, it sometimes gets reported as being present again directly after the absence and then (finally) absent again within seconds. It then stays absent reliably.
The solution is what you proposed, and it is beautifully elegant. I cannot use the presence Items controlled by the binding directly for the reasons mentioned above. So they serve as the triggers for the “real” presence items I then use in other rules. The “real” presence items expire after 5 minutes if not updated. In other words, presence is detected immediately and absence is detected with a 5min delay. (Actually, just for completeness’ sake: Absence is detected with a 20mind delay because the Fritz!Box reports absence with a delay of 15min. This seems to be built into the firmware and cannot be helped.)
Note that I also use “arrival” items. I have defined a timeframe of 5min in which someone is in the state of arriving. E.g. the front door light would be switched on during that time (if it is dark, etc.). Those are just “sugar” items that are not really necessary. The advantage being that the arrival timeframe can be defined in the items definition file as well.
Items:
// Fritz!Box presence items
// iPhone A
Switch PresenceFritzA "A (Fritz) [MAP(presence.map):%d]" <present> {fritzboxtr064="maconline:xx-xx-xx-xx-xx-xx"}
// iPhone B
Switch PresenceFritzB "B (Fritz) [MAP(presence.map):%d]" <present> {fritzboxtr064="maconline:xx-xx-xx-xx-xx-xx"}
// if at least one person is present (ON), the group is present (ON), else absent (OFF)
Group:Switch:OR(ON, OFF) PresenceAnyone "Anyone [MAP(presence.map):%d]" <present>
// be present immediately but be absent after (not receiving presence update for) five minutes
Switch PresenceA "A [MAP(presence.map):%d]" <present> (PresenceAnyone) {expire="5m,command=OFF"}
Switch PresenceB "B [MAP(presence.map):%d]" <present> (PresenceAnyone) {expire="5m,command=OFF"}
// if at least one person is arriving (ON), anyone is arriving (ON) else not (OFF)
Group:Switch:OR(ON, OFF) ArrivalAnyone "Anyone [MAP(arrival.map):%d]"
// status "arriving" is kept for five minutes
Switch ArrivalA "A [MAP(arrival.map):%d]" (ArrivalAnyone) {expire="5m,command=OFF"}
Switch ArrivalB "B [MAP(arrival.map):%d]" (ArrivalAnyone) {expire="5m,command=OFF"}
// There is no XOR for groups so we need to use an Item and a rule
Switch ArrivalFirst "First [MAP(arrival.map):%d]" {expire="5m,command=OFF"}
Rules:
rule "A (Fritz) present or absent"
when
Item PresenceFritzA received update ON
then
PresenceA.sendCommand(ON);
end
rule "B (Fritz) present or absent"
when
Item PresenceFritzB received update ON
then
PresenceB.sendCommand(ON);
end
rule "A arriving"
when
Item PresenceA changed to ON
then
ArrivalA.sendCommand(ON)
end
rule "B arriving"
when
Item PresenceB changed to ON
then
ArrivalB.sendCommand(ON)
end
rule "First arrival"
when
Item PresenceAnyone changed to ON
then
ArrivalFirst.sendCommand(ON)
end
Thank you very much for that elegant solution. It helped me do away with tons of lines of cumbersome timer code as well.
This indeed looks a lot cleaner than the example. And as far as I can judge it has no disadvantage in the behaviour of the rule. Nice work!
I have a weird problem that the timer never expires. I have two sensors, an owntracks sensor and a phone IP
Group:Switch:AND(OFF,ON) gPresent <present> // all presence sensors belong to this group
Switch Present "Someone is Present" <present> // turns off 5 minutes after everyone leaves
Switch Present_Timer { expire="5m,command=OFF" }
Switch PhoneBT "Me @ Home" <bluetooth> (gPresent) { mqttitude="mosquitto:owntracks/me/phone/event:Home" }
Switch PhoneIP <network> (gPresent) {channel="network:device:d12435eb:online"}
The rules file looks like this
rule "System startup"
when
System started
then
Present.sendCommand(OFF) // assume no one is home on startup
PhoneBT.sendCommand(OFF) // assume phone BT is not reachable
end
rule "gPresent updated, at least one sensor changed state"
when
Item gPresent received update
then
logInfo("Debug", "------gPresent updated------")
gPresent.members.forEach [s | logInfo("Debug", s.name + " equals " + s.state.toString)]
logInfo("Debug", gPresent.name + " equals " + gPresent.state.toString)
logInfo("Debug", Present.name + " equals " + Present.state.toString)
// someone came home
if(gPresent.state == ON && Present.state != ON) {
Present_Timer.postUpdate(OFF) // cancel the timer if necessary
Present.sendCommand(ON)
logInfo("Debug", "Someone came home")
}
// no one is home
else if(gPresent.state == OFF && Present.state != OFF){
Present_Timer.sendCommand(ON) // start the timer
logInfo("Debug", "No one is home after five minutes")
}
end
rule "Present_Timer expired"
when
Item Present_Timer received command OFF
then
Present.sendCommand(OFF)
end
When both the sensors go off the logs show that the timer is switched on. However, the timer continues inifinitely. I dont understand why the group rule is getting update every few seconds, since the events dont show the update. The log file looks like so
2017-08-23 19:40:18.657 [INFO ] [eclipse.smarthome.model.script.Debug] - PhoneBT equals OFF
2017-08-23 19:40:18.657 [INFO ] [eclipse.smarthome.model.script.Debug] - PhoneIP equals OFF
2017-08-23 19:40:18.657 [INFO ] [eclipse.smarthome.model.script.Debug] - gPresent equals OFF
2017-08-23 19:40:18.658 [INFO ] [eclipse.smarthome.model.script.Debug] - Present equals ON
2017-08-23 19:40:18.659 [INFO ] [eclipse.smarthome.model.script.Debug] - No one is home after five minutes
2017-08-23 19:40:23.600 [INFO ] [eclipse.smarthome.model.script.Debug] - ------gPresent updated------
2017-08-23 19:40:23.600 [INFO ] [eclipse.smarthome.model.script.Debug] - PhoneBT equals OFF
2017-08-23 19:40:23.601 [INFO ] [eclipse.smarthome.model.script.Debug] - PhoneIP equals OFF
2017-08-23 19:40:23.601 [INFO ] [eclipse.smarthome.model.script.Debug] - gPresent equals OFF
2017-08-23 19:40:23.601 [INFO ] [eclipse.smarthome.model.script.Debug] - Present equals ON
2017-08-23 19:40:23.602 [INFO ] [eclipse.smarthome.model.script.Debug] - No one is home after five minutes
2017-08-23 19:40:38.694 [INFO ] [eclipse.smarthome.model.script.Debug] - ------gPresent updated------
2017-08-23 19:40:38.694 [INFO ] [eclipse.smarthome.model.script.Debug] - PhoneBT equals OFF
2017-08-23 19:40:38.695 [INFO ] [eclipse.smarthome.model.script.Debug] - PhoneIP equals OFF
2017-08-23 19:40:38.695 [INFO ] [eclipse.smarthome.model.script.Debug] - gPresent equals OFF
2017-08-23 19:40:38.695 [INFO ] [eclipse.smarthome.model.script.Debug] - Present equals ON
2017-08-23 19:40:38.696 [INFO ] [eclipse.smarthome.model.script.Debug] - No one is home after five minutes
.......
2017-08-23 19:49:59.298 [INFO ] [eclipse.smarthome.model.script.Debug] - ------gPresent updated------
2017-08-23 19:49:59.298 [INFO ] [eclipse.smarthome.model.script.Debug] - PhoneBT equals OFF
2017-08-23 19:49:59.299 [INFO ] [eclipse.smarthome.model.script.Debug] - PhoneIP equals OFF
2017-08-23 19:49:59.299 [INFO ] [eclipse.smarthome.model.script.Debug] - gPresent equals OFF
2017-08-23 19:49:59.299 [INFO ] [eclipse.smarthome.model.script.Debug] - Present equals ON
2017-08-23 19:49:59.300 [INFO ] [eclipse.smarthome.model.script.Debug] - No one is home after five minutes
The events logs shows that the timer is being called continuously,
2017-08-23 19:40:18.654 [ItemStateChangedEvent ] - PhoneBT changed from ON to OFF
2017-08-23 19:40:18.654 [GroupItemStateChangedEvent] - gPresent changed from ON to OFF through PhoneBT
2017-08-23 19:40:18.659 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:40:23.603 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:40:38.697 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:40:53.971 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:41:09.411 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:41:24.915 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:41:40.071 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:41:55.125 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:42:10.231 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:42:25.477 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:42:40.577 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:42:55.769 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:43:10.923 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
..........
2017-08-23 19:49:13.757 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:49:28.993 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:49:44.084 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
2017-08-23 19:49:59.301 [ItemCommandEvent ] - Item 'Present_Timer' received command ON
Why is the Present_Timer being called every few seconds and why it doesnt stop after 5 minutes?
Have you installed the expire binding?
Since the time keeps getting command ON faster than every five minutes the timer will never go off.
Try adding a check to see if the Timeer is already ON in your else if and only send the command if it is OFF.
It looks like your rule keeps getting repeated away updates so the timer never gets a chance to expire.
Ah, I dont have that installed!
Something like this?
// no one is home
else if(gPresent.state == OFF && Present.state != OFF){
if (Present_Timer.state == OFF) {
Present_Timer.sendCommand(ON) // start the timer
logInfo("Debug", "No one is home after five minutes")
}
That would work.
Never thought about using that one for presence detection!!
Is it possible to map 5m to an number item somehow?