Are You Home Yet? The System Knows... |
I have played with how to tell my Home Automation system if I was home or away for quite some time. Sure I can press a "home" button and an "away" button but what fun is that for a "Smart" home? I wanted the ability for the system to "know" if I'm home or not "automagically" without my sometimes forgetful intervention.
Back before moving to an iPhone I had a bluetooth solution "semi-working". The phone was paired with a bluetooth adapter on the server and some software was running that could tell if the phone was in range or not. A script would then spin through the status file, a simple flat text file, and see if my phone was local and adjust the status in my system. Kludgy but usually worked.
When I moved to an iPhone I was UNhappy to find out that the same bluetooth option would not work so I was back to figuring out a new solution. This time I wrote a script that "pinged" the IP my phone had picked up on the WiFi and if it was there then I was home, if not, away. That worked but I had to make sure I always had WiFi enabled on the phone and the script simply fired off a command ping which was very slow. Also sometimes the ping would time out anyhow if my phone was not active so I would suddenly be "away" when I was really home.
Google Latitude Tracking
The more recent solution is a combination of using Google Latitude (http://www.google.com/latitude), which I was already experimenting with, and a local VBScript that provides the linkage between Latitude data and my HA system. Latitude is available for various mobile phones and although obviously very "Big Brotherish" it provides a nice framework to handle the GPS tracking piece of a proximity system. It also provides all kinds of mobility analytics such as how many miles you've traveled, how much time you spend "at work" and "at home" and other rather interesting pieces of information.To be sure, Latitude is not perfect. It usually has my GPS location pretty well tied down but you will always see occasional "way out there" points when it defaults to the closest cell tower instead of a tight GPS point. But overall it's pretty good at keeping up with where you're at. Personally I haven't see any major battery drainage issues either but I am unrelenting on charging my devices every night no matter how they were used that day.
Of course the first thing you have to do is download the Latitude app for your particular mobile device. Visit the Latitude page and/or your app store and get it working on your device first. There are apps for many of the devices out there so check out the page / links. Make sure the Detect Your Location and Background Updating are turned on in the Settings area so the app is constantly updating location data.
To make Latitude your friend for getting data out, takes a special configuration that isn't overly obvious. You have to expose the data using the "Google Public Location Badge" feature. Sounds like you're giving away the farm but this is just an option if you WANT to publish everywhere you go all the time. The key is, this lets you build the data link but you DON'T HAVE TO share the link. The public location badge allows you to publish either a road map (KML), JSON or ATOM feeds of your location data but we are just going to use the data for our own purposes and not publish to the world.
To get your data link, log into Latitude on the web, click on the gear icon in the upper right, and go to Application Settings. At the very bottom of the screen is a "Developer Information" link. Click on that and you will see the linkage information and your own special username code in the various formats. We are using the JSON format here so the URL looks like this:
https://www.google.com/latitude/apps/badge/api?user={Your Code}&type=json
Once you have this link you can leave the rest of the page alone and move on. Just make sure the Enable and Show Best Location radio button is check in the configuration and click Save. That's after you've checked out all the other tidbits of data you'll have available about your movements of course.
Mobile Status Screen for My Home Automation System |
Getting the Data
Now we need to get the data feed and do some location checking. This is where the VBScript comes into play. You can do this in any other scripting or other language if you want, this is just the easiest to write and understand for me. This script is then scheduled on my HA server to run every five (5) minutes to see where I'm at. I actually have it log my Lat/Lon into my own local database and then check for within a certain range of my home address.VBScript Sample
The key features of the sample script are the GetLatitude and the GetDistance functions. GetLatitude uses your provided Google Latitude user code and pulls the current lat/lon data out of your feed. The GetDistance function takes two lat/lon pairs and returns the distance, in miles, between them. I am using a free online web API to do the distance comparison here but you could spin your own code if you wanted to. GeoCoder.us is free for the low level personal use I am dealing with here. With those two functions you can have your script do whatever you want with the results. The sample script below uses a CheckDistance variable to compare against the results and take action.You'll have to clean up some of the &Amp code issues if you copy/paste the script but the overall process is very simple. Also if you are behind a corporate proxy, the URL gets may or may not work. I've run an enhanced version of this script that links to my Home Automation system and toggles my status for months now and it's been quite stable. The code could obviously use some error handling or at least what to do if we get 0,0 back as location or odd distances but that's up to you creative people out there.
'** GetLatitude.vbsGet Google Latitude Lat/Lon for the user and log to the Log database 'v1.00 - SWN - 10/29/2011 '** Debugging flag - True to see messages MyDebug = TRUE '** Your information and location to test against '** Google Latitude User ID UserID = "{Your Latitude Code Here}" '** Location Latitude to test against LocLat = 35.32 '** Location Longitude to test against LocLon = -96.92 '** If you are within 1/2 Mile of LocLat/LocLon then If triggers CheckDistance = .5 '** First get the user (YOU) current location from the Latitude JSON feed MyLonLat = GetLatitude(UserID) '** Debug stuff - show it if debugging If MyDebug then MsgBox "Raw Coords: " & MyLonLat '** Split out the Lat/Lon from the results MyCoordsA = SPLIT(MyLonLat) MyLon = MyCoordsA(0) MyLat = MyCoordsA(1) '** Now do a distance check between the points '** Note this uses another free web API, GeoCoder.us to calc this for us '** You could build your own dist compare if you wanted... but why if this is there? '** Distance returned is in Miles so you can convert as desired from there MyDistance = GetDistance(MyLat, MyLon, LocLat, LocLon) '** Show distance if debugging If MyDebug then MsgBox "Distance: " & MyDistance '** Now take action on the distance check results '** Obviously you will have to have some session state here so this doesn't fire on every check '** In my HA system, it sets a Home flag so my code checks if the should be changed and takes action if needed If MyDistance < CheckDistance then '** Do something cool because you're close MsgBox "You are within " & MyDistance & " of your target location." Else '** Do something else because you're not MsgBox "You are OUTSIDE of your target location by " & MyDistance - CheckDistance & " miles." End If '** get the Lat/Lon data from your Google Latitude Feed Function GetLatitude(strUserID) Set objHttp = CreateObject("Msxml2.ServerXMLHTTP") objHttp.Open "GET", "http://www.google.com/latitude/apps/badge/api?user=" & strUSERID & "&type=json&callback=parse", False objHttp.Send html = objHttp.ResponseText Lines = Split(html, "[", -1, 1) Count=UBound(Lines) MyCoords = lines(2) MyCoords = LEFT(MyCoords,INSTR(MyCoords,"]") - 1) GetLatitude = MyCoords Set objHTTP = nothing 'Release the object End Function '** Calc the distance between two lat/lon points and return as MILES Function GetDistance(Lat1, Lon1, Lat2, Lon2) Set objHttp = CreateObject("Msxml2.ServerXMLHTTP") GetLink = "http://geocoder.us/service/distance?lat1=" & Lat1 & "&lat2=" & Lat2 & "&lng1=" & Lon1 & "&lng2=" & Lon2 objHttp.Open "GET", GetLink, False objHttp.Send html = objHttp.ResponseText '** Parse out the information here StartPos = Instr(html,"=") EndPos = Instr(html,"mile") GetDistance = Ltrim(Rtrim(Mid(html,StartPos + 1, EndPos-StartPos-1))) GetDistance = GetDistance * 1 Set objHttp = Nothing End Function