Delivering on Collaboration and UC: Geolocation

Its all about location, location, location…

I found that Geolocation was one of the more compelling aspects of our mashup. ts is simply easier for a user to find a resource on a map rather that to try figure out whether a resource listed in “Torrance, CA” is anywhere near the location “El Gato, CA”.

Also, Sales folks are incented based on their coverage. People have similar backgrounds and as a result better synergies when they live closer. Travel is obviously easier for a resource if they are closer… and as a general rule the result of this is that its best to engage the most local resource.

That being said, there is also a lot we can infer from Location too in order to make our contact card smarter…. Is the person in the office? At home? At a customer site? All these change the person’s availability as well.

What I did was to plot all users on a Google map, by getting their location in one of the following ways:

  • Geocoding using the address in the directory.
  • Allowing users to move the map, and then click an “I am here” icon.
  • Allowing users to link to FourSquare, Facebook or Twitter and checking those sites for updates.

First warning of Geolocation: Normalized directories may not help. I found that a lot of the issues we ran into with regards to location were to do with taking an address we had formatted in the directory, and converting it to a location. Google and others have geocoding APIs that fail when it comes to a lot of international addresses. Addresses are listed in differing orders in different countries, some have mailstops that look suspiciously like zipcodes, some order the name of the building before the street name. The problems are everywhere.

What I ultimately did was set up a simple “Wizard” that enrolled folks in the locator. A user logs in and is then run through several (but not too many!) screens:

  • Database basic entry is created with userid and defaults
  • Do you want to be a “discoverable” resource? (Opt in)
  • Do you want to be a “ratable” resource? (opt in)
  • Screen shown while pulling directory information “Please wait, Syncing with Directory”
  • Please zoom in on your home location to place yourself on the map
  • Done! Redirect to Mashup

The find yourself function is a basic google map, zoomed out tot he globe and with a simple callback function that stores latitude and longitude points and updates an “I am here” link – the same thing we do on the actual mashup when a user is signed up:

Essentially to allow users to use the mashup or the wizard to place themselves, I added a ‘mapcenter’ DIV on the page that would receive coordinates whenever the map moved:

GEvent.addListener(map, “moveend”, function() {
var center = map.getCenter();
document.getElementById(“mapcenter”).innerHTML = “<a href=’setloc.php?loc=” + center + “‘>I am here</a>”;
});

This takes care of the static placement of users, but we wanted to also allow them to link an existing Twitter, Facebook or Foursquare account to the mashup so that we could automatically track their location. Foursquare is good because it doesnt clutter my other timelines with “ramblings about location” and I like Facebook or Twitter depending who I am targeting. Either way the locator can get updates from all three…

Using a Web2.0 service to update location

Nobody wants yet another client so that they can plot themselves on some map. The wonder and power of Web2.0 is that we can leverage tools users already use to “Check in” with, and so I opted to link tot he top three services that support Geolocation.

To set up APIs, the process is similar on all… create an account, create an app and get back some keys to be able to do OAUTH with the sites and get keys. Those keys can then be used to log in and get log entries – which contain latitude and longitudes.

Facebook is a little different only in that it’s codes timeout a lot faster unless you sign up for offline_access, which I highly recommend.

The actual steps to the whole process are:

  • If the user is not connected (They have no OAUTH details in my OAUTH database) I show them a “Do you want to connect to Twitter/Facebook/Foursquare?” button.
  • When they click the button, I explain what will happen, the security etc and ask the user if they want to connect.
  • If yes, redirect them to the service authorization page. This is where the service will ask them if they’re okay with linking
  • If the user agrees, the service redirects back to my server with a “code” and I redirect the user back to the mashup. He or she is done, and I save the code.
  • Every so often, in the background I check to see if I have an access token to log in tot he user’s account with. The first time around I do not.
  • Since I have no access token, I use the “code” to hit the service’s OAUTH URL to get a token from the code. If successful, I save the token. If not, I remove the user from the database, essentially re-displaying the “Do you want to link to Service?” button.
  • Now that I have a token, use it to log in and get the Geolocation from the Tweets/Checkins
  • Rinse, repeat the last Background process every nn minutes

