- Python 97.7%
- Shell 2.3%
| docs | ||
| zabbix_alertscripts | ||
| .env.example | ||
| .gitignore | ||
| camera-monitor.service | ||
| camera_monitor.py | ||
| install_ubuntu.sh | ||
| produccion-y-costos-de-whatsapp.md | ||
| README.md | ||
| requirements.txt | ||
| set_whatsapp_token.py | ||
| test_camera_monitor.py | ||
| test_zabbix_alertscript.py | ||
Monitor autónomo de cámaras LAN
Prueba de concepto en Python para detectar caídas y recuperaciones de cámaras
IP y avisar mediante la API oficial de WhatsApp Cloud. Está pensada para Ubuntu,
no abre puertos, no necesita privilegios de root y usa únicamente la
biblioteca estándar de Python.
Estado: PoC validada localmente. El servicio permanente y la integración de WhatsApp para producción todavía no están activados.
Documentos destacados
- WhatsApp: costos y límites explicados para el cliente: qué se cobra, ejemplos para 100 a 500 cámaras, presupuesto sugerido, límites de Meta, cambio anunciado para octubre de 2026 y enlaces oficiales.
- Evidencia de la validación local: cámara utilizada, pruebas ejecutadas, resultados y limitaciones.
Qué resuelve
- Comprueba cualquier cantidad de cámaras mediante ICMP, TCP o ambos.
- Evita declarar una caída por un fallo aislado.
- Mantiene estados independientes
UNKNOWN,UPyDOWN. - Confirma recuperaciones con varias rondas correctas.
- Limita la cantidad de comprobaciones simultáneas.
- Conserva el estado después de reiniciar y evita alertas duplicadas.
- Detecta opcionalmente una posible caída general del gateway.
- Mantiene una cola de notificaciones cuando Meta o Internet no responden.
- Rota los registros y nunca escribe el token en ellos.
- Incluye una unidad endurecida de systemd y un instalador para Ubuntu.
Cómo funciona
Cámaras LAN ──► ping/TCP concurrente ──► máquina de estados
│
Gateway opcional ──► detección de caída general│
▼
cola persistente
│
▼
WhatsApp Cloud API
Para integrar Zabbix sin enviar mensajes reales durante la validación, el
repositorio incluye zabbix_alertscripts/camera_whatsapp_dryrun.py. El script
recibe los datos de una alerta, los registra localmente en formato JSON y no
realiza conexiones de red. Se instalará como alert script de Zabbix antes de
crear el medio y la acción exclusivos para cámaras.
Para una validación temporal con WhatsApp Cloud API real existe además
zabbix_alertscripts/camera_whatsapp_test.py. Lee sus valores únicamente de
/etc/zabbix/camera-whatsapp-test.env en el CT de Zabbix y envía texto libre.
Debe usarse solo mientras el destinatario haya abierto una ventana de atención;
las alertas autónomas fuera de esa ventana requieren una plantilla utility.
El canal preparado para producción es
zabbix_alertscripts/camera_whatsapp_template.py. Usa la plantilla utility
camera_status_alert con cuatro parámetros: estado, cámara, hora y referencia
del evento. No se activa ni se instala con credenciales: cuando exista un
número propio, se crea /etc/zabbix/camera-whatsapp.env con los datos reales,
se instala el script como medio Script de Zabbix y se cambia la acción desde
dry-run de manera controlada.
Una ronda fallida no equivale inmediatamente a una caída. Cada cámara pasa a
DOWN después de FAILURE_ROUNDS_BEFORE_DOWN rondas completas fallidas. Una
cámara caída vuelve a UP sólo después de
SUCCESS_ROUNDS_BEFORE_RECOVERY rondas correctas consecutivas.
Cuando se detecta una caída común de red, se genera un único aviso de
infraestructura para evitar una tormenta de mensajes. En cambio, las
recuperaciones siempre se notifican por host: cada cámara emite su propio
evento RECOVERY una vez que confirma su vuelta a UP; no se envía un mensaje
genérico de recuperación de red que oculte qué cámaras volvieron.
Estado de la demostración
La prueba realizada el 17 de agosto de 2026 usó:
- Ubuntu 26.04 LTS, Python 3.14.4 y systemd 259.
- Cámara
De los Picaflores Oeste,192.168.100.63, RTSP/TCP 554. - Modo
ping_and_tcp; no se copiaron credenciales ni rutas RTSP. - Tres rondas fallidas y una única transición
UNKNOWN→DOWN. - Un
hello_worldaceptado por Meta. - Un texto libre de prueba aceptado dentro de la ventana de servicio y confirmado como recibido por el usuario.
- 24 pruebas automatizadas, sin tráfico real hacia cámaras ni Meta.
El detalle y las limitaciones de esa validación están en docs/validacion-poc.md.
Requisitos
- Linux con
pingcompatible con iputils. - Python 3.11 o posterior recomendado.
- Acceso de red desde el equipo monitor hacia las cámaras.
- systemd sólo si se desea instalar el servicio permanente.
- Sin paquetes de Python externos.
Inicio rápido
git clone https://forge.custronix.com/custronix/camera-monitor-poc.git
cd camera-monitor-poc
cp .env.example .env
chmod 600 .env
python3 camera_monitor.py --check-config
python3 -m unittest -v
python3 camera_monitor.py --once --dry-run
python3 camera_monitor.py --show-status
--dry-run ejecuta la lógica completa y conserva las notificaciones pendientes,
pero nunca llama a Meta.
Configurar cámaras
Edite únicamente el bloque CONFIGURACIÓN EDITABLE al principio de
camera_monitor.py:
CAMERAS = [
{
"name": "Entrada",
"host": "192.168.100.101",
"enabled": True,
"check_mode": "ping_and_tcp",
"port": 554,
},
{
"name": "Patio",
"host": "192.168.100.102",
"enabled": False,
"check_mode": "tcp",
"port": 554,
},
]
Modos disponibles:
| Modo | Condición para considerar la cámara disponible |
|---|---|
ping |
Responde ICMP. |
tcp |
Acepta una conexión al puerto configurado. |
ping_and_tcp |
Responde ICMP y acepta TCP. |
ping_or_tcp |
Responde al menos uno de los dos métodos. |
No se necesitan credenciales RTSP: la prueba TCP abre una conexión y la cierra
inmediatamente. Si una cámara bloquea ICMP, use tcp o ping_or_tcp.
Después de editar:
python3 camera_monitor.py --check-config
El validador identifica nombres duplicados, hosts vacíos o inválidos, puertos fuera de rango, modos desconocidos y parámetros globales inconsistentes.
Parámetros iniciales
| Parámetro | Valor | Efecto |
|---|---|---|
| Intervalo normal | 30 s | Tiempo entre rondas. |
| Intentos rápidos | 3 | Intentos dentro de una ronda. |
| Pausa rápida | 5 s | Espera entre intentos. |
| Timeout ICMP/TCP | 3 s | Límite individual. |
| Umbral de caída | 3 rondas | Confirma DOWN. |
| Umbral de recuperación | 2 rondas | Confirma UP después de DOWN. |
| Repetición de alerta DOWN | 0 | No repite mientras siga caída. |
| Trabajadores | 10 | Máximo de cámaras simultáneas. |
| Cola | 100 | Máximo de notificaciones pendientes. |
| Registros | 5 × 2 MiB | Rotación local. |
El gateway 192.168.100.1 está configurado para la demostración, pero su
control permanece desactivado. Al replicar el proyecto, cambie
GATEWAY_HOST y active GATEWAY_CHECK_ENABLED sólo después de comprobarlo.
Comandos
| Comando | Función |
|---|---|
--check-config |
Valida sin comprobar cámaras ni enviar mensajes. |
--once |
Ejecuta una ronda y termina. |
--show-status |
Muestra estados y cola pendiente. |
--dry-run |
Impide cualquier envío a Meta. |
--test-notification |
Envía exactamente un hello_world. |
--test-text-notification |
Envía un texto manual para la primera cámara DOWN; sólo funciona dentro de la ventana de servicio. |
Configuración de WhatsApp para pruebas
El repositorio incluye .env.example. El archivo real .env está ignorado por
Git y debe conservar permisos restrictivos.
cp .env.example .env
chmod 600 .env
python3 set_whatsapp_token.py .env
El helper solicita el token sin eco, lo escribe atómicamente y activa
WHATSAPP_ENABLED=true. No pegue tokens en comandos, incidencias, commits o
chats.
Para cargar el entorno en una prueba local:
set -a
. ./.env
set +a
python3 camera_monitor.py --test-notification
hello_world no acepta detalles dinámicos. --test-text-notification sirve
únicamente para una prueba manual después de que el destinatario haya escrito al
número de Meta y abierto la ventana de atención. Ninguna de las dos opciones es
la solución automática de producción.
Instalación como servicio Ubuntu
Ejecute esto sólo después de validar cámaras reales en --dry-run:
sudo ./install_ubuntu.sh
sudo /opt/camera-monitor/set_whatsapp_token.py \
/etc/camera-monitor/camera-monitor.env
sudo -u camera-monitor /usr/bin/python3 \
/opt/camera-monitor/camera_monitor.py --check-config
El instalador crea:
- usuario bloqueado
camera-monitor; - aplicación en
/opt/camera-monitor; - entorno en
/etc/camera-monitor/camera-monitor.env; - estado en
/var/lib/camera-monitor; - registros en
/var/log/camera-monitor; - unidad
/etc/systemd/system/camera-monitor.service.
Deliberadamente no habilita ni inicia el servicio. Valide una ronda como el usuario de servicio antes de activarlo:
sudo -u camera-monitor env \
CAMERA_MONITOR_STATE_FILE=/var/lib/camera-monitor/camera_state.json \
CAMERA_MONITOR_LOG_FILE=/var/log/camera-monitor/camera_monitor.log \
/usr/bin/python3 /opt/camera-monitor/camera_monitor.py --once --dry-run
sudo systemctl enable --now camera-monitor.service
systemctl status camera-monitor.service
journalctl -u camera-monitor.service -f
Producción con WhatsApp
La PoC todavía usa hello_world para alertas automáticas. Antes de producción
se necesita un número empresarial, token de usuario de sistema, plantilla
utility aprobada con parámetros, método de pago, seguimiento de estados por
webhook y controles de gasto y seguridad.
La guía completa, incluidos costos vigentes para Ecuador y el cambio anunciado para octubre de 2026, está en produccion-y-costos-de-whatsapp.md.
Archivos principales
| Archivo | Propósito |
|---|---|
camera_monitor.py |
Monitor, configuración, CLI y notificaciones. |
test_camera_monitor.py |
Pruebas con cámaras y Meta simulados. |
.env.example |
Plantilla publicable, sin credenciales. |
set_whatsapp_token.py |
Ingreso silencioso y atómico del token. |
camera-monitor.service |
Unidad systemd endurecida. |
install_ubuntu.sh |
Instalación portable sin activación automática. |
docs/validacion-poc.md |
Evidencia y alcance de la prueba local. |
produccion-y-costos-de-whatsapp.md |
Acceso visible a requisitos, costos y plan de producción. |
docs/whatsapp-produccion.md |
Guía técnica completa de producción. |
El estado, los registros, .env y __pycache__ están excluidos mediante
.gitignore.
Limitaciones actuales
- El envío automático sigue usando la plantilla estática
hello_world. - No se reciben webhooks de entrega, lectura o fallo.
- El servicio systemd está preparado, pero no instalado ni activo.
- La configuración de cámaras sigue dentro del código.
- Sólo existe un destinatario de WhatsApp.
- No hay presupuesto diario, métrica de costo ni panel de salud.
- Un HTTP 200 de Meta confirma aceptación, no entrega al teléfono.
Estas limitaciones son deliberadas para mantener pequeña y auditable la PoC.