Jump to content

Hot-Desking with the Asterisk Database

+ 1
  chco's Photo
Posted Jun 08 2011 09:57 PM

Suppose you need people to be able to log in to any device and accept calls at that location, a feature known as hot-desking. The following excerpt below from the O'Reilly publication Asterisk Cookbook can help you do so.

[HotDesking]
; Control extension range using pattern matches

; Login with 71XX will logout existing extension at this location
; and log this device in with new extension.
; Logoff with 7000 from any device.
;

exten => 7000,1,Verbose(2,Attempting logoff from device ${CHANNEL(peername)})
   same => n,Set(PeerName=${CHANNEL(peername)})
   same => n,Set(CurrentExtension=${DB(HotDesk/${PeerName})})
   same => n,GoSubIf($[${EXISTS(${CurrentExtension})}]?
subDeviceLogoff,1(${PeerName},${CurrentExtension}):loggedoff)
   same => n,GotoIf($[${GOSUB_RETVAL} = 0]?loggedoff)
   same => n,Playback(an-error-has-occurred)
   same => n,Hangup()
   same => n(loggedoff),Playback(silence/1&agent-loggedoff)
   same => n,Hangup()


exten => _71XX,1,Verbose(2,Attempting to login device ${CHANNEL(peername)}
to extension ${EXTEN:1})
   same => n,Set(NewPeerName=${CHANNEL(peername)})
   same => n,Set(NewExtension=${EXTEN:1})

; Check if existing extension is logged in for this device (NewPeerName)
; -- If existing extension exists (ExistingExtension)
;    -- get existing device name
;       -- If no existing device
;          -- (login) as we'll overwrite existing extension for this device
;       -- If existing device name
;          -- logoff ExistingExtension + ExistingDevice
;             -- Goto check_device ---------------------------------------+
; -- If no existing extension exists                                      |
;    -- Check if existing device is logged in for this extension          |
;       (NewExtension) <-----------------------------------------------+
;       -- If existing device exists
;          -- Get existing extension
;             -- If extension exists
;                -- Logoff Device + Extension
;                   -- Login
;             -- If no extension exists
;                -- Remove device from AstDB
;                   -- Login
;       -- If no device exists for NewExtension
;          -- Login

; Tests:
; * Login 100 to 0000FFFF0001
; * Login 101 to 0000FFFF0001 (Result: Only 101 logged in)
; * Login 101 to 0000FFFF0002 (Result: Only 101 logged in to new location)
; * Login 100 to 0000FFFF0001 (Result: Both 100 and 101 logged in)
; * Login 100 to 0000FFFF0002 (Result: Only 100 logged into 0000FFFF0002
;                                      -- change locations)
; * Login 100 to 0000FFFF0001 (Result: Only 100 logged in)

   same => n,Set(ExistingExtension=${DB(HotDesk/${NewPeerName})})
   same => n,GotoIf($[${EXISTS(${ExistingExtension})}]?get_existing_device)

   same => n(check_device),NoOp()
   same => n,Set(ExistingDevice=${DB(HotDesk/${NewExtension})})
   same => n,GotoIf($[${EXISTS(${ExistingDevice})}]?get_existing_extension)
   same => n,NoOp(Nothing to logout)
   same => n,Goto(login)

   same => n(get_existing_device),NoOp()
   same => n,Set(ExistingDevice=${DB(HotDesk/${ExistingExtension})})
   same => n,GotoIf($[${ISNULL(${ExistingDevice})}]?login)
   same => n,GoSub(subDeviceLogoff,1(${ExistingDevice},${ExistingExtension}))
   same => n,GotoIf($[${GOSUB_RETVAL} = 0]?check_device)
   same => n,Playback(silence/1&an-error-has-occurred)
   same => n,Hangup()

   same => n(get_existing_extension),NoOp()
   same => n,Set(ExistingExtension=${DB(HotDesk/${ExistingDevice})})
   same => n,GoSubIf($[${EXISTS(${ExistingExtension})}]?
subDeviceLogoff,1(${ExistingDevice},${ExistingExtension}):remove_device)
   same => n,GotoIf($[${GOSUB_RETVAL} = 0]?loggedoff)
   same => n,Playback(silence/1&an-error-has-occurred)
   same => n,Hangup()
   same => n(remove_device),NoOp()
   same => n,Set(Result=${DB_DELETE(HotDesk/${ExistingDevice})})
   same => n,Goto(loggedoff)

   same => n(loggedoff),Verbose(2,Existing device and extensions have
been logged off prior to login)
   same => n(login),Verbose(2,Now logging in extension ${NewExtension}
to device ${NewPeerName})
   same => n,GoSub(subDeviceLogin,1(${NewPeerName},${NewExtension}))
   same => n,GotoIf($[${GOSUB_RETVAL} = 0]?login_ok)
   same => n,Playback(silence/1&an-error-has-occurred)
   same => n,Hangup()

   same => n(login_ok),Playback(silence/1&agent-loginok)
   same => n,Hangup()

exten => subDeviceLogoff,1,NoOp()
   same => n,Set(LOCAL(PeerName)=${ARG1})
   same => n,Set(LOCAL(Extension)=${ARG2})
   same => n,ExecIf($[${ISNULL(${LOCAL(PeerName)})} |
${ISNULL(${LOCAL(Extension)})}]?Return(-1))
   same => n,Set(PeerNameResult=${DB_DELETE(HotDesk/${LOCAL(PeerName)})})
   same => n,Set(ExtensionResult=${DB_DELETE(HotDesk/${LOCAL(Extension)})})
   same => n,Return(0)

