Delivering on Collaboration and UC: Presence

Presence is all the rage… the darling of the UC set! We are hearing how presence can really make your unified communications platform pop, but how does it work in line of business apps?

The initial business case for presence has largely to do with “Do I call this person now?” or “Should I bother this person now?” The value of presence is, for the most part, around shaving a few minutes off your day by knowing if someone is online.

I have always had an issue with the real value around the general use case of presence. I can justify a few minutes a day at most from this, vs just picking up a phone and calling anyway. In fact most of the UC bells and whistles help lubricate workflows but not to a very large degree. As I said, 5 minutes here, 10 minutes there.

In addition I found that the functions were available only in certain apps that were “supported” by whatever stack we used. For the most part this covers the Microsoft suite but beyond that, when it comes to real Business Line Apps, Microsoft is a direct competitor to a lot of the companies we use such as Oracle… and so you find that there is less support… and I am putting that kindly. Everyone wants to win and so everyone only supports their own…. so again, as with click-to-dial, we will roll-our-own…

In terms of presence functionality in SOAR, Microsoft has done a good job and has built the next-step into Lync – the ability to search for and see the presence of folks who you don’t know, and are not in your buddy list or emails. This essentially mimics some of what we did with SOAR at Cisco and is the start to producing real presence-based apps. Search in Lync for an expert and Click-to-X. It still misses in cross platform, geolocation, linking into our Oracle system (We don’t base expertise on Sharepoint) etc…

In delivering the core Business function of “Find an Expert”, I found there was a lot more at play and so the SOAR Expertise Locator also includes presence in several forms, to help you find a resource who is available and relevant.

What I class as presence information includes:

  • Basic presence (Green, Yellow, Red / Avalable, Busy, DND etc)
  • Extended presence (Status messages – “I am at the gym”, “On the phone”, “In a WebEx”)
  • Location information (From above sources plus Twitter and various other feeds)
  • Free/Busy from Microsoft Exchange
  • “Last device used” type information.

As with the Click-to-Dial workloads, there is a lot you can do with the presence information you get from varied sources. Aggregating them and weighting them based on when they changes, and on which devices, with which priority gives you a lot of insight. For example, using the most recent feed item gives you a pretty good idea as to someone’s presence:

  1. If someone is active at a computer, then presence is easy.
  2. When they step away, the XMPP/SIM/SIMPLE system may eventually show them as away.
  3. Now, if they close down their computer, depending on the system you have in place, you may loose them altogether. (Cisco does not have this issue, but what if they’re on a federated system?)
  4. They may well be available to take a phone call, however. How do we bridge that gap? How do we bridge it no matter what phone the user has? (Cordless, WiFi, SmartPhone, Cell)
  5. If we take a look into Exchange we may be able to see that they have a an appointment, so maybe they’re onsite, but unavailable.
  6. If they are scheduled in a WebEx, or in a Telepresence we also know where they may be and that they may specifically not be available for voice or other types of meetings.

As with click-to-dial, things can get more interesting… if they place a call from a mobile phone associated to the UC system, we may see them as “On The Phone” and know that they may well be available to take calls, but are simply not at a computer.
If they check in on a GPS device driving down the freeway, we know they are not onsite and may be available for calls only, not IMs or Texts.

A second, and more interesting facet of the equation for me was to do the actual search. If we deployed a full application on a desktop or native mobile client, we could do what most expert-search-plus-presence systems: Pull the list of matching experts and put them in a list. “Subscribe” to each of their presence feeds to check what their current status is, and then order them accordingly. Our goal was for the system to be available on any platform, and so by definition it needed to be web based, and function in multiple browsers.

Some facilities exist to do this within XMPP- by way of BOSH and JavaScript APIs that are available at developer.cisco.com, and we do use them, but once again for federated connections and SIP/SIMPLE they don’t exist. In addition if we wanted to aggregate more than just client presence we had some work to do. XMPP and the Javascript API do support locations, basic presence, advanced presence and extensibility but Cisco has not turned on the Location facilities internally yet, and I suspect you may find yourself in the same boat as me – wanting to aggregate more information (including calendaring information) into the Presence status. My next step will be turning around and publishing any additional data back into the XMPP presence “cloud” – which it is perfect for – hence the X – in eXtensible Messaging and Presence Protocol.

Once again for the SOAR initiative we did some pieces and not others:

  • All presence information along with timestamps is store in a database
  • A daemon on the server manages presence feeds from the XMPP/SIMPLE servers
    • This is an actual resource account, logging in and subscribing to presence for realtime feeds. It updates the database as necessary.
    • It also is a fantastic place for users to be able to IM changes, for example a user can IM the Expertise locator and say “I am in building 10”.
    • A widget to display Free/Busy information in any GUI elements also updates the DB.
  • We could not get good real-time information since Exchange does not support a
  • good method of doing this. I use WebDav to grab a day’s worth of information.
  • Location feeds come in from a variety of sources
    • Direct updates in presence messages
    • GeoTags in Twitter tweets and other social apps
    • Manual updates to the locator “Place me here”
    • Incoming IMs to set location.
  • WiFi triangulation from Cisco’s WiFi controllers (Which is not online in my tool yet)

