Configuración práctica de Asterisk (6ª parte): Servicio horario con valores de ajuste almacenados en la base de datos de Asterisk

En todas las centralitas convencionales la entrada de llamadas está determinada por el denominado Servicio Horario. Mediante esta utilidad es posible dirigir las llamadas entrantes a uno u otro destino en función de la hora y día en que se producen dichas llamadas entrantes. Así por ejemplo, en la centralita que usamos en el Instituto de Formación Profesional Tartanga para las prácticas de telefonía, la TEA308 de Panasonic, el servicio horario tiene la siguiente forma:

Servicio Horario en Asterisk_1

Como se observa en la captura de pantalla anterior, es posible establecer tres franjas horarias, denominadas “día”, “noche” y “almuerzo” para cada día de la semana. Posteriormente, en el menú de LN debemos de configurar para cada línea de entrada a que destino se dirigirá cada llamada según se produzca en una u otra franja horaria. En la siguiente captura de pantalla se puede observar un ejemplo de configuración del menú Modo de Línea. En dicha configuración las llamadas entrantes por las líneas 1,2 y 3 se dirigirán a la extensión de operadora en horario de día, a la extensión de “secretaría” en horario de almuerzo y a la operadora automática con reproducción del mensaje de salida 1 (MDS 1) en horario de noche.

Servicio Horario en Asterisk_2

En Asterisk se puede implementar esta función de “Servicio Horario” mediante la aplicación GotoIfTime(), la cual tiene la siguiente sintaxis:

GotoIfTime(times,weekdays,mdays,months,[timezone]?[labeliftrue:[labeliffalse]])

En la aplicación GotoIfTime() el significado de los diferentes parámetros es el siguiente:

  • times: Es una lista de uno o más rangos de horas en formato de 24 horas, por ejemplo 09:00-17:00 para fijar el rango de horas desde las 9 de la mañana a las 5 de la tarde.
  • weekdays: Es una lista de uno o más días de la semana, por ejemplo tue&thu (los días se escriben como mon, tue, wed, thu, fri, sat, sun). Si escribimos un rango seguido de días los separaremos el primero y el último con un guión, como por ejemplo en mon-fri, pero si queremos indicar días no correlativos, utilizaremos el símbolo & como en tue&thu.
  • mdays: Lo mismo que con los días, pero ahora con un valor numérico comprendido entre 1 y 31. Por ejemplo para los días comprendidos entre el 7 y el 12 escribiremos 7-12 o para los días 12, 13 y 18 escribiremos 12&13&18
  • months: : Lo mismo de nuevo, pero ahora con los meses del año: Ejemplo, jan-apr para el rango entre enero y abril, o  jan&apr para los meses enero y abril.
  • labeliftrue: Es la etiqueta o contexto donde se salta si la expresión se evalúa a “true”.
  • labeliffalse: Es la etiqueta o contexto donde se salta si la expresión se evalúa a “false”

Con esta aplicación es muy fácil modificar la entrada de llamadas para que se tenga en cuenta el “servicio horario”. En la siguiente captura de pantalla se muestra la zona dedicada a la entrada de llamadas dentro del DialPlan de una PBX Asterisk:

Servicio Horario en Asterisk_3

El funcionamiento de esta parte de código correspondiente al DialPlan de Asterisk es muy sencillo, ya que para todas las llamadas que entran a través de un contexto denominado [LlamadasEntrantesSarenet] se reproduce el mensaje de audio <mensajeoperadora1> y durante el transcurso de dicho mensaje y durante cinco segundos más, se espera a que el usuario que realiza la llamada introduzca a través del teclado de su teléfono uno de los códigos propuestos en el mensaje de audio (en este caso, <1> para saltar a la ext 201, <2> para saltar a la ext 202, <3> para saltar a la ext 203 o nada para ser atendido por la extensión de operadora). Un ejemplo de modificación al DialPlan para tener en cuenta el denominado servicio horario es el siguiente:

