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:
- Install hping3
- Allow use of sudo commands
- Create script
- 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)