iPhone Presence Detection with hping3 and ARP

Hi Vasily,

I added the cron-script above. You can customize with your IP addresses and openhab switch and add it to your cron jobs to be executed every x minutes or so.
When starting with a plain Raspberian installation, you need to install hping3 (sudo apt-get install hping3), see also at the top of this thread

br Peter

Sorry for the belated reply. Once I marshal sufficient experience, I will give your suggestion a try-out. I am a very elementary learner right now. Regards.

Hi, I was wondering if instead of using a hping3 script to wake the iPhone if we could use the tcp/udp binding ? I’m not on linux and hping3 is hard to install on Mac… also I prefer to have all my thing running in openhab with no external script

I am planning to create a solution that

  • uses the Exec 2 binding
  • calls a bash shell script for the arp command
  • doesn’t require sudo
  • allows for 2 command line parameters IP and MAC to be able to call it for 3 different phones (3 items bound to 3 exec things)
  • get the least number of required hpings to conserve battery
  • get the smallest interval between calls (19 calls at 10 second interval?). Target is < 5 minutes.
1 Like

Sound great ! keep me posted !

I have improved my iPhone detection, based on the above information. The solution allows detection of multiple phones. You can integrate this in your current presence solution.

Required steps:

  1. Install hping3
  2. Allow use of sudo commands
  3. Create script
  4. Create items and rules

Install hping3

sudo apt-get install hping3

Allow use of sudo commands

Instead of adding directly to the sudoers file, I decided to add an inlude file /etc/sudoers.d/openhab, that is automatically picked up by the system.

sudo visudo -f /etc/sudoers.d/openhab

Paste this text in the file:

/etc/sudoers.d/openhab

openhab ALL=(ALL) NOPASSWD: /sbin/ip
openhab ALL=(ALL) NOPASSWD: /usr/sbin/hping3

If you use openHABian or a regular pi, and like to use the script from the commandline, you can duplicate these lines and replace openhab with openhabian or pi respectively.

Create script

The script iphone.sh will hping3 the iphone to wake it from deep sleep. It is required to be pinged more than once. Instead of retrying through a rule as posted above, I decided to loop in the script itself. The script is called by a “Time cron” rule in openHAB at an interval depending on your needs. Mine is 5 minutes. I have tried 1 minute. This works, but will have more impact on your phone’s battery life. The script will try 20 times (this is configurable in the script) to ping the device. If it still fails, the device is considered ‘away’.

The script can best be located in the OH scripts folder. For an apt-get based installation, including openHABian, this is /etc/openhab2/scripts.

cd /etc/openhab2/scripts
touch iphone.sh
chmod +x iphone.sh
nano iphone.sh

/etc/openhab2/scripts/iphone.sh

#!/bin/bash

# detect iphone by IP and MAC address.
# use MAC address too, to prevent false positives if IP might change
# return ON or OFF so output can be directly bound to a switch item

# number of retries, less is faster, but less accurate
MAXRETRIES=20