; ENTRANTES DESDE SAREVOZ
[LlamadasEntrantesSarenet]
; CODIGO PARA EL FUNCIONAMIENTO DE LA OPERADORA AUTOMATICA
; CUANDO HAY UNA LLAMADA ENTRANTE DESDE EL CONTEXTO
;”LlamadasEntrantesSarenet”
exten => s,1,NoOp(Salto en la entrada de llamadas según horario de la empresa)
same => n,Set(hora_inicio=${DB(horarios/inicio)})
same => n,Set(hora_fin=${DB(horarios/fin)})
same => n,Set(mes_vacaciones=${DB(horarios/vacaciones)})
same => n,Set(dia_festivo=${DB(horarios/festivo)})
same => n,GotoIfTime(*,*,*,${mes_vacaciones}?horario_vacaciones,s,1)
same => n,GotoIfTime(*,*,${dia_festivo},*?dia_festivo,s,1)
same => n,GotoIfTime(*,sat-sun,*,*?horario_noche,s,1)
same => n,GotoIfTime(${hora_inicio}-${hora_fin},mon-fri,*,*?horario_dia,s,1:horario_noche,s,1)
same => n, Hangup()
[horario_dia]
exten => s,1,Background(/var/lib/asterisk/sounds/mensajeoperadora1,m)
same => n,WaitExten(5)
same => n,goto(sinmarcacion,1,1)
same => n,Hangup()
; TRATAMIENTO DE LAS OPCIONES DE LA OPERADORA 1 => 201, 2 => 202 3 => 203
exten => 1,1,Dial(SIP/201)
same => n,Hangup()
exten => 2,1,Dial(SIP/202)
same => n,Hangup()
exten => 3,1,Dial(SIP/203)
same => n,Hangup()
exten => _[0-456789]!,1,Goto(sinmarcacion,1,1)
same => n,Hangup()
[sinmarcacion]
exten => 1,1,Playback(/var/lib/asterisk/sounds/mensajetransferirllamadaoperadora)
same => n,Wait(1)
same => n,Dial(SIP/201)
same => n,Hangup()
[horario_vacaciones]
exten => s,1,Playback(/var/lib/asterisk/sounds/mensajehorariovacaciones)
same => n,Wait(1)
same => n,Playback(beep)
same => n,Hangup()
[dia_festivo]
exten => s,1,Playback(/var/lib/asterisk/sounds/mensajediafestivo)
same => n,Wait(1)
same => n,Playback(beep)
same => n,Hangup()
[horario_noche]
exten => s,1,Playback(/var/lib/asterisk/sounds/mensajehorarionoche)
same => n,Wait(1)
same => n,Playback(beep)
same => n,Hangup()
; FIN DEL CONTEXTO PARA LLAMADAS ENTRANTES DESDE EL TRUNK SIP SARENET

En el fragmento anterior del DialPlan se puede observar lo siguiente:

  • Se utiliza cuatro veces la aplicación GotoIfTime() para discriminar si la llamada recibida lo es durante el mes de vacaciones de la empresa, durante un día festivo, durante los días sábado o domingo, en los cuales se supone que la empresa está cerrada o durante el intervalo comprendido entre una hora de inicio y una hora de fin, independientemente del día de la semana, del día del mes y del mes.
  • En cada uno de los cuatro casos anteriores se salta a un contexto determinado, siempre con la extensión s (start) y prioridad 1. Una vez que se entra en cada uno de estos contextos, se reproduce el mensaje de audio adecuado en cada caso.
  • En la aplicación GotoIfTime() cuando se desea no evaluar una condición, se coloca el símbolo del comodín, en este caso el asterisco <*>. Así por ejemplo, cuando se evalúa si el mes actual es el mes fijado de vacaciones, se colocan asteriscos en los campos correspondientes a times, weekdays y mdays.
  • Se ha previsto un tratamiento de errores cuando el usuario tiene que introducir como opciones los números <1>, <2> o <3>. Si introduce cualquier otro número distinto a los señalados, se transfiere la llamada entrante de forma automática a la extensión de operadora, en este ejemplo la <201>.

