Monthly Archives: February 2015

Enabling Group Paging on Polycom VVX Phones for Lync or Skype

Paging is not a native feature for Microsoft Lync, and as such, we rely on third party solutions for this feature.  Typically overhead paging is accomplished by either using a device like the SNOM PA-1, or by using an analog FXS port connected to a universal paging system.  For speakerphone paging we have to rely on the desk phone’s capabilities.

The Polycom VVX series of phones is capable of speakerphone or group paging, but it is not enabled by default.  There are a few things to keep in mind when enabling group paging.  The first is that the paging groups exist only within the VVX phones themselves, they do not transfer over to Lync and therefore will not be heard through the Lync clients.  If you were to need that feature, you should just send an instant message.  Second, Polycom uses a multicast address for group paging to function.  This means pages are broadcast and may not work outside of the subnet or VLAN the phone is on if you’re not forwarding these multicast packets to different VLANs.

Let’s now start with a basic VVX config file, all we’re doing is enabling the feature and adding an outbound caller ID of sorts.

<localcfg>
   <ptt 
     ptt.pageMode.enable="1" 
     ptt.pageMode.displayName = "Your Name Here"
   />
</localcfg>

The line ptt.pageMode.enable turns on the group paging feature, the ptt.pageMode.displayName turns on an outbound caller ID.  Without  the displayName setting, we’re likely to get the phone’s MAC address showing up on other phones.

To test your configuration outside of the provisioning server, you can upload it directly to the phone’s website as seen in the below picture:

upload

To upload your configuration, navigate to your phone’s web page, go to Utilities -> Import & Export Configuration.  Click choose file to find the file you just created and click Import.

On the phone, you’ll now see a Paging button.

Paging1

If you click the Paging button, you’ll see a menu of groups you can send pages to.  These are the default groups.  Later when we add more groups, you could potentially scroll down a list.  Each paging group can be set to one of three priorities.  The default group setting and default setting for other groups you may create is the “Normal” priority, this means that a page won’t play during a call, but you may have the option to hear it if you choose.  There’s a built in priority group with the “Priority” priority, which is weird to say but basically this will interrupt normal pages and active calls.  Finally, there’s the built in Emergency group with the “Emergency” priority.  This will interrupt normal and priority pages, active calls, play at near maximum volume and play even if Do Not Disturb is turned on.

paging2

If we hit a button, 1 through 4 or hit the Page button, our page will start.

paging3

Everyone not currently in a call on the phone, assuming we made a call to the default group, will hear your voice over their speakerphone with no additional action.

Let’s now take it a step further, let’s add more groups and assign specific users to them. We’ll modify our old config a bit and add two groups, Sales and Accounting.

<localcfg>
   <ptt 
     ptt.pageMode.enable="1" 
     ptt.pageMode.displayName = "Your Name Here"

     ptt.pageMode.group.2.available="1"
     ptt.pageMode.group.2.allowTransmit="1"
     ptt.pageMode.group.2.label="Sales"
     ptt.pageMode.group.2.subscribed="1"

     ptt.pageMode.group.3.available="1"
     ptt.pageMode.group.3.allowTransmit="0"
     ptt.pageMode.group.3.label="Accounting"
     ptt.pageMode.group.3.subscribed="1"
   />
</localcfg>

In the above example, group 2 is sales. We’ve made it available to the phone with ptt.pageMode.group.2.available, we’ve labeled it “Sales” with ptt.pageMode.group.2.label, we’ve subscribed the user to it so they can hear it with ptt.pageMode.group.2.subscribed, and we’ve allow them to send calls to it with ptt.pageMode.group.2.allowTransmit.  In our example, group 3 is very similar, but we set allowTransmit to 0, meaning that we can listen to pages, but we can’t transmit.

To grant these settings for all or individual phones, we could use our standard Polycom provisioning methods as found in Jeff Schertz’ Blog on Provisioning Polycom SIP Phones: http://blog.schertz.name/2013/05/provisioning-polycom-sip-phones/.  If we’re going to just use the web interface as you saw above, there’s a much easier way.