As we all know from existing consumer apps, the more options we give users, the better – and that has proven the case with us here at Cisco. The more options, the “cooler” the app and the more likely users are to participate.

When a user does a search, we use the current presence information in the database to do the search and sort on, and so long as the daemon is running, its always up-to-date. This also facilitates more detailed apps we have running where business processes are kicked off or affected by presence (The example with the insurance adjuster)

Then, when we display jellybeans we use a simple <IMG resource – the source of the image is a script that renders a graphic depending on current presence. An upgrade to this, based on browser capability is to use the XMPP and BOSH to render jellybeans real-time in the browser, but since we have rendered the current-state presence we have no latency issues displaying initial presence. If BOSh is not available, we iterate through the jellybean DIVs every 15 seconds or so and refresh the graphics.

Reality Check: I had to work quite a bit on browser caching here. In general a simple <IMG SRC=”/userid.png”> was an issue because across browsers we would get a cached image. So, to alleviate this I highly recommend what we did – adding a bogus parameter that is simply the current time. So in the page we would put <IMG SRC=”/userid.png?t=2011053018233453″>

I also did a bit of caching on some of the original presence links, of which some are still in use. We have RESTful connectivity into the SIP/SIMPLE world of Cisco Unified Presence server. In that world, we have a few modes. We can RESTfully go get the current state, or register an HTTP callback. For the former, I implemented some caching instead of hammering the server. In the case of the latter, you get a RESTful callback when presence of any monitored object has changed. You never get another notification until you go and get the status of that object. So In this case I actually built in a delay, so that I potentially queued up presence changes before going and slamming the server. (The “wait time” I have set at around 3 seconds)

Presence also affects what options show in the contact card. For example if someone is on Do Not Disturb we don’t present a call option. If they are away, we display a camp-on option (that opens a window which refreshes and “watches” their presence state until they come back online).

There is a lot more interesting stuff in the Geolocation than in basic presence, in my view. With geofencing and other technologies, coupled with the WiFi triangulation of devices, we have a pretty interesting dataset we can work with.

Privacy and HR become another issue…

For those interested, an example Presence Perl Script (with goodies removed):

#!/usr/bin/perl
# Presence Pump Version 0.01a Test

# Takes XMPP Presence and feeds it to our DB via an HTTP call, which can be load balanced etc

use Proc::Daemon;
use utf8;
use AnyEvent;
use AnyEvent::XMPP::IM::Connection;
use AnyEvent::XMPP::IM::Presence;
use AnyEvent::XMPP::IM::Roster;
use AnyEvent::XMPP::Util qw/split_jid/;
use LWP::Simple;
use URI::Escape;
use Time::HiRes qw ( sleep );
use Net::SMTP;

Proc::Daemon::Init;

my $continue = 1;

$SIG{TERM} = sub { $continue = 0 };

@months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
@weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
$year = 1900 + $yearOffset;
$theTime = “$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$month] $dayOfMonth, $year”;
print $theTime;

my $j = AnyEvent->condvar;

# Enter your credentials here
my  $cl = AnyEvent::XMPP::IM::Connection->new (
jid              => ‘expertise.gen@cisco.com’,    # Modified for online use
password         => ‘passwordhere’,    # Modified for online use
host             => ‘serverhere.webexconnect.com’    # Modified for online use
);

# Functions
sub sendEmail {
$message=$_[0];

my $MailHost = “outbound.cisco.com”;
my $MailFrom = “nobody\@cisco.com.com”;# Modified for online use
my $MailTo = “nobody\@cisco.com”; # Modified for online use
my $subject = “Update from Expertise Locator Presence”;
my $MailBody = $message;

$smtp = Net::SMTP->new($MailHost);

# Send the From and Recipient for the mail servers that require it
$smtp->mail($MailFrom);
$smtp->to($MailTo);

# Start the mail
$smtp->data();

# Send the header.
$smtp->datasend(“To: $MailTo\n”);
$smtp->datasend(“From: $MailFrom\n”);
$smtp->datasend(“Subject: $subject\n”);
$smtp->datasend(“\n”);

# Send the message
$smtp->datasend(“$MailBody\n\n”);

# Send the termination string
$smtp->dataend();
$smtp->quit;

}

sub jd_subscribe {
$con = $_[0];
$target = $_[1];
print “SUB: “.$target.” “;

my $ro = $con->get_roster();
my $ec = $ro->get_contact ($target);
if($ec eq NULL){
print “New contact. “;
my $c=$ro->new_contact ($target, $target, “Locator”, sub { print “Subscribing to jid >” . $target . “<\n”; } );
}
my $ec = $ro->get_contact ($target);

if($ec ne NULL){
print “Got contact object. “;
$pending= $ec->subscription_pending();
if($pending){
print “Pending. Unsubscribing… “;
$ec->send_unsubscribe();
sleep (0.2);
print “Subscribing… “;
$ec->send_subscribe();
$posturl=”https://asset.cisco.com/presencepump/setsubscribestatus.php?userid=&#8221;.$target.”&status=pending”;
$contents=get($posturl);

}
else
{
$substat = $ec->subscription;

print “Status: “.$substat;
$posturl=”https://asset.cisco.com/presencepump/setsubscribestatus.php?userid=&#8221;.$target.”&status=”.$substat.””;
$contents=get($posturl);

if($substat eq ‘none’){
$ec->send_subscribe ();
}
if($substat eq ‘to’){
$ec->send_subscribed ();
}
if($substat eq ‘both’){
print “Full subscription for “.$target.”\n”;

}
if($substat eq ‘from’){
$ec->send_subscribe ();
}
}
}
print “\n”;

}