Si solamente se hubiera programado el DialPlan con las condiciones indicadas anteriormente, tendríamos un problema importante y es que, cada vez que se desea cambiar el horario de inicio o cierre de la empresa, añadir un día festivo o modificar el mes de vacaciones, estaríamos obligados a editar y modificar el DialPlan. Esto no es en absoluto recomendable, ya que cualquier error al hacer modificaciones como las anteriores en el DialPlan puede hacer que el sistema deje de funcionar correctamente. Por ello, utilizando la base de datos de Asterisk, se ha previsto que dichas variables se escriban en la base de datos de tal forma que la aplicación GotoIfTime() utiliza valores leídos de dicha base de datos en lugar de valores absolutos fijados en el propio DialPlan. Para ello se ha creado una  familia denominada <horarios> con las siguientes entradas o claves en la base de datos de Asterisk, también conocida como AstDB (Asterisk Database):

  • horarios/inicio
  • horarios/fin
  • horarios/vacaciones
  • horarios/festivo

Estos valores se inician con los valores deseados desde la extensión de operadora y mediante el siguiente código dentro del archivo extensions.conf o archivo de DialPlan:

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
;x       CODIGO GRABACION VALORES EN ASTERISK DATABASE                     
;x        PARA ZONAS HORARIAS DE LA EMPRESA                                                      
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; CODIGO “410” PARA AJUSTE DEL HORARIO DE INICIO DE ACTIVIDAD EN LA EMPRESA
; DESPUÉS DEL CÓDIGO 410 HAY QUE INTRODUCIR LA HORA DE COMIENZO, DESDE 00 HASTA 24
exten => _410XX,1,Set(DB(horarios/inicio)=${EXTEN:-2}:00)
same => n,Wait(1)
same =>n,Playback(open)
same => n,SayNumber(${DB(horarios/inicio)})
same => n,Playback(hours)
same => n,Wait(1)
same => n,Playback(beep)
same => n,Hangup()
; CODIGO “411XX” PARA AJUSTE DEL HORARIO DE FIN DE ACTIVIDAD EN LA EMPRESA
; DESPUES DEL CÓDIGO 411 HAY QUE INTRODUCIR LA HORA DE FIN DE ACTIVIDAD, DESDE 00     ; HASTA 24
exten => _411XX,1,Set(DB(horarios/fin)=${EXTEN:-2}:00)
same => n,Wait(1)
same =>n,Playback(closed)
same => n,SayNumber(${DB(horarios/fin)})
same => n,Playback(hours)
same => n,Wait(1)
same => n,Playback(beep)
same => n,Hangup()
; CODIGO “412XX” PARA AJUSTE DE UN DIA FESTIVO
; DESPUES DEL CÓDIGO 412 HAY QUE INTRODUCIR LA FECHA DEL DIA FESTIVO, DESDE 01 HASTA ; 31 PARA LA CONFIGURACION SIN FESTIVOS AJUSTAR ESTE DIA A 32
exten => _412XX,1,Set(DB(horarios/festivo)=${EXTEN:-2})
same => n,Wait(1)
same => n,Playback(day)
same => n,SayNumber(${DB(horarios/festivo)})
same => n,Wait(1)
same => n,Playback(beep)
same => n,Hangup()
; CODIGO “413XX” PARA AJUSTE DEL MES DE VACACIONES
; DESPUES DEL CÓDIGO 413 HAY QUE INTRODUCIR EL NUMERO CORRESPONDIENTE AL MES DE ; VACACIONES DESDE 01 PARA ENERO HASTA 12 PARA DICIEMBRE
exten => _413XX,1,Set(DB(horarios/vacaciones)=${EXTEN:-2})
same => n,Wait(1)
same => n,Set(mes=$[${EXTEN:-2} – 1])
same => n,Playback(/usr/share/asterisk/sounds/digits/mon-${mes})
same => n,Wait(1)
same => n,Playback(beep)
same => n,Hangup()

