iPhone Presence Detection with hping3 and ARP

This tutorial describes how to detect the presence of an iPhone if it is connected to your home’s wifi network.

It is a summary of several posts on this forum, started by the script posted by @kemotsysinc (main thread) and great additions from @Seaside later in this thread. Thanks for that!

  • Used Hardware: iPhone 6 and Raspberry Pi 2
  • Used Software: Rasbian with openHABian 2.0.0 and hping3
  • Necessary binding: Exec binding

To enable iPhone detection follow these steps:

Hping

To wake up the iPhone before checking with arp it’s presence, we use hping3 which pings via UDP to your iPhone:

sudo apt-get install hping3

More information on hping: http://www.hping.org/.

Script

Create a file IphoneD.sh with your favorite editor in the /opt directory.

sudo nano /opt/IphoneD.sh

with the following code:


#!/bin/bash

 #Enter your ip of your device here
DEVICES="10.1.1.20"

for i in `echo $DEVICES`; do
    # Change dev and eth0 if needed
    ip neigh flush dev eth0 $i
    hping3 -2 -c 10 -p 5353 -i u1 $i -q >/dev/null 2>&1
    sleep 1
    # Only arp specific device, grep for a mac-address
    status=`arp -an $i | awk '{print $4}' | grep "..:..:..:..:..:.."`
    statusMessage="OFF"
    #A mac will be 17 characters including the ":"
    if [ ${#status} -eq 17 ]; then
        echo "Phone $i is detected!"
        statusMessage="ON"
    else
        echo "Phone $i is not present"
        statusMessage="OFF"
    fi
done

Make sure you fill in your own local IP address of your iPhone (replace 10.1.1.20). Save and close the file. Btw thanks @rlkoshak for the sleep 1 suggestion.

Note that this script is adjusted from a multiple- to a single device script from @Seaside which you can find in post 3 of this thread, however to communicate status of multiple devices, mqtt messaging was added there.

Now continue to change the permissions of the script-file:

sudo chown openhab IphoneD.sh
sudo chmod 777 IphoneD.sh

Check if the script is executable with:

ls -all

Edit sudoers file, this enables the user openhab to run sudo commands without password. Enabling user openhab to run sudo commands can potentially be dangerous, do this at your own risk.

sudo visudo

Make sure the last line looks like this (if your user for openHAB is openhab)

openhab ALL=(ALL) NOPASSWD: /bin/ip, /bin/bash

openHAB

Now we go to openHAB. We make a rule that is triggered by a cron job to check from time to time presence (every minute in this example). For details on cron triggers, see this link. And we add a rule to make sure we don’t detect ‘false non-presence’ if the Iphone does not react. Empirical evidence :smile: suggests every 19 minutes at least the Iphone answers once the request.

var Number IphoneCounter = 0
val Number MaxCounter = 18

rule "Execute script IphonePresence"
when
    Time cron "0 * * * * ?"
then
    var String IphoneExec = executeCommandLine("sudo@@bash@@/opt/IphoneD.sh", 5000)
    Iphone.postUpdate(IphoneExec)
end

rule "Determine presence Iphone"
when 
	Item Iphone received update
then {
	if(Iphone.state == "OFF") {
		IphoneCounter = IphoneCounter + 1
		if(IphoneCounter > MaxCounter) {
			Iphone_Sw.sendCommand(OFF)
			IphoneCounter = 0	
			logInfo("RULE","Iphone  counter reached threshold and sent command OFF. Counter set to 0")
		}
		else {
			logInfo("RULE","Counter Iphone threshold not yet reached. Counter set to " + IphoneCounter)
		}
	}
	else {
		Iphone_Sw.sendCommand(ON)	
		IphoneCounter = 0
		logInfo("RULE","Iphone_Sw received command ON. Counter reset to 0")
	}
	}
end

Add these to your .items file:

String Iphone  	"John Doe"
Switch Iphone_Sw "John Doe @ Home?"

Your sitemap now shows the presence of the Iphone. Sitemap:

Switch item=Iphone_Sw mappings=[OFF="Away", ON="Home"]
7 Likes

This is a tricky problem I had before. Might even be the one @rlkoshak and I were talking about the other day: One of your code fences had trailing whitespaces, which seems to bring Discourse out of balance. Example with whitespaces as °:

```°°°°
some code
```

Hi!

Thanks for the script @Maurits28 . This helped me out a lot and improved my presence, I’m using a modified version, posting data using MQTT. Basically I have followed @rlkoshak presence guide: Fine tuning of wifi presence detection

Thought I would share it in case someone is looking to modify in a similar manner

Some differences

  • Loop to be able to do presence for multiple devices, I run this on a standalone Linux Server
  • I only flush the arp table for the device I’m looking for (not all, since my server have a lot of arp entries)
  • I look the MAC-address up, you only need to know the IP, which could be good and bad, this solution might not be as robust
  • I only arp the specified device, probably not an issue to do arp -an for all.
  • Relaying on mosquitto_pub to publish messages, which is a bit hard coded.
#!/bin/bash

 #Enter your ip of the devices here, separator space
DEVICES="10.1.1.20 10.1.1.21"
MQTT_SERVER="some ip"

for i in `echo $DEVICES`; do
    # Change dev and eth1 if needed
    ip neigh flush dev eth1 $i
    hping3 -2 -c 10 -p 5353 -i u1 $i -q >/dev/null 2>&1
    sleep 1
    # Only arp specific device, grep for a mac-address
    status=`arp -an $i | awk '{print $4}' | grep "..:..:..:..:..:.."`
    statusMessage="OFF"
    #A mac will be 17 characters including the ":"
    if [ ${#status} -eq 17 ]; then
        echo "Phone $i is detected!"
        statusMessage="ON"
    else
        echo "Phone $i is not present"
        statusMessage="OFF"
    fi
    if [ $i == "10.1.1.20" ]; then
        mosquitto_pub -h $MQTT_SERVER -m $statusMessage -t presence_sensors/network/person1 -q 1
	echo "Pub: $statusMessage -t presence_sensors/network/person1 -q 1"
    fi
    if [ $i == "10.1.1.21" ]; then
	mosquitto_pub -h $MQTT_SERVER -m $statusMessage -t presence_sensors/network/person2 -q 1
	echo "Pub: $statusMessage -t presence_sensors/network/person2 -q 1"
    fi  
done
3 Likes

hping3 doesn’t appear to be waking up my wife’s iphone 5s, the arp tables shows an incomplete mac address 90% of the time:

root@openhab:/opt/openhab# hping3 -2 -c 10 -p 5353 -i u1 192.168.2.19 -q
HPING 192.168.2.19 (wlan0 192.168.2.19): udp mode set, 28 headers + 0 data bytes

--- 192.168.2.19 hping statistic ---
10 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms



root@openhab:/opt/openhab# arp -an
? (192.168.2.19) at <incomplete> on wlan0

Any ideas?

I have problems a iPhone 6 is put to deep sleep, Currently I have a timer set to 19 mins delay before it is marked as not present. With the 19 mins delay it is working.

My detection with iPhone 6 is not flawless yet either, I also will include a delay to make the feedback more robust. I have been doing quite some research, but did not find yet the solution to solve this satisfactorily.

Edit: since this post the initial post has been updated and the presence detection works well now.

For whatever it is worth, we have a iphone7 and one of the latest nexus android phones and both show drop-outs with this method that I cannot reproduce yet. I have to use this script with the Nexus android phone and iphone7 (both phone are fully updated) as the network binding does not work for my android phone (seems to have same no-reponse-to-ping issue, when sleeping). I’ve played around with some parameters, but to make the iphone respond reliably takes much longer and more frequent hping3’s than in the current script…tried it only manually as not to ruin battery life…but frequent hping3 pings for about a 1min or 2 seem to be necessary at times. Android seems to be less reliable. At times the presence works rock-solid for both phones at times it does not work at all…mmmhhh

I have a One Plus 3 Android Phone (Android 6.0.1), for that one I need a timeout of 10 mins, compared to the 19 with the iPhone 6.
I have a SetPoint in my sitemap for the timeout, so can easily adjust the timers.
Usually I notice timeouts during the night, but for the last couple of days it has been stable using those settings.

@Seaside Your script is great and seems to work flawlessly for users. However, not everyone uses MQTT or should be forced to install a broker. Would you alternatively add a way to communicate with the openHAB REST API? Integration via stdout might also be possible. Unsure how to best handle the multiple devices feature that way. I’d probably move the loop to openHAB but I get that your goal was different.

Would be great to finally have ONE solution for all users :sparkles:

@Maurits28 maybe you could update the first posting with this solution. Setting of the privileges should be less insecure by following this recommendation.

1 Like

@Maurits28 Thank you for your example of presence detection for the iPhone.
I tried your solution, and i run into, i think, a permission error:

[12:06:20] pi@openHABianPi:/opt$ ./IphoneD.sh
Failed to send flush request: Operation not permitted
Away

It relates to the command in your script:

ip neigh flush all

Besides this, i got the feeling that the changing of Permissions in your description might be wrong?

Now you need to change the permissions:

sudo chown 777 IphoneD.sh

I do not know of a user-name 777, so i changed that command to:

sudo chown openhab IphoneD.sh
sudo chmod +x IphoneD.sh

Further, with sudo visudo, i gave both my users (pi and openhab) the rights to execute the commands ip and hping3:

openhab ALL=NOPASSWD: /sbin/ip
pi ALL=NOPASSWD: /sbin/ip
openhab ALL=NOPASSWD: /usr/sbin/hping3
pi ALL=NOPASSWD: /usr/sbin/hping3

I am able to perform the command ip neigh from the command prompt, but when i add the flush all argument i receive the error message.

[12:22:47] pi@openHABianPi:/opt$ ip neigh
192.168.178.40 dev eth0  FAILED
192.168.178.22 dev eth0 lladdr 00:27:02:10:7b:74 STALE
192.168.178.130 dev eth0  FAILED
(lines left out)
fe80::5e49:79ff:fe51:781c dev eth0 lladdr 5c:49:79:51:78:1c router STALE
fe80::ca60:ff:fe1b:fb46 dev eth0  FAILED
2001:982:2a43:1:4819:72f3:34e6:1afb dev eth0  FAILED
[12:24:12] pi@openHABianPi:/opt$ ip neigh flush all
Failed to send flush request: Operation not permitted
[12:24:20] pi@openHABianPi:/opt$

Btw, my setup is running on an RPi2.
Any idea what is wrong with my setup?

Hi @deltabert ,

Thanks for your comments, I recently upgraded to openHABian 2.0.0 and just put presence detection back in business again :sweat_smile:

Good point, I changed / added both your suggestions in the initial post.

I have /bin/ip and /bin/bash in the sudo visudo file for user openhab.

Try executing the script (or ip neigh flush dev eth0 xxx.xxx.xxx.xxx for testing) with sudo:
sudo bash /opt/IphoneD.sh.

I’m not an expert on this, but is your network device linked to eth0? You can get more info with sudo ifconfig. Did you change the ip address in the IphoneD.sh script to the ip address of your Iphone? You can also try to use the updated solution that you can find at the top of the page.

Let me know how you progress with it.

@Seaside, @ThomDietrich On another note, I updated the initial solution at the top of the page with the great work @Seaside has done, I just need to add the timeout rule of 19 minutes.

1 Like

I have a problem with the hping3 command. This is not working (iPhone 5S).
At first i thought it is the hping3 program itself, but that is working OK in my network:

[11:37:01] pi@openHABianPi:~$ sudo hping3 -S 192.168.178.40 -c 2 -p 80
HPING 192.168.178.40 (eth0 192.168.178.40): S set, 40 headers + 0 data bytes
len=46 ip=192.168.178.40 ttl=64 id=59134 sport=80 flags=RA seq=0 win=0 rtt=638.2 ms
len=46 ip=192.168.178.40 ttl=64 id=11411 sport=80 flags=RA seq=1 win=0 rtt=17.9 ms

--- 192.168.178.40 hping statistic ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 17.9/328.0/638.2 ms

This is a command send to my iPhone, which is awake btw.
But sending the command from the tutorial to the iPhone (still awake) gives me this:

[11:39:58] pi@openHABianPi:~$ sudo hping3 -2 -c 10 -p 5353 -i u1 192.168.178.40 -q
HPING 192.168.178.40 (eth0 192.168.178.40): udp mode set, 28 headers + 0 data bytes

--- 192.168.178.40 hping statistic ---
10 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
[11:41:26] pi@openHABianPi:~$

Any ideas?
EDIT-1. I tried also with an Android phone (LG-OB) and even with my NAS, both gave the same results… So, it is not related to the iPhone 5S, which i read somewhere…

Hi Bert,

The feedback from hping is ok, it is only meant to wake up the Iphone, I get the same ‘100% packet loss’.

I just updated the initial post with the rule to allow for a time-out before setting presence status to ‘Away’. I tested it a few days and it seems to be working well.

Side note: I would be interested to hear from you which is according to your experience the time-out needed (currently at 19 tries).

@Maurits28: Thanks for your script. I’ve a comprehensive question: I like the approach of the maxcounter timeout. But when I understand the rule right, this means that after a “real” absence (so no false non-presence) it takes 19 minutes (as the script is only executed once a minute) until the presence switch is finally switched to OFF. So I have a quite big delay after leaving the house (in case I’m further using the on/off presence switch for other things (alarm activation etc.).

And another question:
I’ve just created the script and all necessary settings. Just for testing I did several starts of the script from the shell. I have defined two IPs, one is present at the moment (.37), the other one is abscent (.32). .32 is reported correctly every time, but .37 only gets one correct state in about 10 tries. Is this “normal behavior”?

[15:00:30] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:00:33] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:00:36] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:00:39] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:00:42] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:09:45] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:09:50] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:10:06] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is detected!
Phone 192.168.178.32 is not present
[15:10:10] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:10:14] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:10:18] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:10:22] pi@openHABianPi:/opt$ sudo ./IphoneD.sh
Phone 192.168.178.37 is not present
Phone 192.168.178.32 is not present
[15:10:35] pi@openHABianPi:/opt$

