Check presence based on OpenWRT WiFi clients on-line

I made a simple php script to check the presence of Wifi clients (by MAC address) in my home LAN. I use OpenWRT based router and access point and the script checks both of them on all WiFi interfaces.
Prerequisites:

  • root ssh passwordless access to OpenWRT boxes.
  • php
  • awk

In WiFi.items (icon Wifi can have versions (Wifi-0, Wifi-1 etc. based on how many clients are on line):

Group:Number:SUM  WiFi_Clients "Wifi clients [(%d)]" <Wifi>
// 0 - not online, 1 - online
Number WiFi_My_mac  "My MacBookPro" <Wifi> (WiFi_Clients)
Number WiFi_My_iPhone   "My iPhone" <Wifi> (WiFi_Clients)

In sitemap simply:

Group item=WiFi_Clients

The script can be executed via cron or cron item of openhab and executeCommandLine() command. Make sure that the user that runs the script can login via ssh to the OpenWRT box(es).

 #!/bin/php
    <?php
      function readActiveWiFiMacs ($ip,$wifi) {
        $check_openWRT="ssh root@".$ip." 'iw dev ".$wifi." station dump' | awk '/^Station/ {print substr($2,0);}'";
        exec($check_openWRT,$addresses);
        return ($addresses);
      }
      function sendCommand($item, $data) {
        $url = "http://localhost:8080/rest/items/" . $item;
    
        $options = array(
            'http' => array(
            'header'  => "Content-type: text/plain\r\n",
            'method'  => 'POST',
            'content' => $data  //http_build_query($data),
            ),
        );
        $context  = stream_context_create($options);
        $result = file_get_contents($url, false, $context);
        return $result;
    }
      // An array of mac addresses to be checked, adjust to fit your setup
      $macAddresses = array(
       'f1:11:d1:d1:61:41' => 'My_mac',
       'b1:1b:1f:38:2e:48' => 'My_iPhone',
       );
      $users =array ();  // An array to hold  WiFi active status indexed by user name
      foreach ($macAddresses as $mac => $user)
        $users[$user]="0"; // As the openWrt will return only active clients, all known should be initially marked as OFF
      $macs = readActiveWiFiMacs ("192.168.1.2","wlan0");   			// Let's check the first access point
      $macs = array_merge($macs,readActiveWiFiMacs ("192.168.1.1","wlan0")); // Let's see who is online at second AP
      $macs = array_merge($macs,readActiveWiFiMacs ("192.168.1.1","wlan1")); // And on 5MHz network at second AP
      foreach ($macs as $mac)  // Mark users related to returned active mac addresses as active
        $users[$macAddresses[$mac]]="1";
      foreach ($users as $user => $status)
         sendCommand('WiFi_'.$user,$status);           
?>

What does this do verses the Network Health binding?

I could see this being useful if you have segregated your network so your openHAB and other home automation is on a segregated subnet from your computers (a good security policy) and your OpenWRT bridges both.

I can also see this being useful if the devices you care about have dynamic IP addresses and you don’t set up the hosts files or DNS so you can ping them by name.

But if all your devices are on the same network and pingable by name or with static IPs, the Network Health binding is an excellent solution. You can also use it to track specific ports so you can monitor whether certain services are up and running.

Network Health requires ping response, if I am not mistaken. I noticed that iPhones are not pingable when inactive (locked, with blank screen), but they are listed as active clients by OpenWRT. That is why I decided to use this approach instead of NH.

Moreover, as you stated, it works with segmented network and dynamic IP assignments.

Correct me if I’m wrong, but I think the script only works for specific DD-WRT wireless drivers. Other DD-WRT firmware might not have the “iw” command.

It was ment to work with Open WRT, tested on BARRIER BREAKER (14.07, r42625) and ATTITUDE ADJUSTMENT (12.09 r36088).

I have not verified it with DD-WRT.

I have butchered this script to use the arp table as my main router has no wifi in use and some of the wifi points are none WRT.

I used sshpass so that I could pipe in the password (very insecure I know)

#!/etc/php5
<?php
function readActiveWiFiMacs ($ip,$wifi) {
// $check_openWRT=“ssh root@”.$ip." ‘iw dev “.$wifi.” station dump’ | awk ‘/^Station/ {print substr($2,0);}’";
$check_openWRT=“sshpass -p password ssh -o StrictHostKeyChecking=no root@”.$ip." arp > /tmp/a8ree ; sleep 2 | awk ‘{print substr($4,0);}’ /tmp/a8ree";
exec($check_openWRT,$addresses);
return ($addresses);
}
function sendCommand($item, $data) {
$url = “http://192.168.1.8:8080/rest/items/” . $item;
$options = array(
‘http’ => array(
‘header’ => “Content-type: text/plain\r\n”,
‘method’ => ‘POST’,
‘content’ => $data //http_build_query($data),
),
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
return $result;
}
// An array of mac addresses to be checked, adjust to fit your setup
$macAddresses = array(
‘f1:11:d1:d1:61:41’ => ‘My_mac’,
‘00:ez:bd:aa:5a:c4’ => ‘My_iPhone’,
);
$users =array (); // An array to hold WiFi active status indexed by user name
foreach ($macAddresses as $mac => $user)
$users[$user]=“0”; // As the openWrt will return only active clients, all known should be initially marked as OFF
$macs = readActiveWiFiMacs (“192.168.1.1”,“wlan0”); // Let’s check the first access point
$macs = array_merge($macs,readActiveWiFiMacs (“192.168.1.1”,“wlan0”)); // Let’s see who is online at second AP
$macs = array_merge($macs,readActiveWiFiMacs (“192.168.1.1”,“wlan1”)); // And on 5MHz network at second AP
foreach ($macs as $mac) // Mark users related to returned active mac addresses as active
$users[$macAddresses[$mac]]=“1”;
foreach ($users as $user => $status)
sendCommand(‘WiFi_’.$user,$status);
?>

The good news is that it is working however

  1. It seems that sometimes the login is taking 3 times to complete - not sure why?
  2. There are errors/warnings generated

e.g.

PHP Notice: Undefined index: c0:3e:ab:26:d2:16 in /etc/openhab/wrt.php on line 34
PHP Notice: Undefined index: da:4d:5c:54:e1:9c in /etc/openhab/wrt.php on line 34
PHP Warning: file_get_contents(http://192.168.1.8:8080/rest/items/WiFi_): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
in /etc/openhab/wrt.php on line 19

Can anyone help?

I have script running on my OpenWRT that does similar work. It scans logread for “authentificated” and “deautentificated” words and requests for php script if found. It doesn’t require any polling and have no overhead for it.
You still need to have an http server because OpenWRT can’t call HTTP PUT directly that is necessary for REST API.
Here’s the code:

# see http://wiki.openwrt.org/doc/devel/debugging to enable additional logging
logread -f | while read input
do
  if `echo $input | grep -q deauthenticated`
  then
    mac=`echo $input | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'`
    wget -s "http://automation/insert_online.php?state=0&mac=$mac"
  elif `echo $input | grep -q authenticated`
  then
    mac=`echo $input | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'`
    wget -s "http://automation/insert_online.php?state=1&mac=$mac"
  fi
done

Actually there is an HTTP GET REST API for OH as well:

It’s also possible to send a status update using a HTTP GET request (http://localhost:8080/CMD?Temperature_FF_Office=12.3). This way it’s actually possible to send status updates simply through a web browser address bar.

Does it works without any extensions installed? I have 404 error when trying to access to this URL:

HTTP ERROR 404
Problem accessing /CMD. Reason:
Not Found

my script so far

   
#!/bin/sh

###############################################################

# Proximity detection
 
###############################################################

   
username="openhab"
   
password="password"
   
IPAddr="192.168.1.3"
   
port="8080"
   

macdevice1="00:00:cb:ab:00:a6"    #Brians Phone
   
macdevice2="00:01:91:9f:00:49"    #Jens Phone
   
macdevice3="00:00:00:00:00:00"    #Device 3
   
macdevice4="00:00:00:00:00:00"    #Device 4

   
# OpenHAB switch items to be updated for each tracked MAC


   
item1="Presence_Brian_Iphone_Macaddr"
   
item2="Presence_Jen_Iphone_Macaddr"
 
item3="DEVICE_3"
   
item4="DEVICE_4"

  
device=""

   
# see http://wiki.openwrt.org/doc/devel/debugging to enable additional logging


logread -f | while read input

  
do

	if `echo $input | grep -q deauthenticated`
  
  		then
   
    		mac=`echo $input | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'`
  
    		if `echo $mac | grep -q $macdevice1`
   
      			then
   
        		wget -s "http://openhab:password@192.168.1.3:8080/CMD?""$item1""=OFF"
   
		elif `echo $mac | grep -q $macdevice2`

		then
			wget -s "http://openhab:password@192.168.1.3:8080/CMD?""$item2""=OFF"

   
    		fi
   
	elif `echo $input | grep -q authenticated`
   
		then
  
    		mac=`echo $input | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'`
   
    		if `echo $mac | grep -q $macdevice1`
   
      			then
   
        		wget -s "http://openhab:password@192.168.1.3:8080/CMD?""$item1""=ON"
   
		elif `echo $mac | grep -q $macdevice2`
  
      			then
   
        		wget -s "http://openhab:password@192.168.1.3:8080/CMD?""$item2""=ON"
   
    		fi
  
  	fi
   
done
1 Like