Como se observa, se ha utilizado la aplicación Set() para guardar los valores deseados para cada una de las cuatro claves creadas en la base de datos. Esta aplicación Set() tiene la siguiente sintáxis:  Set(DB(familia/clave)=valor) teniendo en cuenta que los valores leídos son siempre los dos últimos dígitos que siguen a los códigos <411>,<412>,<413> y <414> y por ello, para capturar el valor de esos dos dígitos, hemos utilizado la siguiente expresión: ${EXTEN:-2}. Además, para los casos de la <hora de inicio> y <hora de fin> añadimos la expresión :00 a fin de que el formato de hora introducido por el usuario mediante tan solo dos dígitos coincida con el formato de hora esperado por GotoIfTime() en el campo times.

De la misma forma y para que la aplicación permita al usuario comprobar que los valores introducidos para las horas de inicio y fin son correctos, se ha utilizado la aplicación SayNumber() seguida de la reproducción mediante la aplicación Playback() del fichero de audio de Asterisk correspondientes a las palabra <horas>. Estos ficheros se encuentran en el directorio /usr/share/asterisk/sounds  y como es la ruta por defecto, no hace falta especificarla.

Para que el usuario pueda comprobar fácilmente que el valor del mes de vacaciones introducido es el correcto, se ha utilizado un sistema un poco más sofisticado que el anterior. En este caso se reproducen los ficheros de audio de Asterisk correspondientes a los meses del año y que se encuentran situados, junto con otros ficheros de audio, en el directorio /usr/share/asterisk/sounds/digits. Como no es la ruta por defecto, hay que especificarla. Además, como estos ficheros de audio tienen como nombres desde mon-0  para el mes de enero hasta mon-11 para el mes de diciembre, al valor tecleado por el usuario en su teléfono desde 01 hasta 12 hay que restarle 1 y eso se hace mediante la expresión Set(mes=$[${EXTEN:-2} – 1]) en la cual asignamos a la variable mes el valor leído desde el teclado del teléfono del usuario menos 1. Luego, a la hora de buscar el fichero de audio adecuado utilizamos la aplicación Playback() con el siguiente formato:  Playback(/usr/share/asterisk/sounds/digits/mon-${mes}) El resultado práctico se puede ver en los siguientes vídeos: 

Ajuste de los valores del Servicio Horario

 

Prueba de funcionamiento del Servicio Horario

Nota final: La forma de implementar la entrada de llamadas y el servicio horario mostrada en el ejemplo anterior seguramente puede realizarse de una forma más profesional y con muchas más opciones. En el ejemplo descrito se ha tratado únicamente de mostrar a nuestros alumnos del módulo de “Sistemas de Telefonía Fija y Móvil” del ciclo formativo de “Sistemas de Telecomunicación e Informáticos” las posibilidades de la aplicación GotoIfTime() y también la forma de almacenar y recuperar valores de la base de datos de Asterisk.  Queda claro con lo mostrado en esta entrada y en entradas anteriores que Asterisk es una solución extremadamente flexible y potente, permitiendo ajustar el funcionamiento de una PBX IP de una forma absolutamente profesional y donde el límite solo está en la imaginación y en las ganas de trabajar del programador.

Esta entrada fue publicada en Telefonía IP. Guarda el enlace permanente.

2 respuestas a Configuración práctica de Asterisk (6ª parte): Servicio horario con valores de ajuste almacenados en la base de datos de Asterisk

  1. javier dijo:

    Hola, buenas tardes. Consulta: El servidor tiene la hora correcta, la time zone esta definida en UTC+3 y sin embargo Asterisk (1.6 sobre linux) sigue mostrando la hora del SO + 3 por lo cual no puedo tomar esa hora para los controles del IVR, que puede ser ? Gracias !

    Ejemplo: Si la hora del servidor (comando date) muestra 14:30 Asterisk muestra 17:30 hs

  2. Jesus dijo:

    Hola Enrique. Yo creo que debes proponer un curso para profesores el curso que viene sobre telefonía IP…

Deja un comentario

Tu dirección de correo electrónico no será publicada.