This article describes the way how to enable and alter the device presence feature based on the RFCs 3265 – 3865 -3863 -4480. The feature leverages the built-in XML definitions capability of our D-series phones.
The only prerequisite is that the phone has firmware version 10.1.90.0 or higher.
Presence works on two fronts, like a normal BLF. The first one is the phone which has to send a SIP message indicating its status to the PBX. The second one is the monitoring phone which receives a SIP message from the PBX containing the status of the monitored phone. The difference is that the messages will not be of type DIALOG, but PRESENCE.
Part 1: Send the PUBLISH message
We use the setting: general_purpose_xml_descriptions to store the XML definition code without tying them to a specific key.
The following code works exclusively for Identity 1 (change the value of <identity value="1"/> to change the identity number). For more informations about XML definitions please check these pages: XML Definitions, XML Definitions Tutorial, XML Definitions Syntax
<general type="phone_status_xml"/>
<initialization>
<state value='off'/>
<identity value="1"/>
<variable name='presence_state' value='inital'/>
<variable name='basic_state' value='closed'/>
<variable name='person_id' value='intial'/>
<variable name='activity' value="<rpid:unknown/>"/>
<variable name="da" value="initial"/>
<reference name='account' module='setting' id='user_name[$(identity)]'/>
<reference name='domain' module='setting' id='user_host[$(identity)]'/>
<reference name='uuid' module='setting' id='user_uid[$(identity)]'/>
<reference name='ringnum' module='identity.$(identity)' id='ringing_number'/>
<reference name='phonestat' module='identity.$(identity)' id='phone_status'/>
</initialization>
<action>
<assign when="after initialization">
<source value="sip:$(account)@$(domain)"/>
<destination context="this entity" id="da"/>
</assign>
<assign when="on change" reference="phonestat" value_not_in="Alerting,Forwarded">
<source value="$(uuid)-$(identity)"/>
<destination context="this entity" id="person_id"/>
</assign>
<assign when="on change" reference="phonestat" value_in="Alerting">
<source value="Ring-$(ringnum)"/>
<destination context="this entity" id="person_id"/>
</assign>
<assign when="on change" reference="phonestat" value_in="Forwarded">
<source value="Forwarded"/>
<destination context="this entity" id="person_id"/>
</assign>
<assign when="on change" reference="phonestat" value_in="In_A_Call">
<source value="<rpid:on-the-phone/>"/>
<destination context="this entity" id="activity"/>
</assign>
<assign when="on change" reference="phonestat" value_not_in="In_A_Call">
<source value="<rpid:unknown/>"/>
<destination context="this entity" id="activity"/>
</assign>
<assign when="on change" reference="phonestat" value_in="Dnd_All">
<source value="<rpid:busy/>"/>
<destination context="this entity" id="activity"/>
</assign>
<assign when="on change" reference="phonestat" value_in="Offline">
<source value="closed"/>
<destination context="this entity" id="basic_state"/>
</assign>
<assign when="on change" reference="phonestat" value_not_in="Offline">
<source value="open"/>
<destination context="this entity" id="basic_state"/>
</assign>
<assign when="on change" reference="phonestat" value_in="Offline">
<source value=''/>
<destination context="this entity" id="presence_state"/>
</assign>
<assign when="on change" reference="phonestat" value_in="Dnd_All">
<source value="Do not disturb"/>
<destination context="this entity" id="presence_state"/>
</assign>
<assign when="on change" reference="phonestat" value_in="Available,Forwarded">
<source value="Idle"/>
<destination context="this entity" id="presence_state"/>
</assign>
<assign when="on change" reference="phonestat" value_in="Alerting">
<source value="Ring"/>
<destination context="this entity" id="presence_state"/>
</assign>
<assign when="on change" reference="phonestat" value_in="In_A_Call">
<source value="On the phone"/>
<destination context="this entity" id="presence_state"/>
</assign>
<publish when="on change" reference="phonestat" expires="300" target="$(da)" from="$(da)">
<body content_type="application/pidf+xml" event="presence">
<presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model" xmlns:rpid="urn:ietf:params:xml:ns:pidf:rpid" entity="$(da)">
<tuple xmlns="urn:ietf:params:xml:ns:pidf" id="$(uuid)-$(identity)">
<status xmlns="urn:ietf:params:xml:ns:pidf">
<basic>$(basic_state)</basic>
</status>
<note>$(presence_state)</note>
</tuple>
<dm:person id="$(person_id)">
<rpid:activities>$(activity)</rpid:activities>
<dm:note>$(presence_state)</dm:note>
</dm:person>
</presence>
</body>
</publish>
<publish when="on change" reference="phonestat" value_in="Offline" expires="0" target="$(da)"/>
</action>
|
With this code the phone automatically check its own status and, when the status change (when="on change"
), sends a PUBLISH type SIP message including the information in the message body XML code.
The possible statuses are:
- Offline
- Available
- In_A_Call
- Forwarded
- Dnd_All
This is an example of a PUBLISH message sent when the phone change from Available to In_A_Call. As you can see in the body, the phone built the XML code to inser <note>On the phone</note>. This information will be read from the PBX and translated into a NOTIFY message for the monitoring phones.
Sent to Udp:xxx from Udp:192.168.1.85:5060 at Jun 15 11:09:39.163 (1224 bytes):
PUBLISH sip:xxx SIP/2.0
Via: SIP/2.0/UDP 192.168.1.85:5060;branch=z9hG4bK-pebykx4s7s7u;rport
From: <sip:xxx>;tag=kja9amhabe
To: <sip:xxx>
Call-ID: d3a1a9624e27-7obccpq5b0zk
CSeq: 1 PUBLISH
Max-Forwards: 70
User-Agent: snomD785/10.1.101.11
Event: presence
Proxy-Authorization: Digest username="xxx",realm="xxx",nonce="414d535962a9a20a67:55e9afe4485dbc0f71f5b02f720d4376",uri="sip:xxx",response="dfca4547a8f49694ae3104a3efc860a2",algorithm=MD5
Expires: 300
Content-Type: application/pidf+xml
Content-Length: 598
<presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model" xmlns:rpid="urn:ietf:params:xml:ns:pidf:rpid" entity="sip:xxx">
<tuple xmlns="urn:ietf:params:xml:ns:pidf" id="5227a428-5444-4071-8c3d-0004139AC933-1">
<status xmlns="urn:ietf:params:xml:ns:pidf">
<basic>open</basic>
</status>
<note>On the phone</note>
</tuple>
<dm:person id="5227a428-5444-4071-8c3d-0004139AC933-1">
<rpid:activities><rpid:on-the-phone/></rpid:activities>
<dm:note>On the phone</dm:note>
</dm:person>
</presence>
Part 2: Receive and manage NOTIFY messages
On the monitoring phone we need a new type of key, able to process the incoming presence NOTIFY and to reach this result we will use the ReplacementPlan tag and specifically the <key> tag that defines a key-type that will get listed in fkey-WUI-page as type for a line-key
https://docs.snom.com/display/wiki/%3CReplacementPlan%3E+tag
After provisioning the Snom phone with the following code, we will see a new type of key in the fkey drop-down menu, called PresenceBLF. In the Number field we will inser the monitored extension and the phone will send a Presence type SUBSCRIBE for that extension.
Press the key to call the extension and call pickup are also possible.
Note: the pickup code is hard coded into the XML, you can change the code here:
<variable name="pickup_code" value="*8"/>
<?xml version="1.0" encoding="UTF-8"?>
<ReplacementPlan>
<key id="PresenceBLF">
<general type="PresenceBLF">
<default_state name="Closed"/>
</general>
<initialization>
<!-- set pickup code prefix -->
<variable name="pickup_code" value="*8"/>
</initialization>
<subscription type="presence" to="<sip:$(ui_argument)@>" for="$(ui_argument)@"/>
<NotifyParsingRules type="applies">
<level1 translates_to="OK">/presence[@entity="sip:$(ui_argument)@$(registrar)"]</level1>
</NotifyParsingRules>
<NotifyParsingRules type="state">
<level1 translates_to="Closed">/presence/tuple/status/basic[.="closed"]</level1>
<level2 translates_to="Forwarded">/presence/dm:person[@id="Forwarded"]</level2>
<level3 translates_to="Idle">/presence/dm:person/dm:note[.="Idle"]</level3>
<level4 translates_to="On_the_phone">/presence/dm:person/dm:note[.="On the phone"]</level4>
<level5 translates_to="Ring">/presence/dm:person/dm:note[.="Ring-"]</level5>
<level6 translates_to="Ring">/presence/dm:person/dm:note[.="Ring"]</level6>
<level7 translates_to="Do_not_disturb">/presence/dm:person/dm:note[.="Do not disturb"]</level7>
</NotifyParsingRules>
<action>
<assign type="update on change" when="after initialization">
<source context="setting" id="user_host[$(identity)]"/>
<destination context="this entity" id="registrar"/>
</assign>
<invite when="on press" states="Ring" target="$(pickup_code)$(ui_argument)"/>
<invite when="on press" states="Idle" target="$(ui_argument)"/>
<invite when="on press" states="Forwarded" target="$(ui_argument)"/>
<invite when="on press" states="Closed" target="$(ui_argument)"/>
</action>
</key>
</ReplacementPlan>
|
Thanks to the <NotifyParsingRules type="state">
section, the phone fetch the incoming NOTIFY message looking for a state at a predetermined point in the body of the message. The search is systematic from the first level to the last and when a rule is matched, the following ones are not considered.
The following is a NOFITY body example that match the level4 rule:
<?xml version="1.0" encoding="UTF-8"?>
<presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model"
xmlns:rpid="urn:ietf:params:xml:ns:pidf:rpid" entity="sip:104@registrar">
<tuple id="79uvNJuBMsWLcEa55Wdz44Ae0fepp5A5">
<status>
<basic>open</basic>
</status>
<note>On the phone</note>
</tuple>
<dm:person id="yTU74o-mb.pIeO.sBcrklfW7RovU5YvS">
<rpid:activities>
<rpid:on-the-phone/>
</rpid:activities>
<dm:note>On the phone</dm:note>
</dm:person>
</presence>