sub jd_unsubscribe {
$con = $_[0];
$target = $_[1];
my $ro = $con->get_roster();
delete_contact ($target, sub { print “Unsubscribing jid >” . $target . “<\n”; } );
}

sub jd_log {
$con = $_[0];
$msg = $_[1];
sendEmail($msg);

#  my $immsg = AnyEvent::XMPP::IM::Message->new (to => ‘jlaurens@cisco.com’, body => $msg);
#  $immsg->send ($con);
}

sub jd_process {
$con = $_[0];
$newsubs=0;
$posturl=”https://asset.cisco.com/presencepump/tosubscribe.php&#8221;;
$contents=get($posturl);
@users = split(/:/, $contents);
for my $user (@users) {
sleep (0.2);
jd_subscribe($con,$user.’@cisco.com’);
}
jd_log($con,”Done processing new subscriptions…”);

}

sub jd_remind {
$con = $_[0];
$newsubs=0;
$posturl=”https://asset.cisco.com/presencepump/pending.php&#8221;;
$contents=get($posturl);
jd_log($con,”Sending reminder IMs to those who have not accepted subscriptions.”);
@users = split(/:/, $contents);
for my $user (@users) {
jd_subscribe($con,$user.’@cisco.com’);
}
jd_log($con,”Done processing new subscriptions…”);

}

# Callback functions. Their are plenty more but here I have only included some as an example
# Also, remember that the Connection object ($con in my case), is
# always the first argument in the call backs. This is according to the documentation.

$cl->reg_cb (
session_ready => sub {
my ($con, $acc) = @_;
print “session ready\n”;
jd_log($con,’Expertise Bot has started up…:’.$theTime);
jd_process($con);
},
connect => sub {
print “Connected \n”;
},
message => sub {
my ($con, $msg) = @_;
if ($msg->any_body ne “”){
my ($user, $host, $res) = split_jid ($msg->from);
my $username = join(“”, $user,’@’,$host);
print “Message from ” . $username . “:\n”;
print “Message: ” . $msg->any_body . “\n”;
if($msg->any_body eq “MagicalQuitPhrase”){
jd_log($con,’Expertise Bot is quitting…’);
exit;
}

if($msg->any_body eq “remind”){
jd_log($con,’Start manually reminder processing…’);
jd_remind($con);

}

if($msg->any_body eq “process”){
jd_log($con,’Start manually launched processing…’);
jd_process($con);

}

my $sstring = $msg->any_body;
my $command=substr $sstring, 0 , 3;
if ($command eq “sub”){
my $fragment =  substr $sstring, 4;
jd_subscribe($con,$fragment);
}

my $command=substr $sstring, 0 , 5;
if ($command eq “unsub”){
my $fragment =  substr $sstring, 6;
jd_unsubscribe($con,$fragment);
}

print “\n”;
}
},
stream_pre_authentication => sub {
print “Pre-authentication \n”;
},
disconnect => sub {
my ($con, $h, $p, $reason) = @_;
warn “Disconnected from $h:$p: $reason\n”;
$j->broadcast;
exit;
},
error => sub {
my ($cl, $err) = @_;
print “ERROR: ” . $err->string . “\n”;
},
roster_update => sub {
my ($con, $roster, $contacts) = @_;
for my $contact ($roster->get_contacts) {
print “Roster Update: ” . $contact->jid . “\n”;
}
},
presence_update => sub {
my ($con, $roster, $contacts, $old_presence, $new_presence) = @_;
for my $cont ($contacts) {
if($pres = $cont->get_priority_presence ne undef){
$e_presence=uri_escape($new_presence->show);
$e_message=uri_escape($new_presence->status);
$posturl=”https://asset.cisco.com/presencepump/setpresence.php?userid=&#8221;.$cont->jid.”&presence=”.$e_presence.”&message=”.$e_message;

print $posturl.”\n”;
$contents=get($posturl);

} else {
$posturl=”https://asset.cisco.com/presencepump/setpresence.php?userid=&#8221;.$cont->jid.”&presence=Offline&message=”;
print $posturl.”\n”;
$contents=get($posturl);
}
}
},
message_error => sub {
print “error”;
}
);
$cl->connect();
$j->wait;

I am currently working on adding in some of the real-time presence capabilities provided by Cisco’s CAXL JavaScript API which allows us to embed real-time jellybeans into any browser that support JavaScript. At that point we will have several layers of capabilities around presence and embedded IM in the web page, as opposed to needing an IM client on the device.

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