By way of example, here is the initial FourSquare code:

First entry point code – the page linked to by the “Connect to FourSquare” button for users:

<?php
require_once “settings.php”;
$redir=”https://foursquare.com/oauth2/authenticate?client_id=&#8221;.$oauth_clientid.”&response_type=code&redirect_uri=”.$oauth_callback;
if($redir!=”)header( ‘Location: ‘.$redir);
?>

Calback page (the page referenced by $oauth_callback):

<?php

require_once("/var/www/el/include.php");
require_once("/var/www/i_usersonly.php");
require_once("/var/www/location/foursquare/settings.php");
if($_GET['debug']!='')$debug=1; else $debug=0;


$code=$_GET['code'];
$redir="https://asset.cisco.com/el/";
	

$userid=$_SESSION['ciscoid'];

if($code!=''){

	$myquery="SELECT * from oauth where `userid`='".$ciscoid."' and `application`='foursquare'";
	$db_data=mysql_query($myquery);
	$row = mysql_fetch_array( $db_data );
	if($row==null){
		$mySQL= "insert into `oauth` (`token`,`tokensecret`,`userid`,`displayname`,`application`) values ";
		$mySQL.="('".$_GET['code']."',";
		$mySQL.="'',";
		$mySQL.="'".$ciscoid."',";
		$mySQL.="'none',";
		$mySQL.="'foursquare')";
		$db_data=mysql_query($mySQL) or die(mysql_error());
	}
	else
	{
		$mySQL= "update `oauth` ";
		$mySQL.="set `token`='".$_GET['code']."',";
		$mySQL.="`tokensecret`='' ";
		$mySQL.="where `application`='foursquare' and `userid`='".$ciscoid."'";
		$db_data=mysql_query($mySQL) or die(mysql_error());
	}


	
	$input="https://foursquare.com/oauth2/access_token?client_id=".$oauth_clientid."&client_secret=".$oauth_clientsecret."&grant_type=authorization_code&redirect_uri=".$oauth_callback."&code=".$code;
if($debug)echo '<BR>Getting: '.$input.'<P>';

	$ch = curl_init();
	$timeout = 5; // set to zero for no timeout
	curl_setopt ($ch, CURLOPT_URL, $input);
	curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 120);

	$buffer = curl_exec($ch);
	curl_close($ch);
if($debug)echo '<BR>Got: '.$buffer;
	$jobj = json_decode($buffer);
	if (isset($jobj->access_token)){
		$token = $jobj->access_token;
		if($debug)echo '<BR>Got token: '.$token;
			$mySQL= "update `oauth` ";
			$mySQL.="set `tokensecret`='".$token."' ";
			$mySQL.="where `application`='foursquare' and `userid`='".$userid."'";
			if($debug)echo '<BR>'.$mySQL;
			$db_data=mysql_query($mySQL) or die(mysql_error());
		} else {
			
			$token='';
			$mySQL= "delete from  `oauth` ";
			$mySQL.="where `application`='foursquare' and `userid`='".$userid."'";
			$db_data=mysql_query($mySQL) or die(mysql_error());
			}
	


	
}
if($debug==0)header('Location: '.$redir);
?>

In order to get new location data I call some code every few minutes to gather updates… it checks for the update along with checking the timestamp so that we make sure to only use newer entries than what we already have in the database… Foursquare seems to be trickiest with timezones…

<?php
include(“../include.php”);
include(“foursquare/settings.php”);

echo ‘Starting…<BR>’;
date_default_timezone_set(‘America/Los_Angeles’);

$stoprate=0;
$myquery=”SELECT * from `oauth` where `application`=’foursquare'”;
$db_data2=mysql_query($myquery);
while($row2 = mysql_fetch_array( $db_data2 )){
$userid=$row2[‘userid’];
$code=$row2[‘token’];
$tokensecret=$row2[‘tokensecret’];
echo ‘<P>USER: ‘.$userid.'<P>’;

if($tokensecret==”){
echo ‘Going to get ‘.$userid.’ with code: ‘.$code.’…’;
ob_flush();
flush();

$input=”https://foursquare.com/oauth2/access_token?client_id=&#8221;.$oauth_clientid.”&client_secret=”.$oauth_clientsecret.”&grant_type=authorization_code&redirect_uri=”.$oauth_callback.”&code=”.$code;

$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $input);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 120);

