Saltearse al contenido

Taller 6: Buzón de Voz Avanzado con Notificaciones por WhatsApp

Convierte el buzón de voz en un sistema proactivo con externnotify, scripts y buenas prácticas de producción

📬 Taller 6: Buzón de Voz Avanzado con Notificaciones por WhatsApp

Sección titulada «📬 Taller 6: Buzón de Voz Avanzado con Notificaciones por WhatsApp»

🧩 El Problema Real: La “Caja Negra” del Buzón de Voz

Sección titulada «🧩 El Problema Real: La “Caja Negra” del Buzón de Voz»

Las notificaciones por email son lentas y a menudo se pierden en bandejas de entrada saturadas. Los usuarios no se enteran de que tienen mensajes de voz importantes hasta que es demasiado tarde. ¿Cómo hacer que una notificación de voicemail sea tan inmediata como un mensaje de texto?

🪄 La Solución de Producción: Integración con APIs de Mensajería

Sección titulada «🪄 La Solución de Producción: Integración con APIs de Mensajería»

Usaremos la potente función externnotify de Asterisk. Esta directiva ejecuta un script personalizado cada vez que se deja un nuevo mensaje de voz. Nuestro script actuará como puente entre Asterisk y una API web (WhatsApp).


6.0 Buenas Prácticas: Backup y Seguridad Primero

Sección titulada «6.0 Buenas Prácticas: Backup y Seguridad Primero»

Antes de tocar configuración o scripts, realiza un respaldo y asegura el servidor.

Terminal window
cd /etc/asterisk
cp -rfv . ../asterisk.bk-$(date +%F-%H%M)

Esto genera una carpeta con timestamp para rollback rápido.

Si no lo configuraste en talleres previos, limita puertos de señalización y media:

Terminal window
ufw allow 5060/udp
ufw allow 10000:20000/udp
# (Opcional) Restringe a tu red/local o IPs de confianza
ufw allow from 192.168.1.0/24 to any port 5060 proto udp
ufw allow from 192.168.1.0/24 to any port 10000:20000 proto udp

6.1 La Fundación: Configurando el Sistema de Voicemail

Sección titulada «6.1 La Fundación: Configurando el Sistema de Voicemail»

Primero, necesitamos un sistema de buzón de voz funcional.

Terminal window
# Estando en /etc/asterisk/
nano voicemail.conf

Limpia el archivo si tiene contenido de ejemplo y añade la siguiente configuración (usaremos [default]).

[general]
format=wav49|gsm|wav
serveremail=asterisk@tudominio.com
attach=yes
maxsilence=10
silencethreshold=128
maxlogins=3
moveheard=yes
[default]
; sintaxis: buzon => contraseña,Nombre Completo,email
1001 => 1234,Usuario Oficina,email@dominio.com
1002 => 5678,Agente Soporte,email2@dominio.com
1003 => 9012,Personal Almacen,email3@dominio.com

6.1.2 Vincular Endpoints a Buzones en pjsip.conf

Sección titulada «6.1.2 Vincular Endpoints a Buzones en pjsip.conf»

Añadimos mailboxes= en el objeto endpoint para activar MWI (Message Waiting Indicator) y asociación con el buzón.

Terminal window
nano /etc/asterisk/pjsip.conf
; --- Extensión 1001: Usuario de Oficina ---
[1001](endpoint-template)
context=cat1
mailboxes=1001@default ; <--- Añadir esta línea
auth=1001
aors=1001
callerid = Usuario Oficina <1001>
; --- Extensión 1002: Agente Soporte ---
[1002](endpoint-template)
context=cat2
mailboxes=1002@default ; <--- Añadir esta línea
auth=1002
aors=1002
callerid = Agente Soporte <1002>
; --- Extensión 1003: Teléfono Almacén ---
[1003](endpoint-template)
context=cat3 ; categoría propia si aplica
mailboxes=1003@default ; <--- Añadir esta línea
auth=1003
aors=1003
callerid = Almacen <1003>

