Page 1 of 2
Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Monday 20 October 2014 9:47
by salvation
Hi,
I've created a script to determine if someone is at home (or not). It's based on if clients are connected to my Ubiquiti Wifi Network. So via the API I check if a at least one client is connected. I'm not a programmer at all, so most of the code is grabbed from several scripts and it's also a Lua script combined with a bash script.
I think it could be definately be cleaner code, but at least it's working. And it works a lot better than using Automatit or Tasker on the Android phones.
I'm using a dummy light to switch when someone is at home.
Lua time script to trigger the check.
Code: Select all
commandArray = {}
-- Call setHome when someone at home
if (otherdevices['homeSomeOne']=='On') then
os.execute('sudo ./home/pi/domoticz/scripts/bash/setHome.sh "On"')
print('called setHome / On')
end
-- Call setHome when no one at home
if (otherdevices['homeSomeOne']=='Off') then
os.execute('sudo ./home/pi/domoticz/scripts/bash/setHome.sh "Off"')
print('called setHome / Off')
end
return commandArray
Bash script setHome.sh to call Ubiquiti API and switch the dummy light if needed:
Code: Select all
#!/bin/sh
lightStatus=$1
username=<ubiquiti-controller login>
password=<ubiquiti-controller pass>
baseurl=<ubiquiti-controller url>
cookie=/tmp/unifi_cookie
curl_cmd="curl --sslv3 --silent --cookie ${cookie} --cookie-jar ${cookie} --insecure "
named_args_to_payload() {
payload=""
for a in "$@" ; do
if [ "${a##*=*}" = "" ] ; then
k=`echo $a | cut -d = -f 1`
v=`echo $a | cut -d = -f 2`
payload="${payload}, '$k':'$v'"
fi
done
echo ${payload}
}
unifi_requires() {
if [ -z "$username" -o -z "$password" -o -z "$baseurl" ] ; then
echo "Error! please define required env vars before including unifi_sh. E.g. "
echo ""
echo "username=ubnt"
echo "password=ubnt"
echo "baseurl=http://unifi:8443"
echo ""
exit -1
fi
}
unifi_login() {
# authenticate against unifi controller
${curl_cmd} --data "login=login" --data "username=$username" --data "password=$password" $baseurl/login
}
unifi_logout() {
# logout
${curl_cmd} $baseurl/logout
}
# stat/sta
unifi_list_sta() {
${curl_cmd} --data "json={}" $baseurl/api/stat/sta
}
unifi_requires
unifi_login
#put unifi_list_sta output in variabele
#check if a least one host is connected
var=$(unifi_list_sta)
if echo "$var" | grep -q "hostname"; then
isHome=yes;
else
isHome=no;
fi
if [ "$isHome" = "yes" ] && [ "$lightStatus" = "Off" ]; then
curl "http://<domoticz-url:port>/json.htm?type=command¶m=switchlight&idx=48&switchcmd=On"
fi
if [ "$isHome" = "no" ] && [ "$lightStatus" = "On" ]; then
curl "http://<domoticz-url:port>/json.htm?type=command¶m=switchlight&idx=48&switchcmd=Off"
fi
unifi_logout
Next to this I'm using a LUA script to trigger some outlets and lights based on the status of the dummy light.
In the future I will try to get the same result in LUA only but I'm not familiar using JSON and LUA. If someone has tips for improving it let me know.
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Tuesday 15 March 2016 9:47
by tyfoon
Hi, Very much interested in this! I'm now using presence detection via a script on my Asus router that then triggers my Vera. It's based on MAC address as this turns out to be very reliable.
However I just switched to UBiquity AC Pro AP's and now I have to start over.
Can you tell me more about your scripts? Are you still using them? Does it still work for you?CWhat needs to be done (installed) to get working with the Unifi API?
Any help greatly appreciated!
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Sunday 24 April 2016 17:57
by parkerc
Hi
Has there been any more development on this, it would be good to be able to integrate/extract information from the UniFi system and use it in home automation
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Thursday 06 October 2016 10:55
by loyske
Would be nice if the script could check if a certain hostname is connected? My iPad is always at home, so that's not helping now.
If i could check if the hostname or maybe the static IP of my iPhone is connected, that would be cool!
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Thursday 08 December 2016 10:03
by lightman
is there already something to check on specific user / hostname?
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Sunday 12 March 2017 21:38
by Martijn85
@salvation is there any way to update this script? It seems that the API has changed since 2014? Can you help me out with this one.
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Monday 13 March 2017 22:57
by salvation
I'm not using this script anymore. I use a combination of geofence and ping to determine if someone/a phone is at home.
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Monday 13 March 2017 23:30
by Martijn85
Ok thanks for the reply. I will take a look if i can get this to work.
The controller works a lot beter, even when some phones are stand-by the phones are visible, with a ping there not.
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Tuesday 14 March 2017 2:10
by asjmcguire
If this is still needed - I'm going to look into it now - but I'll be scripting using PHP because I'm more comfortable with complex stuff in PHP, and because I can't figure out why those 2 scripts up above are not 1) simpler and 2) require sudo when they aren't using any programs that require sudo.
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Tuesday 14 March 2017 3:52
by asjmcguire
Just stick it on your computer - edit the config section and tell cron to run the file every minute or every 5 minutes or whatever.
Code: Select all
#!/usr/bin/php
<?php
// ******** START OF CONFIG VARS ***************
//Hostnames/MAC addresses to find
$hosts = "LG-G4 b8:27:eb:ef:26:80"; //space seperated, can be name, hostname or mac
//Unifi Config
$unifi['user'] = "<unifi-user>";
$unifi['pass'] = "<unifi-password>";
$unifi['port'] = 8443;
$unifi['base'] = "https://<ip-address>";
//Domoticz Config
$dom['switchidx'] = 483; //I have a blockly connected to this virtual switch so I can turn multiple things on and off
$dom['host'] = "http://<domoticz ip>";
$dom['port'] = 8080;
$dom['user'] = ""; //leave empty if no auth needed
$dom['pass'] = ""; //leave empty if no auth needed
//You probably won't need to change these - but if you do.....
$unifi['site'] = "default";
//**************** END OF CONFIG *******************
//Attempt login
$cookiejar = tempnam(sys_get_temp_dir(),"unifi_cookie.dat");
$login_url = "{$unifi['base']}:{$unifi['port']}/api/login";
$p['username'] = $unifi['user'];
$p['password'] = $unifi['pass'];
$p['strict'] = true;
$json = json_encode($p);
$ch = curl_init();
curl_setopt($ch, CURLOPT_COOKIESESSION,true);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiejar);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_URL,$login_url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($json))
);
$resp = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if (!empty($resp)) {
$result = json_decode($resp,true);
if ($result['meta']['rc'] !== "ok") { bailout("Credentials invalid or URL not found.\n{$login_url}",1); }
} else {
bailout("Credentials invalid or URL not found.\n{$login_url}",1);
}
//OK - so we got here with valid credentials - let's get a list of connected stations (hopefully)
$sta_url = "{$unifi['base']}:{$unifi['port']}/api/s/{$unifi['site']}/stat/sta";
$ch = curl_init();
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiejar);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiejar);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_URL,$sta_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resp = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if (!empty($resp)) {
$data = json_decode($resp,true);
if ($data['meta']['rc'] !== "ok") { bailout("Logged in but couldn't get clients connected list",1); }
$matches = processClients($data['data']);
$switchstate = 0;
if (count($matches)) {
echo "Found " .count($matches) ." clients online\n";
foreach($matches as $client) {
$hname = (isset($client['hostname']) ? $client['hostname'] : "<No Host Name>");
$host = (isset($client['name']) ? $client['name'] : $hname);
echo "Host: {$host} == {$client['mac']}\n";
}
$switchstate = 1;
}
else { echo "No matching clients are currently connected\nNo-one is home!\n"; }
processDomoticz($switchstate);
@unlink($cookiejar);
} else { bailout("Logged in but couldn't get clients connected list",1); }
function processClients($clients) {
global $hosts;
$matches = array();
foreach($clients as $id => $client) {
if ($client['authorized']) {
$hname = (isset($client['hostname']) ? $client['hostname'] : "<No Host Name>");
$cname = (isset($client['name']) ? $client['name'] : $hname);
//echo "{$cname} == {$client['mac']}\n";
if (stristr($hosts,$cname) <> "" || stristr($hosts,$client['mac']) <> "") { $matches[] = $client; }
}
}
return $matches;
}
function processDomoticz($state) {
global $dom, $cookiejar;
//check what the existing switch state is
$ch = curl_init();
$url = "{$dom['host']}:{$dom['port']}/json.htm?type=devices&filter=light&used=true&order=Name";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if (!empty($dom['user'])) {
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "{$dom['user']}:{$dom['pass']}");
}
$resp = curl_exec($ch);
curl_close($ch);
if (!empty($resp)) {
$data = json_decode($resp,true);
$match = 0;
foreach($data['result'] as $switch) {
if ($switch['idx'] == $dom['switchidx']) {
$match = 1;
break;
}
}
if (!$match) { bailout("Connected to Domoticz but didn't find SwitchIDX {$dom['switchidx']}",1); }
$oldstate = ($switch['Status'] == "Off" ? 0 : 1);
if ($oldstate == $state) { @unlink($cookiejar); exit("Switch state doesn't need changing"); }
$newstate = ($state ? "On" : "Off");
echo "\nTurning Switch {$newstate}";
$ch = curl_init();
$url = "{$dom['host']}:{$dom['port']}/json.htm?type=command¶m=switchlight&idx={$dom['switchidx']}&switchcmd={$newstate}";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if (!empty($dom['user'])) {
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "{$dom['user']}:{$dom['pass']}");
}
$resp = curl_exec($ch);
curl_close($ch);
} else { bailout("Couldn't connect to Domoticz!\nCheck URL",1); }
}
function bailout($msg,$exitcode = 1) {
global $cookiejar;
@unlink($cookiejar);
echo "\n*** ERROR ***\n{$msg}\n";
exit($exitcode);
}
?>
Job done. Hope this helps someone.
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Tuesday 14 March 2017 14:41
by sach
This is great, thank you.
It seems to take a while before the host is shown as not active on the Unifi Controller. Do you know if its possible to speed this up in anyway?
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Tuesday 14 March 2017 17:36
by asjmcguire
sach wrote:This is great, thank you.
It seems to take a while before the host is shown as not active on the Unifi Controller. Do you know if its possible to speed this up in anyway?
Yeah seems to be about 5 minutes here - I guess it's because it's holding on to see if the host is really active but just in a bad signal area.
I don't believe there is any way to speed it up.
However there is a "lastseen" field - which I could experiment with - but I haven't so far because I haven't checked yet to see if the timestamp is in UTC or local time or what and playing with timezones is a confusing minefield (especially when DST comes into play) plus we might not be able to speed it up to more than half the time, but could introduce the possibility that the script will see clients as not being active when they are but just haven't been seen for a while.
Leave it with me - this was done at 3 in the morning, just to see if it was feasible.
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Wednesday 15 March 2017 0:15
by sach
Yup you are right it is 5 minutes. Been testing it today and this delay isn't actually too bad. Saves all my lights switching off include I lose WiFi for a minute.
Just need to see how it reacts to my wife's iPhone overnight as the logs on the unifi controller indicate that it switches the WiFi on and off.
Thanks for all your hard work on this. Really appreciate it!
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Wednesday 15 March 2017 1:13
by asjmcguire
sach wrote:Yup you are right it is 5 minutes. Been testing it today and this delay isn't actually too bad. Saves all my lights switching off include I lose WiFi for a minute.
Just need to see how it reacts to my wife's iPhone overnight as the logs on the unifi controller indicate that it switches the WiFi on and off.
Thanks for all your hard work on this. Really appreciate it!
Providing that at least one device in the $hosts list is connected to the controller, the script will assume that someone is home and hence the virtual switch will stay on. So even if your wifes iPhone connects and disconnects all the time, as long as your device is connected - it won't matter too much. If however your device is not home and your wifes iPhone is but keeps connecting and disconnecting then it will cause the lights to go on and off.
There are 2 potential ways to fix this - the first is with Domoticz itself, I have to do something similar to this because I have a dusk sensor - which has a habit of switching on and off several times at dusk and dawn - so I have a virtual switch I use for Hysteresis - if the switch is off and the dusk sensor switches on, it switches the hysteresis switch on (which is on a 15 minute timer), the blockly event.
Code: Select all
Pseudo Code Follows:
[Event virtualNightMode]
If NightMode = On &
NightModeHysteresis = Off &
virtualNightMode = Off then
set virtualNightMode = On &
set NightModeHysteresis on for 30 mins.
Elseif NightMode = Off &
NightModeHysteresis = Off &
virtualNightMode = Off then
set virtualNightMode = Off &
set NightModeHysteresis = On for 30 mins.
[Event NightMode]
if virtualNightMode = On &
virtualAtHome = On then
setGroup LightingDownstairs = On &
send Notification "As you are home, I have turned on the lights for you"
Elseif virtualNightMode = On &
virtualAtHome = Off then
set Livingroom = On &
send Notification "As you are away from home, I have turned the LivingRoom light on"
[Event NightMode Off]
if virtualNightMode = Off then
setGroup AllLights = Off
As you can see - it would be relatively easy to adapt this to implement some hysteresis to prevent turning lights on and off when the WiFi connection is interrupted briefly.
It's also possible for me to adapt the code a bit to take this into account, which is probably what I will end up doing - because I was thinking to reduce the load on Domoticz a bit - I should probably cache the status of the AtHome switch for a few minutes so it doesn't need to ask Domoticz every time - I would then only skip the cache if either it's more than a few minutes old (?5 maybe?) or if the new state of the switch is different to the cached state - at which point - obviously we need to check with domoticz to see if we need to send a request to change the state of the switch. It would probably make sense to add the (configurable) hysteresis to the script at the same time - but you can always play with option 1 in the meantime until I have a few hours to adapt the script a bit.
Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Wednesday 15 March 2017 1:15
by Martijn85
Just changed it to php? Which version of the controller you have running? The api url's has been changed in the latest versions. I also have the script working in shell script. Will post the update tommorow. This works with version 5.x
Edit: never mind, Tapatalk only shows the first line of the php script.
Looks great, Thanks m8!
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Wednesday 15 March 2017 1:22
by asjmcguire
Martijn85 wrote:Just changed it to php? Which version of the controller you have running? The api url's has been changed in the latest versions. I also have the script working in shell script. Will post the update tommorow. This works with version 5.x
Edit: never mind, Tapatalk only shows the first line of the php script.
Looks great, Thanks m8!
v5.0.7
Oh just seen the edit - no problem. See above post regarding possible caching and adding some configurable hysteresis - and let me know your thoughts - this was all just a quick 2 hour middle of the night experiment to prepare for computerised heating
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Wednesday 15 March 2017 8:41
by sach
That's great....excellent work sir!
I have 2 instances of the script running, one for each phone. This lets me be a little granular if for instance I want something to happen when only on of us are out, like leaving the driveway lights on for the other person etc. I also have an Away mode override switch (which is on my imperihome homepage on the tablet in the hallway) for times when we might both be out and have a babysitter round looking after the kids. Only if all 3 conditions are met does the system enter into Away mode.
Looks like it worked a treat last night on the iPhone. No notifications on switch change from Domoticz so I was just worrying about nothing.
Love this solution as it's much more reliable than Geo, doesn't have any impact on battery life and doesn't require Domoticz to be published externally.
Now I need to make a list of my current timer plans so I can create a proper Away Mode timer plan.
Thanks again
Sach
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Wednesday 15 March 2017 11:35
by Martijn85
The PHP scripts works great, thanks for all this hard work
I already had the shell script updated, so if someone still want's to use this one, this is the updated code:
script_time_unifi.lua
Code: Select all
commandArray = {}
-- Call setHome when someone at home
if (otherdevices['SwitchName']=='On') then
os.execute('sudo /bin/bash /home/pi/domoticz/scripts/device.sh "On"')
print('called setHome / On')
end
-- Call setHome when no one at home
if (otherdevices['SwitchName']=='Off') then
os.execute('sudo /bin/bash /home/pi/domoticz/scripts/device.sh "Off"')
print('called setHome / Off')
end
return commandArray
device.sh
Code: Select all
#!/bin/sh
lightStatus=$1
unifi_username=username
unifi_password=password
unifi_controller=https://ip-address:8443
cookie=/tmp/unifi_cookie
domoticz_ip=127.0.0.1
domoticz_port=8080
switch_idx=511
curl_cmd="curl --cookie ${cookie} --cookie-jar ${cookie} --insecure "
named_args_to_payload() {
payload=""
for a in "$@" ; do
if [ "${a##*=*}" = "" ] ; then
k=`echo $a | cut -d = -f 1`
v=`echo $a | cut -d = -f 2`
payload="${payload}, '$k':'$v'"
fi
done
echo ${payload}
}
unifi_requires() {
if [ -z "$unifi_username" -o -z "$unifi_password" -o -z "$unifi_controller" ] ; then
echo "Error! please define required env vars before including unifi_sh. E.g. "
echo ""
echo "username=ubnt"
echo "password=ubnt"
echo "unifi_controller=http://unifi:8443"
echo ""
exit -1
fi
}
unifi_login() {
# authenticate against unifi controller
${curl_cmd} -H "Content-Type: application/json" -X POST -d "{\"password\":\"$unifi_password\",\"username\":\"$unifi_username\"}" $unifi_controller/api/login
}
unifi_logout() {
# logout
${curl_cmd} $unifi_controller/logout
}
# stat/sta
unifi_list_sta() {
${curl_cmd} --data "json={}" $unifi_controller/api/s/default/stat/sta
}
unifi_requires
unifi_login
#put unifi_list_sta output in variabele
#check if a least one host is connected
var=$(unifi_list_sta)
if echo "$var" | grep -q "DeviceName"; then
isHome=yes;
else
isHome=no;
fi
if [ "$isHome" = "yes" ] && [ "$lightStatus" = "Off" ]; then
curl "http://$domoticz_ip:$domoticz_port/json.htm?type=command¶m=switchlight&idx=$switch_idx&switchcmd=On"
echo Switch state changed to On
fi
if [ "$isHome" = "no" ] && [ "$lightStatus" = "On" ]; then
curl "http://$domoticz_ip:$domoticz_port/json.htm?type=command¶m=switchlight&idx=$switch_idx&switchcmd=Off"
echo Switch state changed to Off
fi
unifi_logout
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Wednesday 15 March 2017 14:55
by asjmcguire
Martijn85 wrote:The PHP scripts works great, thanks for all this hard work
I already had the shell script updated, so if someone still want's to use this one, this is the updated code:
I only have 2 queries, the first is why does the first script require sudo - I can't see any commands being run that would require the user of the script to be authenticated with admin credentials.
The second query is - when I was creating the PHP script I discovered a number of oddities with the list of devices - you need to check for both hostname and name - because if the device has been given a name (Alias) in the controller - then it seems to omit the hostname field and presents the name field instead - and if you are searching for both of those, you might as well allow searching the mac field too.
EDIT: Ignore the second question, I see that "DeviceName" is actually whatever we are searching for. So it's just the sudo question.
(As my script uses PHP - I should probably create a new post in the PHP section to stop this becoming a bit too muddled for the mods)
Andy
Re: Switch on/off when someone entering/leaving home (Ubiquiti)
Posted: Wednesday 15 March 2017 21:58
by Martijn85
asjmcguire wrote:EDIT: Ignore the second question, I see that "DeviceName" is actually whatever we are searching for. So it's just the sudo question.
Hello Andy, you don`t realy need the sudo command, i just added this one to be sure that the script is running correctly. If i delete the sudo part it`s also running fine