Agendar (www.agendar.com.ar) es una novedosa propuesta que ofrece a sus usuarios la posibilidad de reservar turnos online en una amplia variedad de negocios, de diferentes rubros, sin la necesidad de realizar largas esperas telefónicas y sin importar cual sea el horario de atención al público de dicho negocio.
Una vez que el usuario ingresa en Agendar, puede navegar a través de las categorías o mismo utilizar el buscador para llegar al negocio que brinde el servicio que desea contratar y allí elegir si quiere realizar una reserva para una fecha y hora en particular o con un profesional que ya conozca. De esa manera, el usuario de Agendar puede ver en tiempo real la agenda del negocio y encontrar el turno que le quede más cómodo y reservarlo.
Luego que el usuario realiza la reserva a través de Agendar, en el negocio que desea, éste le enviará un correo electrónico, para que confirme el turno y una vez confirmado le será notificado al comercio sobre la nueva reserva, el cual podrá Aceptar, Rechazar o mismo comunicarse con el usuario para ofrecerle un nuevo turno.
Los usuarios registrados en el portal de Agendar, pueden acceder a diferentes herramientas que le permitirán administrar sus turnos más fácilmente. Un ejemplo es la opción de "Favoritos", si un usuario tiene un negocio, así sea Peluquería, Veterinaria, Cancha de fútbol, médico, etc. que concurre habitualmente, puede generarse un acceso directo al mismo para que cada vez que inicia sesión pueda acceder a la agenda de turnos del comercio rápidamente, sin la necesidad de utilizar otras herramientas, como el buscador o el navegador de categorías para encontrarlo. También los usuarios tienen la posibilidad de ver un historial de reservas o mismo listar todas aquellas que están pendientes, para luego realizar alguna modificación o cancelación (siempre que la reserva se encuentre dentro de los plazos establecidos por el comercio para realizar dichas acciones)
Otra de las fabulosas atracciones del portal Agendar es la posibilidad de acceder a las funcionalidades de usuarios registrados, a través de su cuenta de Facebook, Gmail o Twitter. Lo cual facilita aun más la utilización de todas sus herramientas.
Los comercios que se registran en Agendar obtienen GRATUITAMENTE un nuevo canal de ventas y marketing de un alcance mucho mayor al que puede ofrecer otro portal, y a su vez tienen una herramienta que les permitirá mejorar la experiencia a sus clientes habituales, ya que para reservar un turno no van a tener que esperar más a ser atendidos telefónicamente o presencialmente en el horario de atención del negocio, sino que podrán reservar su turno a cualquier hora y en cualquier lugar en tres simples pasos.
Si queres conocer más sobre Agendar, te sugiero que ingreses en www.agendar.com.ar o mismo a la fan page https://www.facebook.com/agendar.com.ar/
Asterisk help
Ideas y soluciones para telefonía ip
martes, 2 de febrero de 2016
domingo, 12 de julio de 2015
Distribución de módulos en Python
La idea de este POST es describir brevemente como podemos hacer para distribuír nuestros módulos desarrollados en Python, para que otros desarrolladores los instalen en sus sistemas y puedan utilizar nuestro código.
1) Creamos el módulo que queremos distribuír
Para este ejempo creamos una funcion llamada "recurPrint", que sirve para recorrer una lista de forma recurisva imprimiendo todos los items que la componen, y en caso que dentro de esta lista exista otra lista, también la recorre e imprime su contenido.
para ello creamos un directorio llamado recurprint y dentro de este un archivo llamado recurprint.py con el siguiente código:
-----------------------------------------
"""
Prueba de distribucion de modulo
"""
def recurPrint(pList):
"""
Recorre una lista de forma recursiva e imprime su contendio
"""
for item in pList:
if isinstance(item, list):
recurPrint(item)
else:
print item
------------------ EOF ------------------
2) Generamos el instalador para nuestro módulo
Dentro del mismo directorio, creamos un archivo llamado setup.py, con el siguiente contenido:
-----------------------------------------
from distutils.core import setup
setup(
name = "recurprint",
version = "0.0.1",
py_modules = ["recurprint"],
author = "Gustavo Borgoni",
author_email = "gborgoni@gmail.com",
url = "http://asteriskhelp.blogspot.com",
description = "Este es un modulo de prueba ",
)
------------------ EOF ------------------
3) Generamos los archivos de distribución
Para ello corremos el siguiente comando, dentro del directorio recurprint:
$ python setup.py sdist
Lo que aparecerá en la pantalla:
-----------------------------------------
running sdist
running check
warning: sdist: manifest template 'MANIFEST.in' does not exist (using default file list)
warning: sdist: standard file not found: should have one of README, README.txt
writing manifest file 'MANIFEST'
creating recurprint-0.0.1
making hard links in recurprint-0.0.1...
hard linking recurprint.py -> recurprint-0.0.1
hard linking setup.py -> recurprint-0.0.1
creating dist
Creating tar archive
removing 'recurprint-0.0.1' (and everything under it)
-----------------------------------------
Una vez finalizada la ejecución del comando anterior, nos vamos a encontrar que el contenido de nuestro directorio quedó de la siguiente manera:
recurprint.py (Nuestro código)
recurprint.pyc (Nuestro código compilado)
build
lib
recurprint.py (Nuestro código)
dist
recurprint-0.0.1.tar.gz (Nuestro paquete para distribuír con nuestros amigos)
MANIFEST (Contiene la lista de archivos que son incluidas en esta distribución)
setup.py (Archivo setup creado por nosotros)
4) Instalamos nuestro módulo, para luego poder utilizarlo en nuestros proyectos
$ sudo python setup.py install
[sudo] password for gus:
running install
running build
running build_py
running install_lib
copying build/lib.linux-x86_64-2.7/recuprint.py -> /usr/local/lib/python2.7/dist-packages
byte-compiling /usr/local/lib/python2.7/dist-packages/recurprint.py to recurprint.pyc
running install_egg_info
Writing /usr/local/lib/python2.7/dist-packages/recurprint-0.0.1.egg-info
5) Probamos usar nuestra lib:
$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from recurprint import recurPrint
>>> lista = ["item1", "item2", ["subitem1", "subitem2"]]
>>> recurPrint(lista)
item1
item2
subitem1
subitem2
>>>
Esto es todo por ahora, espero que sea útil la info.
Abrazo!
1) Creamos el módulo que queremos distribuír
Para este ejempo creamos una funcion llamada "recurPrint", que sirve para recorrer una lista de forma recurisva imprimiendo todos los items que la componen, y en caso que dentro de esta lista exista otra lista, también la recorre e imprime su contenido.
para ello creamos un directorio llamado recurprint y dentro de este un archivo llamado recurprint.py con el siguiente código:
-----------------------------------------
"""
Prueba de distribucion de modulo
"""
def recurPrint(pList):
"""
Recorre una lista de forma recursiva e imprime su contendio
"""
for item in pList:
if isinstance(item, list):
recurPrint(item)
else:
print item
------------------ EOF ------------------
2) Generamos el instalador para nuestro módulo
Dentro del mismo directorio, creamos un archivo llamado setup.py, con el siguiente contenido:
-----------------------------------------
from distutils.core import setup
setup(
name = "recurprint",
version = "0.0.1",
py_modules = ["recurprint"],
author = "Gustavo Borgoni",
author_email = "gborgoni@gmail.com",
url = "http://asteriskhelp.blogspot.com",
description = "Este es un modulo de prueba ",
)
------------------ EOF ------------------
3) Generamos los archivos de distribución
Para ello corremos el siguiente comando, dentro del directorio recurprint:
$ python setup.py sdist
Lo que aparecerá en la pantalla:
-----------------------------------------
running sdist
running check
warning: sdist: manifest template 'MANIFEST.in' does not exist (using default file list)
warning: sdist: standard file not found: should have one of README, README.txt
writing manifest file 'MANIFEST'
creating recurprint-0.0.1
making hard links in recurprint-0.0.1...
hard linking recurprint.py -> recurprint-0.0.1
hard linking setup.py -> recurprint-0.0.1
creating dist
Creating tar archive
removing 'recurprint-0.0.1' (and everything under it)
-----------------------------------------
Una vez finalizada la ejecución del comando anterior, nos vamos a encontrar que el contenido de nuestro directorio quedó de la siguiente manera:
recurprint.py (Nuestro código)
recurprint.pyc (Nuestro código compilado)
build
lib
recurprint.py (Nuestro código)
dist
recurprint-0.0.1.tar.gz (Nuestro paquete para distribuír con nuestros amigos)
MANIFEST (Contiene la lista de archivos que son incluidas en esta distribución)
setup.py (Archivo setup creado por nosotros)
4) Instalamos nuestro módulo, para luego poder utilizarlo en nuestros proyectos
$ sudo python setup.py install
[sudo] password for gus:
running install
running build
running build_py
running install_lib
copying build/lib.linux-x86_64-2.7/recuprint.py -> /usr/local/lib/python2.7/dist-packages
byte-compiling /usr/local/lib/python2.7/dist-packages/recurprint.py to recurprint.pyc
running install_egg_info
Writing /usr/local/lib/python2.7/dist-packages/recurprint-0.0.1.egg-info
5) Probamos usar nuestra lib:
$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from recurprint import recurPrint
>>> lista = ["item1", "item2", ["subitem1", "subitem2"]]
>>> recurPrint(lista)
item1
item2
subitem1
subitem2
>>>
Esto es todo por ahora, espero que sea útil la info.
Abrazo!
viernes, 25 de noviembre de 2011
Monitor de llamadas concurrentes
En esta oportunidad, quiero compartir con ustedes un pequeño desarrollo que hice, para poder ver gráficamente el historial de llamadas concurrentes que tuvo nuestra central, a lo largo del día.
El funcionamiento de la aplicación es muy simple, lo único que hace es tomar muestras (de la cantidad de llamadas activas en el momento de la medición) y guardarlas en un archivo de texto, con la fecha y hora. Luego esta información es procesada y mostrada en un gráfico, como se muestra a continuación:
En esta primer versión la herramienta debe instalarse en la misma PBX, dado a que la toma de información la hace localmente, a través de comandos de la CLI. En futuras versiones posiblemente se adapte para que funcione de forma remota.
Para bajar la aplicación pueden hacerlo desde:
http://ccallsmonitor.googlecode.com/files/ccallsmonitor.tar.gz
Hasta la próxima!!
El funcionamiento de la aplicación es muy simple, lo único que hace es tomar muestras (de la cantidad de llamadas activas en el momento de la medición) y guardarlas en un archivo de texto, con la fecha y hora. Luego esta información es procesada y mostrada en un gráfico, como se muestra a continuación:
Para bajar la aplicación pueden hacerlo desde:
http://ccallsmonitor.googlecode.com/files/ccallsmonitor.tar.gz
Hasta la próxima!!
viernes, 11 de noviembre de 2011
Entendiendo el CDR
El Call Detail Record (Registro Detallado de Llamadas) es una aplicación que se encarga de almacenar el Log de llamadas que son cursadas a través de una PBX. En el presente artículo intentaré explicar su instalación, configuración y entendimiento de los registros para poder identificar los distintos tipos de llamadas.
Instalación:
Antes de comenzar con la instalación, es importante aclarar que, para realizar este artículo se utilizó Asterisk 1.4.37 y Addons 1.4.7, que son las versiones que mejores resultados me trajeron, hasta ahora.
Luego de descargar, descomprimir y entrar al menú de selección de la instalación de Asterisk(utilizando: make menuconfig), podemos acceder a la opción "Call Detail Recording", donde está la lista de módulos que permiten que el CDR almacene los logs en el formato / aplicación que necesitemos.
La siguiente tabla muestra las opciones que nos permite utilizar el CDR, para almacenar los registros de las llamadas, y las dependencias que necesita para que las mismas funcionen.
Nótese que en la lista no se encuentra el soporte para mysql, no hay que preocuparse, porque este se encuentra en el paquete addons.
Finalizada la selección de las características para el CDR y de la instalación de Asterisk, pasaremos a instalar el paquete Addons, para poder incorporar el soporte para MySQL.
Hacemos los mismos pasos que antes, descargar, descomprimir y entrar al menú de selección y finalmente accedemos a la opción "Call Detail Recording", donde nos muestra: cdr_addon_mysql (En caso que no esté instalada la dependencia: mysqlclient, aparecerá con XXX al principio, por lo tanto debemos salir del menú e instalar dicha dependencia para luego volver a este paso.)
Configuración:
Una vez finalizado el proceso de instalación, haremos un recorrido por todos los archivos de configuración del CDR y finalmente nos centraremos en la configuración de la integración con MySQL.
La siguiente tabla muestra, la lista de archivos que permiten configurar las diferentes prestaciones del CDR:
cdr.conf
En este archivo vamos a cargar todas las configuraciones que son a nivel general, las cuales afectarían a todos los módulos que anteriormente mencionamos, ahora vamos a ver sus parámetros.
[general]
cdr_manager.conf
Permite acceder al CDR a través del AMI, para ello cuenta con una sola opción a configurar, que la vemos a continuación:
[General]
enabled = yes / no
cdr_pgsql.conf
Para activar el almacenamiento del CDR en PostgresSQL, se tendrá que ingresar los siguientes parámetros, que corresponden a los datos de acceso al servidor de Base de datos.
[global]
hostname=localhost
port=5432
dbname=asterisk
password=password
user=postgres
table=cdr
cdr_custom.conf
Aquí podremos personalizar en el formato, del archivo de texto plano, que queremos que se almacenen los registros de las llamadas. Estos serán guardados en el siguiente path: /var/log/asterisk/cdr-custom/Master.csv
[mappings]
Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})}
En la línea anterior podemos cambiar el nombre del archivo, elegir que datos guardar y que separador utilizar.
cdr_mysql.conf
Al igual que con PostgresSQL, debemos configurar los datos de acceso al Servidor.
[global]
hostname = localhost
dbname=asteriskcdrdb
password = amp109
user = asteriskuser
userfield=1
port=3306
cdr_odbc.conf
Igual que los anteriores, excepto que aquí se configura el DSN que contiene los datos del servidor de base de datos al cual queremos almacenar los datos.
[global]
dsn=MySQL-test
username=username
password=password
loguniqueid=yes
dispositionstring=yes
table=cdr
usegmtime=no
Tabla de registro del CDR para SQL
En caso que utilicemos un servidor de base de datos, cualquier de los que soporta Asterisk, vamos a necesitar crear la tabla donde se almacenaran los datos. Para ello, presento a continuación el código SQL para crear la tabla:
CREATE TABLE `cdr` (
`calldate` datetime NOT NULL default '0000-00-00 00:00:00',
`clid` varchar(80) NOT NULL default '',
`src` varchar(80) NOT NULL default '',
`dst` varchar(80) NOT NULL default '',
`dcontext` varchar(80) NOT NULL default '',
`channel` varchar(80) NOT NULL default '',
`dstchannel` varchar(80) NOT NULL default '',
`lastapp` varchar(80) NOT NULL default '',
`lastdata` varchar(80) NOT NULL default '',
`duration` int(11) NOT NULL default '0',
`billsec` int(11) NOT NULL default '0',
`disposition` varchar(45) NOT NULL default '',
`amaflags` int(11) NOT NULL default '0',
`accountcode` varchar(20) NOT NULL default '',
`userfield` varchar(255) NOT NULL default '',
`uniqueid` VARCHAR(32) NOT NULL default ''
);
Ahora bien, para que las consultas sobre la tabla del CDR sean un poco más rápidas, lo que haremos es crear unos índices sobre las columnas que seguramente más utilizaremos:
ALTER TABLE `cdr` ADD INDEX ( `calldate` );
ALTER TABLE `cdr` ADD INDEX ( `dst` );
ALTER TABLE `cdr` ADD INDEX ( `uniqueid` );
Algunas consultas SQL
Bien, como frutilla del postre a continuación pondré algunos Queryes que tal vez sirvan para obtener distintos tipos de reportes, sobre el CDR. Obviamente estos dependen de la configuración de cada PBX.
- Cantidad de llamadas atendidas por día:
select date_format(calldate, "%Y-%m-%d"), count(*) from cdr where dcontext = 'from-pstn' group by 1;
- Cantidad de llamadas exitosas realizadas por día:
select date_format(calldate, "%Y-%m-%d"), count(*) from cdr where dstchannel like 'DAHDI%' and disposition = 'ANSWERED' group by 1;
- Cantidad de llamadas fallidas por día:
select date_format(calldate, "%Y-%m-%d"), count(*) from cdr where dstchannel like 'DAHDI%' and disposition = 'FAILED' group by 1;
- Cantidad de llamadas realizadas por un interno:
select * from cdr where dstchannel like 'DAHDI%' and disposition = 'ANSWERED' and calldate >= 'YYYY-MM-DD 00:00:00' and calldate <= 'YYYY-MM-DD 23;59;59' and src = NUMERO_INTERNO;
reemplazar YY-MM-DD por el día que deseamos consultar y NUMERO_INTERNO por la extensión.
Saludos y hasta la próxima!!
Instalación:
Antes de comenzar con la instalación, es importante aclarar que, para realizar este artículo se utilizó Asterisk 1.4.37 y Addons 1.4.7, que son las versiones que mejores resultados me trajeron, hasta ahora.
Luego de descargar, descomprimir y entrar al menú de selección de la instalación de Asterisk(utilizando: make menuconfig), podemos acceder a la opción "Call Detail Recording", donde está la lista de módulos que permiten que el CDR almacene los logs en el formato / aplicación que necesitemos.
La siguiente tabla muestra las opciones que nos permite utilizar el CDR, para almacenar los registros de las llamadas, y las dependencias que necesita para que las mismas funcionen.
Applicación
|
Descripción
|
Dependencia
|
cdr_csv | Comma Separated Values CDR Backend | N/A |
cdr_custom | Customizable Comma Separated Values CDR Backend | N/A |
cdr_manager | Asterisk Manager Interface CDR Backend | N/A |
cdr_odbc | ODBC CDR Backend | unixodbc, ltdl |
cdr_pgsql | PostgreSQL CDR Backend | pgsql |
cdr_radius | RADIUS CDR Backend | radius |
cdr_sqlite | SQLite CDR Backend | sqlite |
cdr_tds | MSSQL CDR Backend | freetds |
Nótese que en la lista no se encuentra el soporte para mysql, no hay que preocuparse, porque este se encuentra en el paquete addons.
Finalizada la selección de las características para el CDR y de la instalación de Asterisk, pasaremos a instalar el paquete Addons, para poder incorporar el soporte para MySQL.
Hacemos los mismos pasos que antes, descargar, descomprimir y entrar al menú de selección y finalmente accedemos a la opción "Call Detail Recording", donde nos muestra: cdr_addon_mysql (En caso que no esté instalada la dependencia: mysqlclient, aparecerá con XXX al principio, por lo tanto debemos salir del menú e instalar dicha dependencia para luego volver a este paso.)
Configuración:
Una vez finalizado el proceso de instalación, haremos un recorrido por todos los archivos de configuración del CDR y finalmente nos centraremos en la configuración de la integración con MySQL.
La siguiente tabla muestra, la lista de archivos que permiten configurar las diferentes prestaciones del CDR:
Archivo
|
Descripción
|
cdr.conf | Configuración general del CDR |
cdr_manager.conf | Acceso al CDR a través del AMI |
cdr_pgsql.conf | Configuración para PostgresSQL |
cdr_custom.conf | Configuración de Log Personalizado |
cdr_mysql.conf | Configuración para MySQL |
cdr_odbc.conf | Conector ODBC (Para cualquier base de datos) |
cdr_tds.conf | Configuración para FreeTDS |
cdr.conf
En este archivo vamos a cargar todas las configuraciones que son a nivel general, las cuales afectarían a todos los módulos que anteriormente mencionamos, ahora vamos a ver sus parámetros.
[general]
Parámetro
|
Valores
|
Descripción
|
enable | yes/no | Activa o desactiva la utilización del CDR. |
unanswered | yes/no | Registrar las llamadas no atendidas |
batch | yes/no | Permite almacenar los datos de las llamadas en un buffer, para luego enviarlos a donde quisiéramos almacenar. OJO! que activando esta opción, si bien se liberaría un poco de procesamiento a Asterisk, puede ocasionar posibles perdidas de datos, en caso que Asterisk se detenga. |
size | Número entero | En caso que se active la opción de Batch, se define la cantidad de registros de CDR que se acumularán en el buffer, antes de ser enviados al medio de almacenamiento. |
time | Número entero | En caso que se active la opción de Batch, se define la cantidad de tiempo máximo que deberán estar los registros almacenados en el buffer. |
time | Número entero | En caso que se active la opción de Batch, se define la cantidad de tiempo máximo que deberán estar los registros almacenados en el buffer. |
scheduleronly | yes/no | Asterisk utiliza un "scheduler" interno, para determinar en que momentos se envían los registros al medio de almacenamiento. Dicho envío se puede hacer en el mismo "thread" donde está el "scheduler" o bien crear un nuevo "thread" para realizar esta tarea. En caso que se configure un proceso Batch con pocos registros, el envío puede estar en el "thread" del "scheduler" (Configurar este parámetro en "yes"). Ahora si se configuró un Batch de mayor tamaño, por ejemplo size=10, es recomendable realizar esta tarea en un nuevo "thread" (Configurar este parámetro en "no"). |
safeshutdown | yes/no | Si hacemos un "stop now" en Asterisk y justo en ese momento se están enviando registros de CDR, al configurar este parámetro en "yes", se bloquea el apagado de Asterisk hasta que terminen de enviarse los registros. |
endbeforehexten | yes/no | Generalmente el CDR no se cierra hasta que todos los internos finalicen su ejecución. Al habilitar esta opción el CDR se cerrará antes que se ejecute el hangup, lo que causaría que se pierdan algunos datos. |
cdr_manager.conf
Permite acceder al CDR a través del AMI, para ello cuenta con una sola opción a configurar, que la vemos a continuación:
[General]
enabled = yes / no
cdr_pgsql.conf
Para activar el almacenamiento del CDR en PostgresSQL, se tendrá que ingresar los siguientes parámetros, que corresponden a los datos de acceso al servidor de Base de datos.
[global]
hostname=localhost
port=5432
dbname=asterisk
password=password
user=postgres
table=cdr
cdr_custom.conf
Aquí podremos personalizar en el formato, del archivo de texto plano, que queremos que se almacenen los registros de las llamadas. Estos serán guardados en el siguiente path: /var/log/asterisk/cdr-custom/Master.csv
[mappings]
Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})}
En la línea anterior podemos cambiar el nombre del archivo, elegir que datos guardar y que separador utilizar.
cdr_mysql.conf
Al igual que con PostgresSQL, debemos configurar los datos de acceso al Servidor.
[global]
hostname = localhost
dbname=asteriskcdrdb
password = amp109
user = asteriskuser
userfield=1
port=3306
cdr_odbc.conf
Igual que los anteriores, excepto que aquí se configura el DSN que contiene los datos del servidor de base de datos al cual queremos almacenar los datos.
[global]
dsn=MySQL-test
username=username
password=password
loguniqueid=yes
dispositionstring=yes
table=cdr
usegmtime=no
Tabla de registro del CDR para SQL
En caso que utilicemos un servidor de base de datos, cualquier de los que soporta Asterisk, vamos a necesitar crear la tabla donde se almacenaran los datos. Para ello, presento a continuación el código SQL para crear la tabla:
CREATE TABLE `cdr` (
`calldate` datetime NOT NULL default '0000-00-00 00:00:00',
`clid` varchar(80) NOT NULL default '',
`src` varchar(80) NOT NULL default '',
`dst` varchar(80) NOT NULL default '',
`dcontext` varchar(80) NOT NULL default '',
`channel` varchar(80) NOT NULL default '',
`dstchannel` varchar(80) NOT NULL default '',
`lastapp` varchar(80) NOT NULL default '',
`lastdata` varchar(80) NOT NULL default '',
`duration` int(11) NOT NULL default '0',
`billsec` int(11) NOT NULL default '0',
`disposition` varchar(45) NOT NULL default '',
`amaflags` int(11) NOT NULL default '0',
`accountcode` varchar(20) NOT NULL default '',
`userfield` varchar(255) NOT NULL default '',
`uniqueid` VARCHAR(32) NOT NULL default ''
);
Ahora bien, para que las consultas sobre la tabla del CDR sean un poco más rápidas, lo que haremos es crear unos índices sobre las columnas que seguramente más utilizaremos:
ALTER TABLE `cdr` ADD INDEX ( `calldate` );
ALTER TABLE `cdr` ADD INDEX ( `dst` );
ALTER TABLE `cdr` ADD INDEX ( `uniqueid` );
Algunas consultas SQL
Bien, como frutilla del postre a continuación pondré algunos Queryes que tal vez sirvan para obtener distintos tipos de reportes, sobre el CDR. Obviamente estos dependen de la configuración de cada PBX.
- Cantidad de llamadas atendidas por día:
select date_format(calldate, "%Y-%m-%d"), count(*) from cdr where dcontext = 'from-pstn' group by 1;
- Cantidad de llamadas exitosas realizadas por día:
select date_format(calldate, "%Y-%m-%d"), count(*) from cdr where dstchannel like 'DAHDI%' and disposition = 'ANSWERED' group by 1;
- Cantidad de llamadas fallidas por día:
select date_format(calldate, "%Y-%m-%d"), count(*) from cdr where dstchannel like 'DAHDI%' and disposition = 'FAILED' group by 1;
- Cantidad de llamadas realizadas por un interno:
select * from cdr where dstchannel like 'DAHDI%' and disposition = 'ANSWERED' and calldate >= 'YYYY-MM-DD 00:00:00' and calldate <= 'YYYY-MM-DD 23;59;59' and src = NUMERO_INTERNO;
reemplazar YY-MM-DD por el día que deseamos consultar y NUMERO_INTERNO por la extensión.
Saludos y hasta la próxima!!
viernes, 4 de noviembre de 2011
Como enviar variables entre centrales
Después de tanto tiempo que no publico nada en el Blog, quiero compartir con ustedes una solución, tal vez un poco "sucia", a un problema que seguramente se le presentó a aquellas personas que tienen varios Asterisk interconectados por troncales SIP o IAX2.
Veamos un ejemplo:
Tal como se muestra en la imagen anterior, en el momento que Teléfono llama al Interno, dicho llamado pasará por ambas PBX y a su vez generará un registro en el CDR de cada una de ellas. Si queremos asociar ambos registros, nos daríamos cuenta que sería una tarea muy complicada, dado a que ambos contarán con un UniqueID distinto.
Ahora, si nosotros pudiéramos, de alguna forma, enviar de la PBX A a la PBX B el uniqueID, eso simplificaría muchísimo las cosas.
En el momento que el llamado pasa de la "PBX A" a la "PBX B" la única variable que es enviada es CALLERID(name), por lo tanto lo que podríamos hacer es concatenarle los datos que quisiéramos enviar y luego, cuando los valores se reciben en la "PBX B", parsearlos y volver todo como estaba.
Para ello haremos lo siguiente:
PBX A:
Supongamos que en esta PBX tenemos un DID donde los llamados que se reciben a través de este, son enviados a un contexto, llamémoslo from-my-did, que es donde se hace el dial a la PBX B. Entonces para poder concatenar, en este caso el uniqueID, para pasarlo a la otra PBX, tendríamos que poner, antes del dial, la siguiente línea:
exten => s,1,set(CALLERID(name)=${CALLERID(name)}#CDR(uniqueid)=${CDR(uniqueid)}#)
dando como resultado, lo siguiente:
[from-my-did]
exten => s,1,set(CALLERID(name)=${CALLERID(name)}#CDR(uniqueid)=${CDR(uniqueid)}#)
exten => s,n,dial(IAX2/pbxb/frommydid)
Como se podrá notar, cuando concatenamos la variable uniqueID vemos que la misma está entre dos numerales (#), esto se debe a que lo vamos a utilizar como separador para poder parsear los datos que enviamos.
PBX B:
Ahora bien, supongamos que en la configuración del troncal IAX2 dijimos que los llamados de la PBX A, van a ser recibidos en el contexto "from-pbx-a". Entonces tendríamos que agregar la siguiente línea, que se encargará de parsear los datos y crear las variables necesarias:
exten => frommydid,1,AGI(parser.php)
Dando como resultado, lo siguiente:
[from-pbx-a]
exten => frommydid,1,AGI(parser.php)
exten => frommydid,n,Dial(SIP/222)
Por lo tanto, cada vez que la PBX B reciba un llamado desde la PBX A, se parsearan y crearan las variables que concatenamos al CALLERID(name) y luego el llamado será enviado al interno 222.
Aquí les paso el código del parser.php
#!/usr/bin/php
/* Parser.php
* ----------------------------------------------------------------------
* AGI utilizado para parsear las variables enviadas a através del
* CALLERID(name), separadas por #, y luego declararlas en Asterisk.
* ----------------------------------------------------------------------
* by Gustavo Borgoni - gborgoni@gmail.com
*/
<?php
require_once "phpagi.php";
$agi = new AGI();
function get_var($value) {
global $agi;
$r = $agi->get_variable( $value );
if ($r['result'] == 1) {
$result = $r['data'];
return $result;
} else {
return '';
}
}
$info = get_var("CALLERID(name)");
$result = split("#", $info);
$agi->set_variable("CALLERID(name)", $result[0]);
foreach ($result as $k => $v) {
$variable = split("=",$v);
if (trim($variable[0]) != "" && trim($variable[1]) != "") {
$agi->set_variable(trim($variable[0]), trim($variable[1]));
}
}
?>
Hasta la próxima!
Veamos un ejemplo:
Tal como se muestra en la imagen anterior, en el momento que Teléfono llama al Interno, dicho llamado pasará por ambas PBX y a su vez generará un registro en el CDR de cada una de ellas. Si queremos asociar ambos registros, nos daríamos cuenta que sería una tarea muy complicada, dado a que ambos contarán con un UniqueID distinto.
Ahora, si nosotros pudiéramos, de alguna forma, enviar de la PBX A a la PBX B el uniqueID, eso simplificaría muchísimo las cosas.
En el momento que el llamado pasa de la "PBX A" a la "PBX B" la única variable que es enviada es CALLERID(name), por lo tanto lo que podríamos hacer es concatenarle los datos que quisiéramos enviar y luego, cuando los valores se reciben en la "PBX B", parsearlos y volver todo como estaba.
Para ello haremos lo siguiente:
PBX A:
Supongamos que en esta PBX tenemos un DID donde los llamados que se reciben a través de este, son enviados a un contexto, llamémoslo from-my-did, que es donde se hace el dial a la PBX B. Entonces para poder concatenar, en este caso el uniqueID, para pasarlo a la otra PBX, tendríamos que poner, antes del dial, la siguiente línea:
exten => s,1,set(CALLERID(name)=${CALLERID(name)}#CDR(uniqueid)=${CDR(uniqueid)}#)
dando como resultado, lo siguiente:
[from-my-did]
exten => s,1,set(CALLERID(name)=${CALLERID(name)}#CDR(uniqueid)=${CDR(uniqueid)}#)
exten => s,n,dial(IAX2/pbxb/frommydid)
Como se podrá notar, cuando concatenamos la variable uniqueID vemos que la misma está entre dos numerales (#), esto se debe a que lo vamos a utilizar como separador para poder parsear los datos que enviamos.
PBX B:
Ahora bien, supongamos que en la configuración del troncal IAX2 dijimos que los llamados de la PBX A, van a ser recibidos en el contexto "from-pbx-a". Entonces tendríamos que agregar la siguiente línea, que se encargará de parsear los datos y crear las variables necesarias:
exten => frommydid,1,AGI(parser.php)
Dando como resultado, lo siguiente:
[from-pbx-a]
exten => frommydid,1,AGI(parser.php)
exten => frommydid,n,Dial(SIP/222)
Por lo tanto, cada vez que la PBX B reciba un llamado desde la PBX A, se parsearan y crearan las variables que concatenamos al CALLERID(name) y luego el llamado será enviado al interno 222.
Aquí les paso el código del parser.php
#!/usr/bin/php
/* Parser.php
* ----------------------------------------------------------------------
* AGI utilizado para parsear las variables enviadas a através del
* CALLERID(name), separadas por #, y luego declararlas en Asterisk.
* ----------------------------------------------------------------------
* by Gustavo Borgoni - gborgoni@gmail.com
*/
<?php
require_once "phpagi.php";
$agi = new AGI();
function get_var($value) {
global $agi;
$r = $agi->get_variable( $value );
if ($r['result'] == 1) {
$result = $r['data'];
return $result;
} else {
return '';
}
}
$info = get_var("CALLERID(name)");
$result = split("#", $info);
$agi->set_variable("CALLERID(name)", $result[0]);
foreach ($result as $k => $v) {
$variable = split("=",$v);
if (trim($variable[0]) != "" && trim($variable[1]) != "") {
$agi->set_variable(trim($variable[0]), trim($variable[1]));
}
}
?>
Hasta la próxima!
lunes, 15 de noviembre de 2010
Soporte R2 en Asterisk
MFC/R2 (Multi Frecuency Compelled R2) es un protocolo de señalización telefónica peer-to-peer, el cual es utilizado, generalmente, en países de Latinoamérica y Asia.
En este artículo intentaré explicar como instalar el soporte para MFC/R2 en Asterisk. A su vez es importante destacar que esta guía está orientada a aquellos lectores que poseen cierta experiencia instalando y configurando Asterisk y dahdi.
Lo primero que debemos hacer, es ver si la versión de Asterisk que deseamos instalar dispone del parche de R2. Para ello, debemos dirigirnos a la siguiente URL: http://code.google.com/p/openr2/downloads/list
NOTA! En caso de querer instalar, el soporte para R2, en Asterisk-RSP habrá que bajar el
siguiente parche: http://openr2.googlecode.com/files/openr2-asterisk-1.4.24.patch seguramente dará conflictos y habrá que editar a mano chan_dahdi.c para resolverlos.
Una vez determinada y bajada la versión de Asterisk, el parche y la librería openr2. Pasaremos a compilar e instalar todos los paquetes en el siguiente orden:
- libopenr2 (reemplaza la instalación de libpri)
- dahdi-linux
- dahdi-tool
Finalizados los pasos anteriores aplicamos el parche e instalamos Asterisk:
- cd /path/to/asterisk-sources/
- patch -p0 < /path/to/openr2.patch
- ./bootstrap.sh
- ./configure
- make && make install
Para corroborar que chan_dahdi se haya compilado con el soporte para openR2, ejecutamos el siguiente comando: ldd /usr/lib/asterisk/modules/chan_dahdi.so y si todo está bien veremos la siguiente línea:
libopenr2.so.X => /usr/local/lib/libopenr2.so.X
Ahora pasamos a configurar dahdi. Editamos /etc/dahdy/system.conf y configuramos nuestros Spans, de la siguiente manera:
span=1,1,0,cas,hdb3
cas=1-15:1101
cas=17-31:1101
dchan=16
Si poseemos más de una trama, vamos repitiendo el bloque anterior modificando los números de los canales y span, según corresponda. Por ejemplo para el span2 sería:
span=2,2,0,cas,hdb3
cas=32-46:1101
cas=48-62:1101
dchan=47
Por último configuramos chan_dahdi, editando el archivo: /etc/asterisk/chan_dahdi.conf
[channels]
language=es
context=from-pstn
signalling=mfcr2
mfcr2_variant=ar
mfcr2_get_ani_first=no
mfcr2_max_ani=10
mfcr2_max_dnis=4
mfcr2_category=national_subscriber
mfcr2_mfback_timeout=-1
mfcr2_metering_pulse_timeout=-1
mfcr2_logdir=log
mfcr2_logging=all
group=0
channel => 1-15
channel => 17-31
En este artículo intentaré explicar como instalar el soporte para MFC/R2 en Asterisk. A su vez es importante destacar que esta guía está orientada a aquellos lectores que poseen cierta experiencia instalando y configurando Asterisk y dahdi.
Lo primero que debemos hacer, es ver si la versión de Asterisk que deseamos instalar dispone del parche de R2. Para ello, debemos dirigirnos a la siguiente URL: http://code.google.com/p/openr2/downloads/list
NOTA! En caso de querer instalar, el soporte para R2, en Asterisk-RSP habrá que bajar el
siguiente parche: http://openr2.googlecode.com/files/openr2-asterisk-1.4.24.patch seguramente dará conflictos y habrá que editar a mano chan_dahdi.c para resolverlos.
Una vez determinada y bajada la versión de Asterisk, el parche y la librería openr2. Pasaremos a compilar e instalar todos los paquetes en el siguiente orden:
- libopenr2 (reemplaza la instalación de libpri)
- dahdi-linux
- dahdi-tool
Finalizados los pasos anteriores aplicamos el parche e instalamos Asterisk:
- cd /path/to/asterisk-sources/
- patch -p0 < /path/to/openr2.patch
- ./bootstrap.sh
- ./configure
- make && make install
Para corroborar que chan_dahdi se haya compilado con el soporte para openR2, ejecutamos el siguiente comando: ldd /usr/lib/asterisk/modules/chan_dahdi.so y si todo está bien veremos la siguiente línea:
libopenr2.so.X => /usr/local/lib/libopenr2.so.X
Ahora pasamos a configurar dahdi. Editamos /etc/dahdy/system.conf y configuramos nuestros Spans, de la siguiente manera:
span=1,1,0,cas,hdb3
cas=1-15:1101
cas=17-31:1101
dchan=16
Si poseemos más de una trama, vamos repitiendo el bloque anterior modificando los números de los canales y span, según corresponda. Por ejemplo para el span2 sería:
span=2,2,0,cas,hdb3
cas=32-46:1101
cas=48-62:1101
dchan=47
Por último configuramos chan_dahdi, editando el archivo: /etc/asterisk/chan_dahdi.conf
[channels]
language=es
context=from-pstn
signalling=mfcr2
mfcr2_variant=ar
mfcr2_get_ani_first=no
mfcr2_max_ani=10
mfcr2_max_dnis=4
mfcr2_category=national_subscriber
mfcr2_mfback_timeout=-1
mfcr2_metering_pulse_timeout=-1
mfcr2_logdir=log
mfcr2_logging=all
group=0
channel => 1-15
channel => 17-31
miércoles, 10 de noviembre de 2010
Data API Providers
Con el lanzamiento de Asterisk 1.8, en octubre del presente año, se incorporaron varias características nuevas, las cuales iremos comentando a medida que las vallamos testeando. Hoy nos centraremos en una utilidad desarrollada por Eliel Sardañons, un desarrollador Argentino que participó del pasado Google Summer of Code 2010. Esta nueva herramienta permite obtener información detallada sobre Asterisk y cada uno de sus módulos, aplicaciones, channels, etc. los cuales son denominados "Providers".
Sin más preámbulos, vamos a la acción y veamos en funcionamiento esta API. Para acceder a la información que necesitemos, lo primero que debemos saber es cuales son los Providers que disponemos y que nivel de de información nos interesa saber. Para ello debemos ejecutar, el siguiente comando:
*CLI> data show providers
/asterisk/channel/iax2/peers (get) [chan_iax2.c]
/asterisk/channel/iax2/users (get) [chan_iax2.c]
/asterisk/channel/dahdi/version (get) [chan_dahdi.c]
/asterisk/channel/dahdi/status (get) [chan_dahdi.c]
/asterisk/channel/dahdi/channels (get) [chan_dahdi.c]
/asterisk/channel/agent/list (get) [chan_agent.c]
/asterisk/channel/sip/peers (get) [chan_sip.c]
/asterisk/core/hints (get) [pbx.c]
/asterisk/core/channels (get) [channel.c]
/asterisk/core/channeltypes (get) [channel.c]
/asterisk/application/voicemail/list (get) [app_voicemail.c]
/asterisk/application/queue/list (get) [app_queue.c]
/asterisk/application/meetme/list (get) [app_meetme.c]
El resultado del comando anterior nos muestra la lista de Providers con su respectivo nivel de información, separado por barras (/). Por ejemplo, si únicamente nos interesa ver los datos relacionados con los Peers de IAX2, podríamos ejecutar lo siguiente:
*CLI> data get /asterisk/channel/iax2/peers
peers
peer
smoothing: False
pokefreqok: 60000
inkeys: ""
host: "XXX.XXX.XXX.XXX"
encryption: "no"
mailbox: ""
mohinterpret: ""
cid_num: ""
parkinglot: ""
expiry: 60
dbsecret: ""
maxcallno: 0
maxms: 2000
status: "OK (1 ms)"
trunk: True
port: 4569
regexten: ""
outkey: ""
historicms: 1
mask: "255.255.255.255"
dynamic: False
zonetag: ""
username: "USUARIO"
pokefreqnotok: 10000
secret: "CLAVE"
peercontext: ""
callno: 0
mohsuggest: ""
lastms: 1
name: "NOMBRE PEER"
cid_name: ""
context: ""
codecs
codec
frame_length: 80
samplespersecond: 8000
name: "alaw"
description: "G.711 A-law"
A medida que vamos Quitando niveles, nos dará más información. Por ejemplo si nos interesa saber todo lo que pasa en Asterisk en general, solamente debemos ejecutar CLI*> data get /asterisk
Como se podrá apreciar, la información que este devuelve es muy completa y puede ser de gran utilidad para el desarrollo de aplicaciones de monitoreo de Asterisk.
Para cerrar este artículo, voy a mostrar como es posible llamar remotamente a esta API a través del AMI.
Action: Command
ActionID: test
Command: data get Asterisk/channel/iax2/peers \r\n\n
Sin más preámbulos, vamos a la acción y veamos en funcionamiento esta API. Para acceder a la información que necesitemos, lo primero que debemos saber es cuales son los Providers que disponemos y que nivel de de información nos interesa saber. Para ello debemos ejecutar, el siguiente comando:
*CLI> data show providers
/asterisk/channel/iax2/peers (get) [chan_iax2.c]
/asterisk/channel/iax2/users (get) [chan_iax2.c]
/asterisk/channel/dahdi/version (get) [chan_dahdi.c]
/asterisk/channel/dahdi/status (get) [chan_dahdi.c]
/asterisk/channel/dahdi/channels (get) [chan_dahdi.c]
/asterisk/channel/agent/list (get) [chan_agent.c]
/asterisk/channel/sip/peers (get) [chan_sip.c]
/asterisk/core/hints (get) [pbx.c]
/asterisk/core/channels (get) [channel.c]
/asterisk/core/channeltypes (get) [channel.c]
/asterisk/application/voicemail/list (get) [app_voicemail.c]
/asterisk/application/queue/list (get) [app_queue.c]
/asterisk/application/meetme/list (get) [app_meetme.c]
El resultado del comando anterior nos muestra la lista de Providers con su respectivo nivel de información, separado por barras (/). Por ejemplo, si únicamente nos interesa ver los datos relacionados con los Peers de IAX2, podríamos ejecutar lo siguiente:
*CLI> data get /asterisk/channel/iax2/peers
peers
peer
smoothing: False
pokefreqok: 60000
inkeys: ""
host: "XXX.XXX.XXX.XXX"
encryption: "no"
mailbox: ""
mohinterpret: ""
cid_num: ""
parkinglot: ""
expiry: 60
dbsecret: ""
maxcallno: 0
maxms: 2000
status: "OK (1 ms)"
trunk: True
port: 4569
regexten: ""
outkey: ""
historicms: 1
mask: "255.255.255.255"
dynamic: False
zonetag: ""
username: "USUARIO"
pokefreqnotok: 10000
secret: "CLAVE"
peercontext: ""
callno: 0
mohsuggest: ""
lastms: 1
name: "NOMBRE PEER"
cid_name: ""
context: ""
codecs
codec
frame_length: 80
samplespersecond: 8000
name: "alaw"
description: "G.711 A-law"
A medida que vamos Quitando niveles, nos dará más información. Por ejemplo si nos interesa saber todo lo que pasa en Asterisk en general, solamente debemos ejecutar CLI*> data get /asterisk
Como se podrá apreciar, la información que este devuelve es muy completa y puede ser de gran utilidad para el desarrollo de aplicaciones de monitoreo de Asterisk.
Para cerrar este artículo, voy a mostrar como es posible llamar remotamente a esta API a través del AMI.
Action: Command
ActionID: test
Command: data get Asterisk/channel/iax2/peers \r\n\n
Suscribirse a:
Entradas (Atom)