6.1.3 Actualizar el Dialplan para Usar Voicemail

Sección titulada «6.1.3 Actualizar el Dialplan para Usar Voicemail»

Necesitamos dos cosas: una forma de dejar mensajes y una forma de escucharlos.

  1. Modificar extensions_anexos.conf para desviar a buzón según DIALSTATUS:
Terminal window
nano extensions_anexos.conf
[anexos-internos]
; Lógica para llamar entre extensiones internas (1001, 1002, 1003)
exten => _100X,1,NoOp(Llamada interna a la extension ${EXTEN})
same => n,Set(BUZON=${EXTEN}) ; Guarda el número de extensión en variable BUZON
same => n,Dial(PJSIP/${EXTEN},20,tT)
same => n,Goto(s-${DIALSTATUS},1) ; Salta a etiqueta según resultado
exten => s-BUSY,1,Voicemail(${BUZON}@default,b) ; Ocupado -> anuncio "busy"
same => n,Hangup()
exten => s-NOANSWER,1,Voicemail(${BUZON}@default,u) ; No contesta -> "unavailable"
same => n,Hangup()
exten => _s-.,1,Goto(s-NOANSWER,1) ; Otros estados -> unavailable
; [anexos-internos]
; ; Lógica para llamar entre extensiones internas (1001, 1002, 1003)
; exten => _100X,1,NoOp(Llamada interna a la extension ${EXTEN})
; same => n,Dial(PJSIP/${EXTEN},30,tT)
; same => n,Hangup()
  1. Añadir acceso a buzón en extensions_funciones.conf:
Terminal window
nano extensions_funciones.conf
[funciones-voicemail]
; El usuario marca *97 y Asterisk usa su CallerID para ir directo a su buzón
exten => *97,1,NoOp(Acceso a buzón de voz para ${CALLERID(num)})
same => n,Answer()
same => n,VoicemailMain(${CALLERID(num)}@default)
same => n,Hangup()
exten => *98,1,NoOp(Acceso a cualquier buzon)
same => n,Answer()
same => n,VoicemailMain()
same => n,Hangup()
  1. Otorgar permisos en extensions_categorias.conf:
Terminal window
nano extensions_categorias.conf
[cat1]
include => anexos-internos
include => funciones-voicemail ; <-- Añadir
include => salidas-celular
[cat2]
include => anexos-internos
include => funciones-voicemail ; <-- Añadir
[cat3]
include => anexos-internos
include => funciones-voicemail

6.2 El Puente: Script de Notificación por WhatsApp

Sección titulada «6.2 El Puente: Script de Notificación por WhatsApp»

Usaremos CallMeBot, un servicio gratuito que permite enviar mensajes de WhatsApp vía una API HTTP GET.

  • Pasos para obtener tu API Key:
    1. Añade el número de CallMeBot a tu teléfono y envía el mensaje de activación.
    2. Recibirás tu API Key personal (guárdala como contraseña).
    3. Ten a mano tu teléfono en formato internacional (ej: 51987654321).