exten => subDeviceLogin,1,NoOp()
   same => n,Set(LOCAL(PeerName)=${ARG1})
   same => n,Set(LOCAL(Extension)=${ARG2})
   same => n,ExecIf($[${ISNULL(${LOCAL(PeerName)})} |
${ISNULL(${LOCAL(Extension)})}]?Return(-1))
   same => n,Set(DB(HotDesk/${LOCAL(PeerName)})=${LOCAL(Extension)})
   same => n,Set(DB(HotDesk/${LOCAL(Extension)})=${LOCAL(PeerName)})
   same => n,Set(ReturnResult=${IF($[${DB_EXISTS(HotDesk/${LOCAL(PeerName)})}
& ${DB_EXISTS(HotDesk/${LOCAL(Extension)})}]?0:-1)})
   same => n,Return(${ReturnResult})


Hot-desking is a fairly common feature that is gathering increased traction as Asterisk systems are deployed because of the inherent flexibility the dialplan provides. Older, traditional PBX systems apply an extension number to either a line on the system or with a device itself. With Asterisk, we have the ability to apply dialplan logic and information stored in a local database (or external database) to determine where an extension rings. We could easily develop a system where an extension number does nothing but ring a cell phone, or a combination of devices (like in a paging system, or a group of sales agents).

In the dialplan provided for this example of hot-desking, we’ve allowed people to log in to any device by dialing 71XX where 1XX is the person’s extension number in the range 100 through 199. To log out the extension from the device, the user simply dials 7000 from the device to log out from. While it has made the dialplan and logic more complicated, the dialplan also takes into account other extensions already logged into a device someone wants to log in to, and automatically logs them out first. Additionally, if we were logged into another device previously and didn’t log out before changing locations, the dialplan will log the extension out from the other device first before logging it into the new location.

No external scripts or databases[2] have been employed, which helps demonstrate the flexibility of Asterisk. Let’s look at what happens when we log in an extension to a device that has no existing extension logged in.

[2] Although using an external database may actually have simplified the logic.


First we do our checks as described by the logic flow in the comment block in the code. Figure 2-1 shows the visual representation of what we’re checking for before logging the extension in.

Note: You’ll need to be aware we haven’t added any logic to authenticate callers. This may not be necessary, but, if so, you can add some additional logic using a caller authentication recipe. Additionally, we haven’t added any prompts notifying the callers that an existing extension is logged in prior to logging them out, as we wanted to keep the fundamental logic of the hot-desking application so you have a base to work with.

Figure 2-1. Login check logic

Attached Image


To log in extension 100, we’ll dial 7100, which will place the appropriate information into the AstDB: two rows located within the HotDesk family. After you’ve logged in, you can see the entries in the database by entering database show HotDesk from the Asterisk console:

*CLI> database show HotDesk
/HotDesk/0000FFFF0001                             : 100
/HotDesk/100                                      : 0000FFFF0001
2 results found.


The two entries are to provide a link between an extension→device and device→ extension. When logging off a device we’ll need to know what extension to remove from the database, but when dialing an extension we’ll need to know what device to call.[3] The flowchart in Figure 2-1 shows how we’ve performed our checks to help account for various situations. If we log in to a device, we have to make sure there wasn’t another extension already logged in, and if so, log it out first. Another situation is where we were logged into another device and moved somewhere else, and need to move locations, which means we have to log out our extension from the other device first. And because we have multiple entries associated with each login, we have to verify that we’ve removed and modified both entries.

[3] Because the AstDB is based on the usage of a family/key relationship, we need two entries and to keep them synchronized. This is a good reason why using an external relational database could actually simplify the hot-desking logic.


The following tests were performed to validate the logic used:
  • Login 100 to 0000FFFF0001
  • Login 101 to 0000FFFF0001 (Result: Only 101 logged in)
  • Login 101 to 0000FFFF0002 (Result: Only 101 logged in to new location)
  • Login 100 to 0000FFFF0001 (Result: Both 100 and 101 logged in)
  • Login 100 to 0000FFFF0002 (Result: Only 100 logged into 0000FFFF0002—change locations)
  • Login 100 to 0000FFFF0001 (Result: Only 100 logged in)


Using these tests, you can then step through the logic and look at the dialplan to understand all the checks going on, and validate that things are working as they should.

Warning: It is possible that if two people attempt to log in to the same extension at the same time, or if someone else is logging into a device that was previously logged into by an extension moving locations (and attempting to log in at the same time as the other person) that the database could get out of sync. No locking has been performed here in order to keep the logic as clean and simple as possible. If there exists a strong possibility of people changing locations and logging in and out often on top of each other, then you may wish look into adding dialplan locking, which can be done using the LOCK() and UNLOCK() dialplan functions.

In more than one situation, the promise of hot-desking being just one more feature of the system is what eventually convinced a company to go with Asterisk because hot-desking was the killer application they were looking for.

Asterisk Cookbook

Learn more about this topic from Asterisk Cookbook.

Asterisk has a wealth of features to help you customize your PBX to fill very specific business needs. This short cookbook offers recipes for tackling dialplan fundamentals, making and controlling calls, and monitoring channels in your PBX environment. Each recipe includes a simple code solution you can put to work immediately, along with a detailed discussion that offers insight into why and how the recipe works.

See what you'll learn


Tags:
0 Subscribe


0 Replies