Wednesday, May 2, 2012

[Added 12/27/2014: Updated code using the new schema and JSON encoding, here][Added 1/22/2014: Please note that SPOT has revised their API and this code has not been updated to reflect that. See this post.]

Well, not very much closer, since the data and their representation are pretty simple, as described here. So, I'll take a look at how to pull down the data, parse them out, and put them on a map. This is where race tracking software starts, and the tracker put together by the folks who tracked the Percy Dewolfe didn't go a lot further. A "real" tracker is a far more complicated thing and needs to be smart about speed to be credible, has to deal with storing and retrieving data for all participants over the length of the race, subsetting the data on demand, plus all that fancy stuff that Trackleaders and others do.

Snagging the data

An "API," or "application programming interface," is how services are exposed (or provided) to third parties programmatically. That is to say, if I want to write my own programs that make use of Spot's tracking data, or Google Maps (or both!), I use their APIs from my programs.

The truth is that Spot's API can barely be considered an API, since all it really allows you to do is to download XML-formatted records. Here's how it works:

When you register your Spot tracker, or edit your settings, you have the opportunity (if and only if you've paid for the tracking service) to set up a "shared page" to display the data. That shared page is automatically assigned a "glId" by Spot. I believe that "glId" is a "guest link" identifier, but I wouldn't swear to it. Anyway, you can find the glId for your shared pages by going to your list of shared pages at https://login.findmespot.com/spot-main-web/share/list.html and choosing the shared page that has the data you'd like to use.

You'll find the glId embedded in the URI of the shared page. So, if the URI of the shared page is "http://share.findmespot.com/shared/faces/viewspots.jsp?glId=0BW5A0B1QQFTHG4GivzbYsQFyIFo5VHTh" the glId is 0BW5A0B1QQFTHG4GivzbYsQFyIFo5VHTh.

The data can be accessed through the URI http://share.findmespot.com/messageService/guestlinkservlet?glId=0BW5A0B1QQFTHG4GivzbYsQFyIFo5VHTh&completeXml=true with the glId from your shared page substituted in for the glId value.

When you do an HTTP GET on that URI, what you'll get is a chunk of XML, as described in this earlier post.

Displaying the data

Once you get the data out of your Spot shared page, you need to parse the XML, then turn it into data you can display using the mapping API of your choosing. These days the most popular option is Google maps, which has a rich API and which gives the programmer a lot of control over what goes on the page and how the user interacts with it. I've written a very simple example of using Spot data to create a track on a Google map, with clickable track points and pop-up info windows that show the timestamp and the distance from the previous track point.

I wrote it in Javascript because I wanted to be able to provide code you could play with without having to install additional infrastructure (languages, libraries, etc.). If you're writing a real tracker you probably don't want to do this, since it puts some computational and storage load on the user's browser (seriously, doing trigonometric calculations in a browser window doesn't seem like a great idea). It's cleaner and more efficient to do the computational work (including XML parsing) on the server side, in the language of your choice. Note that in the code below I'm grabbing the data from localhost. I made a local copy, since Spot only keeps your data for a week. If you're writing a real tracker you'll have to add local data storage and data management (de-duplication, for example) to your code. I've also left out all error-checking, data validation, etc., to keep the sample code compact and clean. If you're writing code for production use you must check to make sure that operations are successful, that the data you're getting are clean, etc. - if you're going to fail, fail gracefully. As an example of what I'm talking about, take a look at extract_gps_data, and notice that I'm making a lot of assumptions about what data are present and that the XML document hasn't been corrupted in some way - that's terrible programming practice. Checking for run-time errors and validating your data gives you control over what your users experience if something goes wrong. A program that "works" doesn't really work if it blows up on unexpected inputs.

So here's the code. Drop me a line if anything isn't clear, or if you notice a problem.