Asterisk func device_State


--Original page content moved from DEVSTATE() wiki page


Get or Set a device state
Introduced in Asterisk 1.6 as DEVICE_STATE(), with a backport available for 1.4 as DEVSTATE().


The DEVICE_STATE function can be used to retrieve the device state from any device state provider.
is the current way to get a devices state.

For example:

NoOp(SIP/mypeer has state ${DEVICE_STATE(SIP/mypeer)})
NoOp(Conference number 1234 has state ${DEVICE_STATE(MeetMe:1234)})

The DEVICE_STATE function can also be used to set custom device state from the dialplan. The "Custom:" prefix must be used.
For example:


You can subscribe to the status of a custom device state using a hint in the dialplan:

exten => 1234,hint,Custom:lamp1
exten => 12345,hint,confbridge:MyConfName ; requires Asterisk 1.8 with ConfBridge()

The possible values for both uses of this function are:


Asterisk 1.6.1.x: The event infrastructure in Asterisk got another big update to help support distributed events. It currently supports distributed device state and distributed Voicemail MWI (Message Waiting Indication). A new module has been merged, res_ais, which facilitates communicating events between servers. It uses the SAForum AIS (Service Availability Forum Application Interface Specification) CLM (Cluster Management) and EVT (Event) services to maintain a cluster of Asterisk servers, and to share events between them. For more information on setting this up, see doc/distributed_devstate.txt.


  • Make sure you know what will happen after an Asterisk restart! It might be necessary to use a .call file (or the Asterisk manager API) to call the DevState application right after Asterisk has started to ensure correct LED status. Note that, before doing so, you might also have to reboot or initialize the phones in question so that they can renew their SIP subscription of the extension that is used to monitor the devicestate; for example SIP NOTIFY could be used for that purpose (see sip_notify.conf).

  • For Asterisk 1.8, you must set callcounter=yes in sip.conf general section or the specific device you want to monitor. Without this setting DEVICE_STATE will return NOT_INUSE.

Example of using DEVICE_STATE for call-limit

Because call-limit is deprecated, sometimes you will need to make sure that, if an extension is in use, you will not call it.
The following dialplan entries make sure that extension 100 has only one call at a time.

exten => 100,1,ExecIf($[ ${DEVICE_STATE(SIP/${EXTEN})} = INUSE ]?Busy)
exten => 100,2,Dial(SIP/${EXTEN})

Example for controlling BLF lights:

See http://www.voip-info.org/wiki/view/Asterisk+day+night+mode+example
Also see How to use custom device states to control BLF lamps

Example to monitor the use of a ISDN BRI trunk (external SIP-to-ISDN gateway)

The example below uses Asterisk 1.4 with a patched-on func_devstate and is made for a single BRI with 2 lines.
It can most easily be adapted to monitor a VoIP trunk, or a mixed LCR-type setup with both ISDN and VoIP.

Not yet taken care of:
  • undirected pickup via *8 (directed PickUp() you will need to handle yourself in the dialplan)
  • transfers

; — outbound call via our SIP-ISDN gateway --
exten => _0X.,1,Set(GROUP()=ISDN)
exten => _0X.,2,Macro(trunk-devstate,RINGINUSE)
; use the Dial() option M() to change the BLF from RINGINUSE to INUSE once the call was answered
exten => _0X.,3,Dial(SIP/${FILTER(0-9,${EXTEN})}@isdn_gateway,60,M(trunk-devstate^INUSE))
... Fallback route
Use VoIP instead of ISDN so cancel the ISDN group and reset BLF ...
exten => _0X.,n,Set(GROUP()=VOIP)
exten => _0X.,n,Macro(trunk-devstate,REDUCE) ; we could also use NOT_INUSE instead
exten => _0X.,n,Dial(SIP/${FILTER(0-9,${EXTEN})}@voip_carrier,60)
exten => _0X.,n,HangUp

