← Volver al índice
📞 Salescare — Monitor Asterisk en tiempo real

Salescare Panel

Panel de monitorización en tiempo real del estado de extensiones de la centralita Salescare. Expone una API REST para que QueueMetrics libere canales bloqueados automáticamente.

🌟 Python 3 + aiohttp (async)
WebSocket + AMI
🌐 Puerto 8090
🔌 systemd Linux
En producción
0
Base de datos (todo en memoria)
5
Estados de extensión posibles
WS
WebSocket UI en tiempo real
AMI
Asterisk Manager Interface

Cómo funciona

Conexión persistente al AMI de Asterisk Salescare. Estado de extensiones sincronizado en memoria vía eventos AMI. UI actualizada en tiempo real por WebSocket. API REST para integración con QueueMetrics.

🔌 AMI Client

Conexión persistente con reconexión automática. Escucha ExtensionStatus, DeviceStateChange, Newchannel, Hangup. Rastrea canales activos por extensión.

💡 Estado en memoria

Sin base de datos. Estado completo en dict Python: extensión → {state, since, channels[]}. Se reconstruye completamente desde AMI al arrancar. Cero I/O de disco.

⚡ WebSocket broadcast

Cada cambio de estado AMI se propaga a todos los clientes WebSocket conectados. La UI de monitorización refleja el estado en <100ms sin polling.

Flujo QueueMetrics → Hangup

QueueMetrics detecta extensiones bloqueadas y las libera automáticamente via la API REST del panel.

1
QueueMetrics detecta discrepancia — agente libre en QM pero state: inuse en /api/extensions
2
POST /api/extensions/1200/hangup — con header X-API-Key: <key>
3
Panel abre conexión AMI dedicadaEvents: off, ejecuta Action: Hangup para cada canal activo de la extensión
4
Asterisk libera el canal — AMI emite ExtensionStatus con estado NOT_INUSE
5
Panel actualiza estado — WebSocket broadcast a la UI, extensión aparece libre
6
QM verifica en próximo pollstate: available, agente listo para nuevas llamadas

Endpoints REST

API REST consumida por QueueMetrics y la UI de monitorización.

Método Endpoint Descripción Auth
GET /api/extensions Estado de todas las extensiones + canales activos
POST /api/extensions/{exten}/hangup Cuelga todos los canales activos de una extensión X-API-Key
GET /api/health Health check + estado de conexión AMI
WS /ws WebSocket — estado en tiempo real

Respuesta ejemplo de GET /api/extensions:

{ "1200": { "state": "inuse", "since": 1717594123.4, "channels": ["SIP/1200-00001abc"], "context": "from-internal" }, "1201": { "state": "available", "since": 1717594000.0, "channels": [], "context": "from-internal" } }

Estados de extensión

Cinco estados posibles derivados de los eventos AMI ExtensionStatus y DeviceStateChange.

EstadoDescripciónColor UI
available Extensión libre, sin llamada activa Verde
inuse En llamada. Puede haber uno o varios canales activos Naranja
ringing Sonando, entrante sin responder Cyan
onhold Llamada en espera Púrpura
unavailable Extensión no registrada o sin dispositivo Gris

Módulos del proyecto

Cuatro módulos Python asincrónos con responsabilidades bien delimitadas.

MóduloResponsabilidad
backend/ami_client.py Conexión AMI persistente, suscripción a eventos, tracking de canales activos por extensión, ami_hangup() con conexión dedicada
backend/server.py PanelServer: endpoints REST + WebSocket, broadcast de cambios de estado, integración con AMI client
backend/config.py Loader INI para secciones [ami], [web], [auth], [names]
backend/main.py Entry point: arranque, bucle de reconexión AMI con backoff exponencial

Configuración y despliegue

📄 config.ini

[ami] host = <IP_ASTERISK_SALESCARE> port = 5038 username = salescare-panel secret = <SECRET> [web] host = 0.0.0.0 port = 8090 [auth] api_key = <API_KEY_PARA_QUEUEMETRICS> [names] 1200 = Nombre Agente 1201 = Otro Agente

🔌 Servicio systemd

Deploy en servidor Linux Asterisk Salescare.

  • Servicio: systemdsalescare-panel
  • Path: /opt/jmfernandez/salescare-panel
  • Deploy: bash deploy.sh
  • Puerto: 8090 (mismo servidor que Asterisk Salescare)

Consideraciones importantes

⏳ Ventana de detección de canal

Los eventos Newchannel/Hangup del AMI son eventuales. Hay una pequeña ventana desde que la extensión entra en llamada hasta que el canal queda registrado en el dict. Si QueueMetrics pide el hangup durante esa ventana, la API devuelve 400 y QM debe reintentar.

⚡ Conexión AMI dedicada para hangup

El endpoint POST /hangup abre una segunda conexión AMI temporal con Events: off. No interfiere con la conexión principal de monitorización. La respuesta indica qué canales se colgaron exitosamente.

🔄 Sin base de datos

Todo el estado está en memoria. En caso de reinicio del servicio, el estado se reconstruye desde el AMI (los eventos de reconexión lo rellenan). No hay CDR, no hay exportaciones, no hay persistencia.

👤 Nombres de agentes

La sección [names] del config.ini mapea extensión a nombre para mostrar en la UI. Para añadir o modificar nombres hay que editar el fichero y reiniciar el servicio.