# exit immediately if no parameters supplied
if [ $# -lt 2 ]
  then
    echo "UNDEF"
    exit 1
fi

# Set variables
IP=$1
MAC=$2

COUNT=0
while [ ${COUNT} -lt ${MAXRETRIES} ];
do

  # Change dev and eth0 if needed
  sudo ip neigh flush dev eth0 ${IP}

  sudo hping3 -q -2 -c 10 -p 5353 -i u1 ${IP} >/dev/null 2>&1
  sleep .1

  # Only arp specific device, grep for a mac-address
  STATUS=`arp -an ${IP} | awk '{print $4}' | grep "${MAC}"`

  if [ ${#STATUS} -eq 17 ]; then
      # exit when phone is detected
      echo "ON"
      exit 0
  fi
  let COUNT=COUNT+1
  sleep .1
done

# consider away if reached max retries 
echo "OFF"

Create items and rules

iphone.items

Switch Phone1 "iPhone 1 [%s]" <present>
Switch Phone2 "iPhone 2 [%s]" <present>
Switch Phone3 "iPhone 3 [%s]" <present>

iphone.rules

rule "Find My iPhone"
when
    Time cron "0 */5 * * * ? *" // every 5 minutes
then
    val Number timeout = 10*1000 // give the script some time to finish, to capture the result

    // replace 0.0.0.0 with your ip address
    // replace 00:00:00:00:00:00 with your mac address
    var String result1 = executeCommandLine('/etc/openhab2/scripts/iphone.sh@@0.0.0.0@@00:00:00:00:00:00', timeout)
    var String result2 = executeCommandLine('/etc/openhab2/scripts/iphone.sh@@0.0.0.0@@00:00:00:00:00:00', timeout)
    var String result3 = executeCommandLine('/etc/openhab2/scripts/iphone.sh@@0.0.0.0@@00:00:00:00:00:00', timeout)

    Phone1.postUpdate(result1)
    Phone2.postUpdate(result2)
    Phone3.postUpdate(result3)

end

TODO:

  • DRY: use lambdas for reusing code per phone.
  • get Exec2 binding working to replace current cron based rule
  • optimize detection timing
  • (perhaps) use REST api to sets items directly (with $3 for item)
3 Likes

I’m on Mac son I can’t install hping3… I mean there is some way but I don’t think it’s gonna work or I will need to remake all the script to make it compatible so …I need another way

Have you tried brew?


http://brewformulas.org/Hping

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install hping

No I tought it was diferent so the script will not work … I’m gonna try it

it’s not working

I got this :

line 8: ip: command not found
usage: arp [-n] [-i interface] hostname
arp [-n] [-i interface] [-l] -a
arp -d hostname [pub] [ifscope interface]
arp -d [-i interface] -a
arp -s hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]
arp -S hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]
arp -f filename
Phone 192.168.111.15 is not present

Great one Robert!

Maybe @Maurits28 could reference your solution in the first posting so others can realistically find it… @Maurits28 you could also transform your first posting into a wiki posting so Robert can edit it himself. But that’s of course totally up to you!

If you are really persistent, Google should be your friend, or someone with Mac Terminal skills.

I googled for ‘mac ip command’ and found this:

You might give it a try. It suggests to ‘brew’ iproute2mac or use the ifconfig command.

And you can flush the arp table, too:

https://scottlinux.com/2011/08/03/clear-or-flush-arp-cache-in-os-x/#comment-892

@rtvb It it strange that I am able to detect my phone if I run the script from my console but if the script is executed by the rule, my phone is not found in my network.
Is there a difference if openhab is running ths script_

Have you tried a variation of the script, that logs its output to a file and see what happens? See my modified example script down here. Make sure user openhab has write access to the log file.

#!/bin/bash

# v1.1 2017-04-11: VARIATION WITH LOGGING INCLUDED

# detect iphone by IP and MAC address.
# use MAC address too, to prevent false positives if IP might change
# return ON or OFF so output can be directly bound to a switch item

# number of retries, less is faster, but less accurate
MAXRETRIES=20

# path to log file - to use logging, uncomment all lines containing 'echo >> logfile'
LOGFILE=/etc/openhab2/scripts/iphone.log

# exit immediately if no parameters supplied
if [ $# -lt 2 ]
  then
    # echo `date '+%F %T'` - Required parameters not specified >> ${LOGFILE}
    echo "UNDEF"
    exit 1
fi

# Set variables
IP=$1
MAC=$2

# echo `date '+%F %T'` - Script started for ${IP} and ${MAC} >> ${LOGFILE}

COUNT=0
while [ ${COUNT} -lt ${MAXRETRIES} ];
do

  # echo `date '+%F %T'` - Try ${COUNT} >> ${LOGFILE}

  # Change dev and eth0 if needed
  sudo ip neigh flush dev eth0 ${IP}

  sudo hping3 -q -2 -c 10 -p 5353 -i u1 ${IP} >/dev/null 2>&1
  sleep .1

  # Only arp specific device, grep for a mac-address
  STATUS=`arp -an ${IP} | awk '{print $4}' | grep "${MAC}"`

  if [ ${#STATUS} -eq 17 ]; then
      # exit when phone is detected

      # echo `date '+%F %T'` - Phone detected >> ${LOGFILE}

      echo "ON"
      exit 0
  fi
  let COUNT=COUNT+1
  sleep .1
done

# consider away if reached max retries 
# echo `date '+%F %T'` - Phone not detected >> ${LOGFILE}
echo "OFF"

Thank you for help. I am not sure but I assume that the script is not running up to the last line of code if it is not finding a phone. The log contains just the last ‘Try’ entry but it is never achieving the command ‘echo off’.
Also the script is not running correct. It results in ‘Phone detected’ although I am not connected to the network. Otherwise If I run the script from the command line the detection is correct.

2017-04-12 22:10:00 - Try 0
2017-04-12 22:10:00 - Try 1
2017-04-12 22:10:01 - Try 2
2017-04-12 22:10:01 - Try 3
2017-04-12 22:10:02 - Try 4
2017-04-12 22:10:02 - Try 5
2017-04-12 22:10:03 - Try 6
2017-04-12 22:10:03 - Phone detected
2017-04-12 22:10:03 - Try 0
2017-04-12 22:10:04 - Try 1
2017-04-12 22:10:04 - Try 2
2017-04-12 22:10:05 - Try 3
2017-04-12 22:10:05 - Try 4
2017-04-12 22:10:06 - Try 5
2017-04-12 22:10:06 - Try 6
2017-04-12 22:10:07 - Try 7
2017-04-12 22:10:07 - Try 8
2017-04-12 22:10:08 - Try 9
2017-04-12 22:10:08 - Try 10
2017-04-12 22:10:09 - Try 11
2017-04-12 22:10:09 - Try 12
2017-04-12 22:10:10 - Try 13
2017-04-12 22:10:10 - Try 14
2017-04-12 22:10:11 - Try 15
2017-04-12 22:10:12 - Try 16
2017-04-12 22:10:12 - Try 17
2017-04-12 22:10:13 - Try 18
2017-04-12 22:10:13 - Try 19
2017-04-12 22:11:00 - Try 0
2017-04-12 22:11:00 - Try 1
2017-04-12 22:11:00 - Phone detected
2017-04-12 22:11:01 - Try 0
2017-04-12 22:11:01 - Try 1
2017-04-12 22:11:02 - Try 2
2017-04-12 22:11:02 - Try 3
2017-04-12 22:11:03 - Try 4
2017-04-12 22:11:03 - Try 5
2017-04-12 22:11:04 - Try 6
2017-04-12 22:11:04 - Try 7
2017-04-12 22:11:05 - Try 8
2017-04-12 22:11:05 - Try 9
2017-04-12 22:11:06 - Try 10
2017-04-12 22:11:06 - Try 11
2017-04-12 22:11:07 - Try 12
2017-04-12 22:11:07 - Try 13
2017-04-12 22:11:08 - Try 14
2017-04-12 22:11:08 - Try 15
2017-04-12 22:11:09 - Try 16
2017-04-12 22:11:09 - Try 17
2017-04-12 22:11:10 - Try 18
2017-04-12 22:11:10 - Try 19
2017-04-12 22:12:00 - Try 0
2017-04-12 22:12:00 - Try 1
2017-04-12 22:12:01 - Try 2
2017-04-12 22:12:01 - Phone detected
2017-04-12 22:12:01 - Try 0
2017-04-12 22:12:02 - Try 1
2017-04-12 22:12:02 - Try 2
2017-04-12 22:12:03 - Try 3
2017-04-12 22:12:03 - Try 4
2017-04-12 22:12:04 - Try 5
2017-04-12 22:12:04 - Try 6
2017-04-12 22:12:05 - Try 7
2017-04-12 22:12:05 - Try 8
2017-04-12 22:12:06 - Try 9
2017-04-12 22:12:06 - Try 10
2017-04-12 22:12:07 - Try 11
2017-04-12 22:12:07 - Try 12
2017-04-12 22:12:08 - Try 13
2017-04-12 22:12:08 - Try 14
2017-04-12 22:12:09 - Try 15
2017-04-12 22:12:09 - Try 16
2017-04-12 22:12:10 - Try 17
2017-04-12 22:12:10 - Try 18
2017-04-12 22:12:11 - Try 19

I have noticed some glitches in my own use of the modified script, too. I will have a look at it the coming days.

What I experienced during tests with the original script is that if you do the pings too close after each other, the results are often not reliable. Therefore I use an interval of one minute between the tests. It might help to test with one minute or 30 secs to get a reliable reading.

Little question :

It work really well with my girlfriend iPhone I have 0 issue ! But with mine … My iPhone goes offline really often … I try to set up a rules that said wait 20 min before declare my iPhone as gone but it does not fix it …

Could it be something like my iPhone 7 have more protection from ping when he sleep ? Or a physical issue with my iPhone ?

Does anyone have an iPhone 7 and make this work well ?

Hey all,

I have extended the network binding to be able to use arping. Additionally I send an empty packet to udp port 5353, as suggested here in this thread. I do not own an iPhone though, so cannot test if it actually works. The device presence detection for my android 6 phone works now, thanks to arping.

I need to know which parameters need to be configurable as apparently different parameters worked for different phones. At the moment it works like this:

Repeat the following every REFRESH_TIME in ms (default 60000):

  • Increase attempt by one
  • Send one empty packet to port 5353
  • Wait 50ms
  • Perform some arp pings with ARPING, but don’t wait longer than TIMEOUT in total

A device is deemed offline if attempt >= MAX_ATTEMPTS.

All uppercase parameters are configurable.

Is there a reason why the preferred solution here is to flush the arp table + use arp later instead of using the arping tool?

The pull request:

Cheers, David

4 Likes

Hi David,

Is there still a jar file which I can use to Test the arp ping feature of the network binding?

Have a nice weekend!