; — inbound call from ISDN --
exten => 987203,hint,SIP/myDevice
exten => 987203,1,Set(GROUP()=ISDN)
exten => 987203,n,Macro(trunk-devstate,RINGING)
exten => 987203,n,Answer(700)
exten => 987203,n,Dial(SIP/myDevice&Local/204,25,M(trunk-devstate^INUSE)
exten => 987203,n,HangUp

; — internal extension --
exten => 204,hint,SIP/myWireless
; watch out for variable inheritance from the Local channel (that will auto-destroy itself)
exten => 204,1,NoOp(-- Value of BLF_LINE: ${BLF_LINE} --)
exten => 204,n,Wait(10)
exten => 204,n,Dial(SIP/myWireless,15,M(trunk-devstate^INUSE))
exten => 204,n,HangUp

; subscribe to these extensions in order to watch the BLF light up and blink
exten => 301,hint,Custom:isdn1
exten => 302,hint,Custom:isdn2

; — general hang up handling --
The lines below must also be copied into every context or macro (!) along the call's way
exten => h,1,NoOp(-- Caller hung up --)
exten => h,n,Set(CALLEND=1)
exten => h,n,Macro(trunk-devstate,REDUCE)
exten => h,n,NoOp(-- ISDN line 1: ${DEVSTATE(Custom:isdn1)} - ISDN line 2: ${DEVSTATE(Custom:isdn2)} --)

; Control BLF for both inbound and outbound calls on our trunk with one LED for each ongoing call
; Any new call must set the group to "ISDN" before coming here!
new status (see below) or REDUCE
; The possible values for the DEVSTATE function are:
exten => s,1,NoOp(-- ISDN line 1: ${DEVSTATE(Custom:isdn1)} - ISDN line 2: ${DEVSTATE(Custom:isdn2)} --)
exten => s,n,NoOp(-- Dialstatus: ${DIALSTATUS} - Hangupcause: ${HANGUPCAUSE} --)

; the next line also helps if we are out-of-sync for whatever reason
exten => s,n,ExecIf($["${GROUP_COUNT(ISDN)}" = "0"]|Set|DEVSTATE(Custom:isdn1)=NOT_INUSE)
exten => s,n,ExecIf($["${GROUP_COUNT(ISDN)}" = "0"]|Set|DEVSTATE(Custom:isdn2)=NOT_INUSE)
exten => s,n,ExecIf($["${GROUP_COUNT(ISDN)}" = "0"]|MacroExit)

; At this point we have to slightly delay the execution to make sure that a Local channel hangup is
; faster here than a successful connect. In case of a multi-dial, example "Dial(SIP/123&Local/456)":
; The local channel will cancel the BLF LED because someone else answered, but the user that answered
; will then want to set it (again)!
; For a call that was just answered DIALSTATUS is -empty- and Hangupcause is 16 (normal clearing)
; Speed up the wrapping up, call this with macro ARG1 = REDUCE
exten => s,n,GotoIf($["${CALLEND}" = "1"]?reduce)
; make sure Local channel hangup is faster than the channel that answered with a Dial() macro
exten => s,n,ExecIf($[$["${DIALSTATUS}" = ""] & $["${CALLEND}" != "1"]]|Wait|.1)

; first determine if we assign a new call to BLF LED button 1 or to LED button 2 (channel variable)
; if we happen to run out of BLF_LINE slots then the caller is simply not going to get one
; we use a double underscore __ in front of BLF_LINE hoping to cover also subsequent transfers
; The very presence of this the BLF_LINE variable is used to identify an ISDN call
exten => s,n,ExecIf($[$["${BLF_LINE}" = ""] & $["${DEVSTATE(Custom:isdn1)}" = "NOT_INUSE"]]|Set|__BLF_LINE=1)
exten => s,n,ExecIf($[$["${BLF_LINE}" = ""] & $["${DEVSTATE(Custom:isdn2)}" = "NOT_INUSE"]]|Set|__BLF_LINE=2)
exten => s,n,ExecIf($[$["${BLF_LINE}" = ""] & $["${DEVSTATE(Custom:isdn1)}" = "UNKNOWN"]]|Set|__BLF_LINE=1)
exten => s,n,ExecIf($[$["${BLF_LINE}" = ""] & $["${DEVSTATE(Custom:isdn2)}" = "UNKNOWN"]]|Set|__BLF_LINE=2)

; clear the device state for a specific BLF LED
exten => s,n(reduce),ExecIf($[$["${BLF_LINE}" = "1"] & $["${ARG1}" = "REDUCE"]]|Set|DEVSTATE(Custom:isdn1)=NOT_INUSE)
exten => s,n,ExecIf($[$["${BLF_LINE}" = "2"] & $["${ARG1}" = "REDUCE"]]|Set|DEVSTATE(Custom:isdn2)=NOT_INUSE)

; assign any other device state
exten => s,n,ExecIf($[$["${BLF_LINE}" = "1"] & $["${ARG1}" != "REDUCE"]]|Set|DEVSTATE(Custom:isdn1)=${ARG1})
exten => s,n,ExecIf($[$["${BLF_LINE}" = "2"] & $["${ARG1}" != "REDUCE"]]|Set|DEVSTATE(Custom:isdn2)=${ARG1})

; If user hangs up while we are in this macro then the h extension of the calling context will not be executed!
The lines below must also be copied into every context or macro (!) along the call's way
exten => h,1,NoOp(-- Caller hung up in the middle of macro execution --)
exten => h,n,Set(CALLEND=1) ; in hung-up state Asterisk does not like the Wait() used above
exten => h,n,Macro(trunk-devstate,REDUCE) ; call ourselves again
exten => h,n,NoOp(-- ISDN line 1: ${DEVSTATE(Custom:isdn1)} - ISDN line 2: ${DEVSTATE(Custom:isdn2)} --)

Outdated example with MeetMe for the old app_devstate (now turned into a function)

exten => 1234,hint,DS/1234
exten => 1234,1,DevState(1234,2) ; == solid , or 1234,6 for blinking
exten => 1234,2,Meetme(1234)
exten => 1234,3,Hangup

exten => h,1,DevState(1234,0) ; LED off

Then configure for example a SNOM phone function key as a BLF (or destiantion) to 1234.

See also

Created by: zktech, Last modification: Wed 16 of May, 2012 (14:03 UTC) by feptias
Please update this page with new information, just login and click on the "Edit" or "Discussion" tab. Get a free login here: Register Thanks! - Find us on Google+