EDIT: I’ve done a little more research. Both iPhones (5s and SE) are only detected when they are in active use. But as soon as I lay them down and the screen goes off, the detection doesn’t work anymore (or everything but reliable).

Any thoughts? Does this mean that the hping3 isn’t working? hping3 is installed and I can run hping3 from bash.

Hi Stefan, your understanding is correct, and to prevent ‘false’ away detections a time-out of 19 is in use. The issue with the Iphone is that when it is in sleep mode, it is hard to wake it up. For that we use Hping3, to wake it up just before we detect it’s presence via arp. Even then it does not always wake up, hence the ‘time-out threshold’ of 19 tries.

I see that you tried once every few seconds, my experience with such an interval is also that it does not detect the iPhone lots of times. You might want to try an interval of 30 seconds instead of one minute, and see empirically how many times you’ll need to have a reliable presence detection. Post your results in this thread so we can learn from your experience! :slight_smile:

The ip neigh command requires dig which is not installed on an RPi by default. Use sudo apt-get update && sudo apt-get install dnsutils first.

Hello,

Thanks for the material. I am installing openHAB2 and found your script educational. My question to you is why don’t you use the arp command to obtain the IP address of Apple devices since the MAC addresses of the latter have a well known prefix. (ref: https://nmap.org/book/nmap-mac-prefixes.html.

Regards.

Hi Matha

It is an interesting thought, however for me personally the additional work needed to implement does not weigh against the advantages. And I see a few things that still would need ‘manual’ work:

  • Assigning of a specific Apple device to a specific person in your household
  • You do not want to track all Apple devices like AppleTV, iPad, MacBook as you are interested in the fact if somebody is in the house or not.

But hey, why don’t you give it a try and tell us how it works? There are always users that would benefit from your proposed solution.

Cheers!

Hi seaside,
I like your shared bash script, I turn to your script as it can check multi iPhone in single run,
after few days operate, I think it’s not necessary to flush arp in every run

ip neigh flush dev eth1 $i

, I use crontab to flush arp every 10 minutes and run your script every minute, in openhub items time out in 4 minutes, result is pretty accurate, may be 1 time false “away” per day, as my home only got 1 door to leave, so door must open when someone leave, than I set the offline rules turn TRUE if door also opened within 10 minutes which makes the detection 100% right in my home. you may also go for a try.

1 Like