How can I have my Raspberry Pi continually scan for a MAC address on my network then perform a task when it detects a specific MAC address?

I use my Pi to run various home automation tasks. I'd like it to perform a task when it senses that my phone connects to the Wi-Fi, (meaning I just got home). What is the best way to have the Pi scan for my phone's MAC Address continually? I know I can use arp-scan to scan for MAC Addresses, but I need this to be continually scanning. I'm sure there's a better method then having arp-scan run in a loop, or using cron to have it run every minute.

  • 2
    If you don´t need realtime response cron is the best way. First you write script which return something like true or false in sh (status code is he best option to privide response) then script which will store previous value somewhere to /tmp and check for change. If change happend it will log it.
    – Misaz
    May 30, 2017 at 19:36

2 Answers 2



My phone acts differently, as all phones has some difference. A ping response only happens if the phone is awake. If the Pi is rebooted and the phone is in sleep mode, multiple pings will place its ip and mac addresses in the arp table, with 100% packet loss. I just learned that the arp command is obsolete, ip neighbor is used now.

pi@RPi0:~ $ ip neighbor dev eth0 lladdr 64:31:00:00:00:00 REACHABLE dev wlan0 lladdr ac:b3:00:00:00:00 STALE
fe80::aeb3:13ff:fe00:000 dev wlan0 lladdr ac:b3:00:00:00:00 router STALE

pi@RPi0:~ $ ping
PING ( 56(84) bytes of data.
From icmp_seq=1 Destination Host Unreachable
From icmp_seq=2 Destination Host Unreachable
From icmp_seq=3 Destination Host Unreachable
--- ping statistics ---
34 packets transmitted, 0 received, +3 errors, 100% packet loss, time 34303ms

pi@RPi0:~ $ ip neighbor dev wlan0 lladdr ac:b3:00:00:00:00 REACHABLE dev eth0 lladdr 64:31:00:00:00:00 REACHABLE dev wlan0 lladdr ac:37:00:00:00:00 REACHABLE
fe80::aeb3:13ff:fe00:000 dev wlan0 lladdr ac:b3:00:00:00:00 router STALE

After testing, my solution would be to have two loops inside of a forever loop. the first inside loop would be to do a ping on a range of ip addresses, multiple times, that would be possible for my phone. My router has reserved the first 19 ip address and I may have about a half dozen address that DHCP will assign, including my phone, starting at address I will ping a dozen ip address once, in background mode, wait one second for response, and throw the results away as junk. I will wait eight seconds on the arp table, and run the ip neighbor command, grep the mac address for the ip address. The router and phone will keep this same ip address unless something unusual happens. The arp table will remain in the Pi, but will change states from REACHABLE, STALE, and FAILED from pings and time.

The second inside loop will ping and check the arp table every five minutes to determine if the phone is at home. With three ping 'FAILED' in a row, the phone is not at home. One 'REACHABLE', when phone is not at home, will make the phone return home (do something). There are checks to validate the ip address and return to the first inside loop if corrections are required.

# A script to do something when Phone returns Home.

mac="ac:37:00:00:00:00"    # Your phone mac address
ip_addr=""                 # Leave blank or ip for test
network=""      # Your network (Class C only)
range="20 32"              # ip address possible range
pgm='echo "do something"'  # program to exec when Phone returns Home

start=$(echo "$range" | cut -d " " -f1)
stop=$(echo "$range" | cut -d " " -f2)
network=$(echo "$network" | cut -d. -f1-3)

echo "Start  $(date)"
while [ 1 ]; do
    [ "$ip_addr" ] || while [ ! "$ip_addr" ]; do
        for x in $(seq "$start" "$stop"); do
            (junk=$(ping -c1 -W1 "$network"."$x") & )
        sleep 8
        ip_addr=$(ip neighbor | grep "$mac" | cut -d " " -f1)
        if (( $cnt > 15 )); then
            echo "--- Phone not Home  $(date)"
            sleep 300      # 5 minutes
        if [ "$ip_addr" ]; then
            echo "--- Phone is Home, Count = $cnt, Date = $(date)"
            echo "Phone ip = $ip_addr  mac = $mac"

    while [ "$ip_addr" ]; do
        junk="$(ping -c1 -W1 $ip_addr)"
        sleep 8
        home_nw="$(ip neighbor | grep $ip_addr | cut -d ' ' -f 1,5,6)"
        echo "$home_nw - $(date)"
        is_home=$(echo "$home_nw" | cut -d " " -f3)
        if [ "$is_home" == "REACHABLE" ] && (( "$fail" >= 3 )); then
            echo "--- Phone returned Home - $(date)"
        [ "$is_home" == "REACHABLE" ] && fail=0
        mac_stat=$(echo "$home_nw" | cut -d " " -f2)
        if [ "$mac_stat" == "FAILED" ]; then
            (( "$fail" < 10 )) && ((fail++))
            ip_test="$(ip neighbor | grep $mac | cut -d ' ' -f1)"
            if [ "$ip_test" ]; then
                [ "$ip_test" == "$ip_addr" ] || ip_addr=""
            if (( "$fail" == 3 )); then
                echo "--- Phone not at Home  $(date)"
            if [ "$mac_stat" != "$mac" ]; then
        sleep 300          # 5 minutes

Why not add a reservation to your phone/s ip address and simply do a ping via a cron job every few minutes.

    HOSTS="x.x.x.1 x.x.x.2"
    for myHost in $HOSTS
      count=$(ping -c $COUNT $myHost | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }')
      if [ $count -eq 10 ]; then
        # 100% response
        # let the cat out

I accomplish this on my rpi using fhem, it has a built in presence detection module that lets me set resident statuses that can be queried to influence home automation tasks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.