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.
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
It seems that sometimes the login is taking 3 times to complete - not sure why?
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
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.