Terminal window
nano /var/lib/asterisk/agi-bin/notify_whatsapp.sh
#!/bin/bash
# --- MODO DE SIMULACIÓN ---
# Poner en "true" para escribir en un log en lugar de enviar un mensaje real.
# ¡Perfecto para probar sin gastar cuota y si el servicio está caído!
SIMULATION_MODE="true"
# --- CONFIGURACIÓN DE LA API (REEMPLAZAR CON TUS DATOS) ---
PHONE_NUMBER="TU_NUMERO_DE_TELEFONO" # Ej: 51987654321
API_KEY="TU_API_KEY"
# --- CAPTURA DE ARGUMENTOS DE ASTERISK ---
# externnotify pasa estos argumentos al script.
VM_CONTEXT="$1"
VM_MAILBOX="$2"
VM_CALLERID_NUM="$3"
VM_CALLERID_NAME="$4"
VM_DURATION="$5"
# --- LÓGICA DEL SCRIPT ---
LOG_FILE="/var/log/asterisk/whatsapp_notifications.log"
# Formateamos el mensaje que queremos enviar
# Usamos URL encoding para los espacios (%20) y saltos de línea (%0A)
MESSAGE="¡Nuevo%20Voicemail!%0A-%20Buzón:%20${VM_MAILBOX}%0A-%20De:%20${VM_CALLERID_NAME}%20(${VM_CALLERID_NUM})%0A-%20Duración:%20${VM_DURATION}%20segundos."
if [ "$SIMULATION_MODE" = "true" ]; then
# MODO SIMULACIÓN: Escribimos en un archivo de log
echo "$(date): SIMULACIÓN - Mensaje para ${PHONE_NUMBER}: ${MESSAGE}" >> ${LOG_FILE}
else
# MODO REAL: Construimos la URL y la llamamos con curl
URL="https://api.callmebot.com/whatsapp.php?phone=${PHONE_NUMBER}&text=${MESSAGE}&apikey=${API_KEY}"
echo "$(date): ENVIANDO - Mensaje para ${PHONE_NUMBER}" >> ${LOG_FILE}
# Usamos curl para hacer la petición a la API. -s (silencioso), -o /dev/null (descarta la salida)
curl -s -o /dev/null "$URL"
fi
exit 0
Terminal window
chmod +x /var/lib/asterisk/agi-bin/notify_whatsapp.sh

6.3 La Conexión Final: Activando externnotify

Sección titulada «6.3 La Conexión Final: Activando externnotify»

Dile a Asterisk que use el script cada vez que llegue un nuevo voicemail.

Terminal window
nano /etc/asterisk/voicemail.conf

Añade en [general]:

[general]
...
externnotify=/var/lib/asterisk/agi-bin/notify_whatsapp.sh
...

6.4 ¡A Probar la Notificación Instantánea!

Sección titulada «6.4 ¡A Probar la Notificación Instantánea!»
  1. Recarga los módulos:
Terminal window
asterisk -rx "voicemail reload"
asterisk -rx "dialplan reload"
asterisk -rx "pjsip reload"
  1. Prepara la depuración:
  • Terminal 1 (CLI de Asterisk): asterisk -rvvv
  • Terminal 2 (Log de Notificaciones): touch /var/log/asterisk/whatsapp_notifications.log && tail -f /var/log/asterisk/whatsapp_notifications.log
  1. La prueba:
  • Desde la extensión 1001, llama a la 1002.
  • Deja que suene hasta que salte el buzón de voz.
  • Deja un mensaje corto y cuelga.
  1. Verifica los resultados:
  • En el CLI: verás que externnotify se ejecutó.
  • En el log: verás registros como:
Mon Oct 28 10:30:00 2024: SIMULACIÓN - Mensaje para 51987654321: ¡Nuevo%20Voicemail!...
  • (Opcional - Modo real): Si SIMULATION_MODE="false", revisa tu WhatsApp.
  1. Prueba de escucha:
  • Desde 1002, marca *97 para entrar a tu buzón y escuchar el mensaje. La luz MWI debería encenderse.

  • Logs útiles: /var/log/asterisk/full y /var/log/asterisk/whatsapp_notifications.log.
  • Permisos: si el script no corre, revisa chmod y propiedad (usuario asterisk).
  • URL encoding: añade más campos al mensaje usando %0A entre líneas.
  • Seguridad: guarda API_KEY y PHONE_NUMBER en variables de entorno o archivo protegido; exporta y usa en el script.
  • Alternativas: puedes cambiar CallMeBot por otra API (Twilio, Meta Cloud API) ajustando la llamada curl.

✅ Siguiente Paso

Integra este sistema con un dashboard o agrega confirmación de lectura. O continúa con el siguiente módulo práctico del curso.