$buffer = curl_exec($ch);
curl_close($ch);
ob_flush();
$jobj = json_decode($buffer);
if (isset($jobj->access_token)){
$token = $jobj->access_token;
echo ‘Got a new access token: ‘.$token;
$mySQL= “update `oauth` “;
$mySQL.=”set `tokensecret`='”.$token.”‘ “;
$mySQL.=”where `application`=’foursquare’ and `userid`='”.$userid.”‘”;
$db_data=mysql_query($mySQL) or die(mysql_error());
} else {
echo $buffer;
exit;
$token=”;
$mySQL= “delete from  `oauth` “;
$mySQL.=”where `application`=’foursquare’ and `userid`='”.$userid.”‘”;
$db_data=mysql_query($mySQL) or die(mysql_error());
}
} else {
$token=$tokensecret;
echo ‘Using old access token: ‘.$token;
}

if($token!=”){
echo ‘<P>Getting data from FS with access token: ‘.$token.'<P>’;
$url = ‘https://api.foursquare.com/v2/users/self/checkins?limit=1&oauth_token=&#8217;.$token;
$curl_handle=curl_init();
curl_setopt($curl_handle,CURLOPT_URL,$url);
curl_setopt($curl_handle,CURLOPT_CONNECTTIMEOUT,2);
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,1);
$buffer = curl_exec($curl_handle);
curl_close($curl_handle);
echo ‘<P><B>’.$buffer.'</B>’;

$jobj = json_decode($buffer);

if(isset($jobj->meta->code))if($jobj->meta->code==401){
$mySQL= “delete from  `oauth` “;
$mySQL.=”where `application`=’foursquare’ and `userid`='”.$userid.”‘”;
$db_data=mysql_query($mySQL) or die(mysql_error());
}
else
{
if (isset($jobj->response->checkins->items[0]->venue->location->lat)){
$lat=$jobj->response->checkins->items[0]->venue->location->lat;
}
if (isset($jobj->response->checkins->items[0]->venue->location->lng)){
$lon=$jobj->response->checkins->items[0]->venue->location->lng;
}
if (isset($jobj->response->checkins->items[0]->createdAt)){
$createdAt=$jobj->response->checkins->items[0]->createdAt;
}
if (isset($jobj->response->checkins->items[0]->timeZone)){
$timeZone=$jobj->response->checkins->items[0]->timeZone;
}
$dateCreated=date (‘c’,$createdAt);
$longDate=$dateCreated.’ ‘.$timeZone;
echo ‘LD: ‘.$longDate.'<P>’;
$adjustedCreated=date (‘r’,strtotime($longDate));

if($lat<>”)if($lon<>”){
$sql=”select * from `mashup` where `devicename`='”.$userid.”‘”;
$db_check=mysql_query($sql);
$checkrow=mysql_fetch_array( $db_check );
$t_lastupdate = strtotime($checkrow[‘lastupdate’]);
$t_fsupdate= strtotime($adjustedCreated);
if ($t_fsupdate > $t_lastupdate) {
echo ‘Last update: ‘.$checkrow[‘lastupdate’];
echo ‘New location – updating mashup loaction…’;
$sql=”update `mashup` set `locsource`=’FS’,`lon`='”.$lon.”‘,`lat`='”.$lat.”‘,`lastupdate`=now() where `devicename`='”.$userid.”‘”;
$db_update=mysql_query($sql) or die(mysql_error());
} else echo ‘Foursquare ‘.$adjustedCreated.’ update is older than the last update in the mashup: ‘.$checkrow[‘lastupdate’].’…’;
}

}
} else echo ‘I have no access token…’;

}
echo ‘<P>Done…’;
?>

I am currently working on adding in some of the real-time presence capabilities provided by Cisco’s CAXL JavaScript API which will allow us to take the geolocation updates and push them back into the XMPP cloud so that any other Geo-aware apps that use XMPP can derive the location from the IM/Presence system

Back to index.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s