To manage all of this through the browser, navigate to your phone’s web page, go to Settings -> Paging/PTT Configuration and behold:

websitepaging1

To see the groups we’ve created above, click the Configure Groups button.

websitepaging2

 

Much easier right?  Well, maybe for a small number of phones.

One last gotcha, you’ll notice that paging is only available on the Idle screen, and if you pick up the handset first and then want to page, there’s no option for it.  Stay tuned for the next blog post where I’ll walk you through creating a button on the phone that can handle this as well as paging the default group automatically.

QuickTip: Get-CSConferencingServer for Lync or Skype

As you might know, many of my posts arise out of common questions seen on TechNet. This is one such post.

The question is: There’s a command for Set-CSConferencingServer, but now that I made my changes, how do I see them?  There’s no Get-CSConferencingServer command!

Not all Lync PowerShell commands are created equally, and this is one of those commands that is a bit different.  The equivelant command to Get-CSConferencingServer you’re looking for is:

Get-CsService -ConferencingServer

 

2015-02-18 09_53_59-hqlync13fe01 (172.25.1.34) - Remote Desktop Connection Manager v2.7

Lync – Tracking Response Group Logins

Disclaimer:  This article is a journal of my experiences solving a particular problem, it is not suggesting that you should follow my approach and I cannot say doing so wouldn’t cause serious issues on your system.  As with anything you find on the Internet, take it with a grain of salt and don’t blindly run code or follow advice without doing your own research first.  Employ at your own risk.

Microsoft does not offer a native contact center option with Lync/Skype.  Instead, they’ve made it easy for third party vendors to integrate with Lync using the available SDKs.  This gives us a best of breed approach, allowing for many contact center vendors to exist and giving you the ability to choose from disruptive startups to very mature firms that have been around for 20+ years.

There are numerous benefits to a full contact center solution including real time monitoring and dashboards, pre-built reporting, call recording, callers hearing their position in the queue, you get the picture.  There is also a cost associated with all of this.  Before we get too far off track, the intention of this article isn’t to sell you on a contact center, it’s to help those who don’t need a full contact center solution but want a touch more than what comes in the box.

Lync does offer response groups that can route calls in a serial, parallel, round robin, or longest idle fashion.  These groups can be set as “formal” allowing users to log in and out via a web portal as seen in Figure 1 below.  Further, Lync logs answered calls into an LcsCDR database when monitoring is deployed.  What I’ve found on occasion are clients that don’t need a full call center, just stronger reporting around call flow into response groups.  In response to this, I’ve written several reports that monitor agent availability, wait time before answer, abandoned (to another queue or voicemail) calls, average call time, calls per agent.  All of that is available in the databases, you just need to write the report to suit your needs.

Signin

Figure 1 – Lync Response Group Sign-in Web Portal

One item that is lacking, is the ability to monitor agent’s break time and how long they were logged into the queues.  This information can be key when reviewing agent performance.  Knowing how many calls the agent answered without knowing how long they were available to receive calls gives an incomplete picture.  Unfortunately, within the Lync databases we can only see if a user is or isn’t logged into a response group queue using the AgentGroupSignInStates table in the rgsdyn database.   Agents are marked with a 0 or 1 to represent logged out or in, respectively.

RGSigninStates

Figure 2 – AgentGroupSignInStates Table

To overcome this, what I’ve used in the past is a SQL trigger.  Before we go any further, I want you warn you that if you opt to use this method, you’ll need to understand the pros, cons, and risks of using triggers.  Used or written improperly, they can cause performance and other issues.  One reason for this is because a trigger is basically a procedure that executes when an event such as an INSERT, UPDATE, or DELETE occurs within a table.  If you have a heavily written table, you’re going to have a heavily executed procedure.  That said, in the environments where I’ve deployed this, there are a minimal number of agents (40 as seen in the above figure) and table events usually total 2-6 per day per agent.

