Presence of mind
Jabber is so last decades. Webex and its competition are the best modern means of messaging. But Cisco IM&P, a companion server to Cisco Call Manager, is still the best way to subscribe to user presence updates.
Suppose you have a group of employees to whom you assign tasks as they come in. If you can watch the presence of that group, you’ll know who is available, who is away, who is on the phone, etc. You can build an application that automatically assigns tasks according to the presence of the users.
The Presence Web Services (PWS) API, a feature of Cisco IM&P, is ideal for this kind of application. In my experience as a former developer support engineer, I noticed many developers don’t quite understand how to use PWS properly. I hope that by the time you’re done reading this, you’ll have a good grasp of everything involved in making PWS work for you.
Here’s a condensed breakdown of the steps:
- Log in an application user with app username and password
a. This operation returns the application user session key
- Use the application user session key to log in an end user
a. This operation returns an end user session key
- Create a web service to handle presence notifications
a. Run this web service to listen on a common port, e.g., 8080
- Use the application user session key to register the URL of your web service as an endpoint
a. This returns an endpoint ID
- Use the end user session key to subscribe to one or more end user contacts
a. This returns a subscription ID
- Create a script to fetch the subscribed presence, using the subscription ID
a. For example, get_subscribed_presence.py
In steps 1 and 2, there’s a choice called “force=”. If you set “force=true”, the server will return a new session key every time. I recommend you use “force=false”, so that it keeps re-using the same session key. This covers a multitude of programming sins.
In Step 3, it is important to use a common port, like 80, 82, 8080, etc. If your web service is based on Python and you use the Flask library, the default port for Flask is 5000, which will not work. You must tell flask to use one of the common ports, instead.
Once you have completed steps 1 through 5, any change in the presence of the contacts in your step 5 subscription will trigger a REST GET operation on the endpoint. The GET will pass two parameters: The subscription id which should always be 1 with these scripts, and etype, which should always be “PRESENCE_NOTIFICATION”.
Your application should then use the subscription ID to fetch all the presence changes for that subscription. The API for that is getSubscribedPresence. The script that invokes getSubscribedPresence is, coincidentally, get_subscribed_presence.py.
The sample scripts use REST, but you can also use SOAP.
A common problem occurs when you run your endpoint after a contact’s presence already changed. The server will send a presence notification to the endpoint, but the endpoint isn’t running, so that notification never gets to the endpoint, and the endpoint doesn’t fetch the subscribed presence information. This is a problem because, if for any reason you don’t fetch the presence values on that subscription, the server will stop sending future notifications until you do.
So, the script you create in Step 6 is a fail-safe. Suppose a contact, Carlotta Tendant, switches from AVAILABLE to AWAY. The server will notify the web service at the endpoint URL that a change in presence occurred. If your endpoint isn’t active, or it does not pick up the notification and fetch the presence information, the server will stop sending presence notifications until you fetch that presence information.
It is important to know that the presence notification doesn’t send any contact information or the fact that Carlotta is now AWAY; it just notifies the web service that a presence has changed for one or more contacts for that subscription. Your web service must fetch the information about the contact and the contact’s presence.
To avoid the possibility of missed notifications, run the get_subscribed_presence.py script once everything is set up and ready and your endpoint is running. This grabs the information for the users and their presence, and thus clears the queue for the server to send new presence notifications.
There is another reason the web service may not receive a notification. If the Cisco IM&P server CPU usage reaches 80% or higher, the server stops sending notifications until the CPU usage drops below 80%. Here’s how to compensate for that possibility. Write your app to perform a get subscribed presence at an interval of every 10 minutes (or whichever seems best), just to make sure that if, for any reason, your application did not act on a presence notification, the queue will clear, and notifications will continue.
WARNING: Don’t use my sample scripts on a production server. These are for instructional purposes only.
My sample scripts are as follows:
And there are some data files the script uses to get information about the server, the host for the endpoint, app user, end user, and the contacts for your presence subscription.
serverparams.json (points to your Cisco IM&P server and the host IP address for the endpoint)
appuser.json (has the application username and password)
enduser.json (has the end user name. You use the session key from your application user login)
contacts.list (the list of contacts for which you will subscribe to get presence notifications)
Here’s how you run the scripts, in order.
- python3 pws-delete.py
- This removes all endpoints and subscriptions so you can start fresh
- python3 pws-create.py
- This sets up the endpoint and subscribes to the presence of contacts in list. It uses serverparams.json to identify your Cisco IM&P server and the IP address of the host where your endpoint will run.
- python3 endpoint.py
- This is the endpoint script. It uses the Flask Python library to work as a web service.
- python3 get_subscribed_presence.py 1 BASIC_PRESENCE (or RICH_PRESENCE)
- You run this after the endpoint web service is up and running. This clears out any pending subscription updates and notifications so that the queue is empty and future notifications will work.
If you look at the code in the sample endpoint script, for the web service endpoint doesn’t include the code to fetch the subscription presence. I put all that into the get_subscribed_presence.py script. My endpoint simply executes the script externally like so:
subprocess.run("python3 get_subscribed_presence.py "+id+" "+etype, shell=True) The endpoint will know the value of id and etype and pass the values when it runs get_subscribed_presence.py. If you want to run the script yourself, however, you need to pass values at the command line, for example:
python3 get_subscribed_presence.py 1 BASIC_PRESENCE
You can also use RICH_PRESENCE instead if that’s what you want. If you’re done everything correctly, the subscription id will always be 1, which is why you pass the number 1 to the script at the command line.
The sample script doesn’t do anything with the presence information. It prints it to the console where you run the endpoint web service. Your application must perform your needed task, such as updating a display of contacts and their presence.
We’d love to hear what you think. Ask a question or leave a comment below.
And stay connected with Cisco DevNet on social!