New! Check out the new ClickOnce Where's Tim Tasktray alerter!
http://timhibbard.com/wherestim/
When I tell people that I keep a GPS enabled Nextel phone in my car and anybody, at anytime can see my current position, they always ask, “Well, aren’t you worried about that?” I always say, “No, one day everybody will use their current location to assist them in their everyday lives.” While most people aren’t as comfortable with this level of transparency, I believe the social and business benefits of real time location based services will change the world, and the company that I work for, EnGraph (http://www.engraph.com/), is putting a lot of time and research into this area.
Where's Tim is an ASP.net page using Google Maps (http://maps.google.com/), EnGraph GPS Parser (http://www.engraph.com/gps.html), and AJAX.net (http://ajax.schwarz-interactive.de/csharpsample/default.aspx). One of EnGraph's main focuses is Automatic Vehicle Locator (AVL) systems, and the original goal of Where's Tim (besides using Google's awesome map API) was to simulate the functionality of our business AVL solutions as a quick way to show potential customers what we can provide.
Some of the features are:
Auto Refresh:
Using the AJAX.net library, it will get my current position, change the location of the icon on the map, and recenter the map if the icon goes outside the bounds of the map. Since this is done asynchronously, the experience is seamless to the user. The interval between map refreshes can be set using Auto Refresh. The default interval is 30 seconds. The idea behind AJAX is simple. You have one .NET function and two javascript functions.
.NET Function
Public Class AJAXDemo
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Ajax.Utility.RegisterTypeForAjax(GetType(AJAXDemo))
End Sub
_
Public Function GetDotNetTime() As String
Return Now.ToString
End FunctionEnd Class
Javascript:
function getTime(){
AJAXDemo.GetDotNetTime(getTime_callback);
}
function getTime_callback(response){
var av = response.value;
alert(av);
}
The AJAX code in Where's Tim is a bit more complicated, but it is based on this simple concept.
Messaging:
Clicking on my location icon brings up an openInfoWindowHtml window. In that window, a user can see what street address I am closest to, my speed, the last recorded reading time, and a place to enter a message to send to me. An optional return email address text box is there, and a message text box. Once the message is entered, clicking "Send" will send the message to my phone. This is also all done asynchronously with AJAX.net and a green Sent! message is displayed in the window upon success. The message goes through the Where's Tim Webservice and the code looks like this:
Fly To With Google Earth:
Google Earth is one of those programs that is starting to change the world. It's biggest exposure (unfortunately) was during all the hurricanes when news stations would use it to show places that had been impacted. Google Earth understands a type of XML called KML. I found one of these files, picked it apart and figured out what to change to make it work in this application. On Where's Tim, there is a button called "Fly To With Google Earth". Clicking this button will take a base XML file, use an XMLNodeList to parse and change the base XML file, save the base XML as a KML file, and use a Response.Redirect to launch the url with the KML file When the user pushes "Open," Google Earth will open and "Fly To" my current location using my picture as an icon.
Here is the base XML file that I used. Note that the file HAS to be saved with the .xml extension.
Private Function GenerateKML(ByVal lat As Double, ByVal lon As Double) As String
Dim xDoc As New System.Xml.XmlDocument
'Change this url to where you saved your base XML doc
xDoc.Load("http://www.timhibbard.com/kml/base.xml")
Dim nowticks As String = Now.Ticks.ToString
'creates a new unique name to save
Dim tmpFileName As String = Server.MapPath("kml\") & nowticks & ".xml"
'replaces the longitude tag with the lon parameter
Dim MyNode As System.Xml.XmlNodeList = xDoc.GetElementsByTagName("longitude")
MyNode.Item(0).InnerText = lon.ToString
'replaces the latitude tag with the lon parameter
MyNode = xDoc.GetElementsByTagName("latitude")
MyNode.Item(0).InnerText = lat.ToString
'replaces the coordinates tag with actual data
MyNode = xDoc.GetElementsByTagName("coordinates")
MyNode.Item(0).InnerText = lon.ToString & ", " & lat.ToString & ", 0"
'saves the file as an XML document
xDoc.Save(tmpFileName)
Dim actualFileName As String = tmp.TrimEnd(".xml".ToCharArray) & ".kml"
'renames the file as a KML file that Google Earth can understand
Rename(tmpFileName, actualFileName)
Return "http://www.timhibbard.com/kml/" & nowticks & ".kml"
End Function
Get Directions To Tim:

This is a feature that my boss, Kyle Archer (http://kylejarcher.blogspot.com), requested. He wanted to be able to click on the map and find out how far away he was from me. I took it a step further and provided directions to my current location. Clicking the "Get Directions To Tim" button prompts the user to select their current position on the map (the map can still be moved around and the zoom level can be changed). When the user has selected their location, Where's Tim will asynchronously generate a Google Maps URL with directions to my location. The URL is then launched in the web browser. This is also done with AJAX.net.
Here is the VB.NET code:
_
Public Function GetDirectionsURL(ByVal lat As String, ByVal lon As String) As String
Try
'class that handles my current gps location
Dim myLoc As MyLocation.Loc = GPS.GetLocation
'generate url
Dim RV As String
RV = "http://maps.google.com/maps?q=from%3A+" & lat.ToString & ",+" & lon.ToString
RV += "+to%3A"
RV += "+" & myLoc.lat & ",+" & myLoc.lon
Return RV
Catch ex As Exception
Return "http://maps.google.com"
EndTry
End FunctionThe Javascript code:
var lstner;
function getdirections()
{
alert("Click on your location on the map");
lstner = GEvent.addListener(map, 'click', function(overlay, point){
document.getElementById("btnGetDirections").value = "Working...";
document.getElementById("btnGetDirections").disabled = true;
var x = point.x;
var y = point.y;
wherestim.GetDirectionsURL(y,x, getdirections_callback);
});
}
function getdirections_callback(response)
{
var av = response.value;
document.getElementById("btnGetDirections").value = "Get Directions to Tim";
document.getElementById("btnGetDirections").disabled = false;
GEvent.removeListener(lstner);
//window.navigate(av); wasn't working on firefox
window.location=av;
}
RSS:
We have several different RSS Feeds.
My current location feed. You can customize it here.
Where's Tim news.
Text messages people send me. My favorite feed...just look at these :)
Get Directions to me log
List of the nice people that have linked to Where's Tim.
Where's Tim Mobile:

I built this when my new phone didn't support any of the Sprint GPS applications. It uses Yahoo Map Image REST API to generate a map centered around a star at my current location. The page is http://www.timhibbard.com/wherestimmobile.aspx. The code is simple. I build a REST url with my lat/long information and the size of the image I want returned and load the url into a XMLDocument. Yahoo will return a url that points to the image.
WeatherBug:
WeatherBug provides an API (http://api.weatherbug.com/api/) that allows for a zipcode to be placed in a REST url and it returns an object with weather information.
Basically, to consume WeatherBug's API, I:
1) Make a call to the Where's Tim webservice
2) Parse the zipcode out of the .Place property of the GPSData structure
3) Pass the zipcode into a function that builds the REST url
4) Load the url into a System.Data.DataSet using the .ReadXML function
5) Pass that DataSet into my WeatherInfo structure that takes a DataSet as a constructor
Code to get location and parse zipcode:
Public Function GetTimsWeather() As WeatherInfo
Try
Dim CurData As GPSData = GetTimsLocation()
Dim ZipCode As String = CurData.Place.Remove(0, CurData.Place.Length - 5)
Return GetWBInfo(ZipCode)
Catch ex As Exception
Return Nothing
End Try
End Function
Code to build URL, load DataSet, and construct structure:
Private Function GetWBInfo(ByVal ZipCode As String) As WeatherInfo
Try
Dim url As String = "http://[myCode].api.wxbug.net/getlivecompactweather.aspx?acode=[myCode]&zipcode=" & ZipCode
Dim DS As New System.Data.DataSet
DS.ReadXml(url)
Dim RV As New WeatherInfo(DS, ZipCode)
Return RV
Catch ex As Exception
Return Nothing
End Try
End Function
Code of WeatherInfo structure constructor:
Public Sub New(ByVal DS As System.Data.DataSet, ByVal ZipCode As String)
Try
_temp = DS.Tables("temp").Rows(0).Item("temp_Text")
_rain = DS.Tables("rain-today").Rows(0).Item("rain-today_Text")
_wind = DS.Tables("wind-speed").Rows(0).Item("wind-speed_Text")
_winddirection = DS.Tables("weather").Rows(0).Item("wind-direction")
_zipcode = ZipCode
_weblink = "http://web.live.weatherbug.com/Common/home.aspx?zip=" & _zipcode
Catch ex As Exception
End Try
End Sub
Where's Tim Webservice;
Our webservice (http://www.timhibbard.com/webservices/engraphgps/engraph.asmx) allows other developers to integrate my current location information into their applications.
The GetTimsLocation function returns a GPSData structure:
GPSData
-Lat
-Lon
-Speed (in MPH)
-Since (last active reading - date format)
-Place (reverse geocoded location - string)
Thanks to the new My class in VS2005, my current speed can be displayed with one line of code:
MsgBox(My.WebServices.EnGraphGPS.GetTimsLocation.Speed.ToString)
The SendTimAnEmail function accepts 3 parameters (From, Subject and Body) and returns a boolean
The SendTimATextMessage function accepts 2 parameters (From and Message) and returns a boolean
The GetTimsWeather function returns a WeatherInfo structure:
WeatherInfo
-Temp (current, in Fahrenheit)
-Rain (amount for current day)
-Wind (in MPH)
-WindDirection
-ZipCode
-WebLink (to extended information)
The future:
In the coming months, we want to add:
-Geofencing alerts. A user could get an email, text message or RSS feed when I enter or leave a virtual geographic area.
-More Yahoo maps integration.
-Add tabbed info windows like on Google Local.
-Integration with Flickr (http://www.flickr.com). So that users can see pictures from around my current location.
-A ClickOnce Windows Forms application that has the same functionality (almost done).
-Historical views. Users will be able to view where I was during a given date range.
We have been researching and developing GPS applications and components since the mid 1990's. We have developed reusable dll's that work with multiple GPS data sources. The communications gap is the main thing holding GPS back from penetrating the consumer market. Nextel is the only company that has released the API for developers to capture and process GPS data. Sprint has promised this API to developers for years, and hopefully it is just a matter of time before we can pull GPS data from Sprint phones. Stand alone GPS devices still have to be hard wired to cellular or satellite communication to push the GPS data to a server for consumption. Eventually, manufacturers will add Wi-Fi, allowing them to connect to any unsecured wireless network and send the data to a specific server. These future GPS devices will also have Bluetooth technology, where they will easily pair with a cell phone and use its existing network connection to move data.
When all the communication and hardware handcuffs are removed, who knows "Where Tim" will be in 5 years.
Tim Hibbard's real time location
Location of Tim Hibbard, Software Architect for EnGraph
Tim Hibbard
Replace Me later
Replace Me later
3000
60
0
1
1
relativeToGround
replace with lat,replace with lon,0
I then use this function to populate the XML document:
_
Public Function SendTimATextMessage(ByVal From As String, ByVal Message As String) As Boolean
Try
Dim MyAddress As String = "mailto:785550143@messaging.sprintpcs.com"
If Message = "" Then
Message = "no message"
End If
If From = "" Then
From = "no@email.com"
End If
Dim MM As New System.Net.Mail.MailMessage(From, MyAddress, "no", Message)
Dim Sender As New Net.Mail.SmtpClient
Sender.Credentials = New Net.NetworkCredential("tim@timhibbard", "mypassword")
Sender.Host = "mail.timhibbard.com"
Sender.Send(MM)
Return True
Catch ex As Exception
Return False
End Try
End Function