The trigger I employ basically writes the login and logout times to a simple table.  Those times can later be added to a report to show total login time, or a simple audit of login/logout.  To start, let’s create the table.

USE [rgsdyn]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[RGAgentSessions](
 [AgentId] [uniqueidentifier] NOT NULL,
 [GroupId] [uniqueidentifier] NOT NULL,
 [LoginDate] [datetime] NOT NULL,
 [LogoutDate] [datetime] NULL
) ON [PRIMARY]

GO

RGAgentSessions

Figure 3 – RGSAgentSessions Table Created

The table I’ve created exists in rgsdyn because that’s where our AgentGroupSignInStatesTable exists and it’s easy for me to reference later in SQL calls.  You may prefer it in the LcsCDR database.  Four fields are added, the AgentID and GroupID to uniquely identify the agent and group represented, and the login and logout date/time.  On it’s own, we’ve got an empty table.  With the trigger, it begins to populate as users sign in and out.  I’ll create the trigger now.

USE [rgsdyn]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[Trigger1] On [dbo].[AgentGroupSignInStates] AFTER INSERT, UPDATE
AS 
SET NOCOUNT ON 

IF (SELECT State FROM inserted) = 0 BEGIN
 UPDATE dbo.RGAgentSessions SET LogoutDate=GETDATE() WHERE
 LogoutDate IS NULL AND
 AgentId=(SELECT AgentId FROM inserted) AND
 GroupId=(SELECT GroupId FROM inserted) AND
 LoginDate=(SELECT Max(LoginDate) FROM dbo.RGAgentSessions where AgentId=(SELECT AgentId FROM inserted) and GroupId=(SELECT GroupId FROM inserted))
END
ELSE BEGIN
 INSERT INTO dbo.RGAgentSessions
 SELECT AgentId,GroupId,GETDATE(),NULL
 FROM INSERTED 
END

GO

RGTrigger

Figure 4 – The Trigger Code

The code watches INSERT and UPDATE modifications to the AgentGroupSignInStates table.  This is the table above where we can see the 1 or 0 state for each agent per group.  When a new row is added to the table (INSERT), or an agent toggles their login state (UPDATE), our trigger will spot it using the below line and the rest of our code will execute.

CREATE TRIGGER [dbo].[Trigger1] On [dbo].[AgentGroupSignInStates] AFTER INSERT, UPDATE

The meat of the code  has an IF statement that watches the State field from the original table. If we see any value other than 0, we consider it a login and create a new record writing the current time as the login time and a logout time of NULL.  This is in the ELSE portion of the code below.

If we see a 0 it means the agent must have just logged out of the response group, setting the state field in the original table to 0.  We’ll then search for the last login record matching that agent and group and put the current time in as the logout.

IF (SELECT State FROM inserted) = 0 BEGIN
 UPDATE dbo.RGAgentSessions SET LogoutDate=GETDATE() WHERE
 LogoutDate IS NULL AND
 AgentId=(SELECT AgentId FROM inserted) AND
 GroupId=(SELECT GroupId FROM inserted) AND
 LoginDate=(SELECT Max(LoginDate) FROM dbo.RGAgentSessions where AgentId=(SELECT AgentId FROM inserted) and GroupId=(SELECT GroupId FROM inserted))
END
ELSE BEGIN
 INSERT INTO dbo.RGAgentSessions
 SELECT AgentId,GroupId,GETDATE(),NULL
 FROM INSERTED 
END

In time as users log in and out of the formal response groups, data will populate as you can see in figure 3.  The example above has now been in place for three years and has moved from Lync 2010 to 2013 without issue.  The data is used in different ways within customer Lync SSRS reports, typically showing hours and minutes logged in per time range selected.  Exporting the data for simple auditing can be useful as well.

If you have a more efficient method of storing this data, or just want to correct my horrible SQL, please reach out and let me know!  Thanks for reading!