Usar Webcam como videovigilancia inteligente con IA en Raspberry Pi (Docker, Frigate y Telegram)

Nota: En calidad de Afiliado, obtengo ingresos por las compras adscritas que cumplen los requisitos aplicables. Algunos de los enlaces de esta página son enlaces de afiliado, lo que significa que si compras a través de ellos, gano una pequeña comisión sin ningún coste adicional para ti.

En este tutorial vamos a convertir cualquier Raspberry Pi con una webcam USB estándar en un sistema de videovigilancia profesional con detección de personas por Inteligencia Artificial y avisos instantáneos con foto en Telegram.

A diferencia de los sistemas tradicionales como MotionEye (que saltan por cualquier cambio de luz o movimiento de hojas), este montaje utiliza Frigate NVR para analizar la imagen mediante redes neuronales en tiempo real, garantizando cero falsas alarmas.

🛠️ Requisitos previos

  • Raspberry Pi (Recomendado Raspberry Pi 4 de 4GB/8GB o Raspberry Pi 5).
  • Sistema Operativo: Raspberry Pi OS / Debian 64 bits con Docker y Docker Compose instalados.
  • Cámara: Cualquier webcam USB estándar compatible con la norma UVC (Logitech, Trust, modelos genéricos sin marca, etc.).
  • Una cuenta de Telegram.

📸 Paso 1: Identificar la webcam USB en Linux

Conecta tu webcam a cualquier puerto USB de la Raspberry Pi. En Linux, las cámaras USB crean varios nodos de vídeo. Para comprobarlos, ejecuta:

ls -l /dev/video*

Normalmente verás /dev/video0 y /dev/video1. El nodo principal de captura de vídeo suele ser /dev/video0.

Para consultar las resoluciones y formatos nativos compatibles con tu cámara:

v4l2-ctl --list-formats-ext

📁 Paso 2: Crear la estructura de carpetas y Mosquitto

Crearemos una carpeta organizada para alojar todos los ficheros de configuración del proyecto:

mkdir -p ~/camara-ia/mosquitto/config ~/camara-ia/mosquitto/data ~/camara-ia/mosquitto/log ~/camara-ia/frigate/config ~/camara-ia/notifier
cd ~/camara-ia

Configurar el Broker MQTT (Mosquitto)

Frigate utiliza MQTT para comunicar los eventos de detección en tiempo real. Creamos el archivo de configuración para Mosquitto:

echo -e "listener 1883\nallow_anonymous true" | sudo tee ./mosquitto/config/mosquitto.conf

🤖 Paso 3: Configurar Frigate NVR (config.yml)

Crea el archivo ~/camara-ia/frigate/config/config.yml y pega la configuración base adaptada a webcams USB genéricas:

# 1. Configuración de conexión MQTT
mqtt:
  enabled: true
  host: mosquitto
  port: 1883

# 2. Motor de inferencia por CPU
detectors:
  cpu1:
    type: cpu

# 3. Configuración de la Cámara USB
cameras:
  webcam_usb:
    enabled: true
    ffmpeg:
      inputs:
        - path: /dev/video0
          roles:
            - detect
            - record
          input_args:
            - -f
            - v4l2
            - -input_format
            - mjpeg # Cambiar a yuyv422 si tu webcam no admite mjpeg
            - -video_size
            - 1280x720 # Resolución recomendada para rendimiento óptimo
            - -framerate
            - "15"
    detect:
      enabled: true
      width: 1280
      height: 720
      fps: 5 # 5 FPS es el estándar perfecto para detección por IA

    objects:
      track:
        - person # Objeto a rastrear

# 4. Grabación y retención de eventos
record:
  enabled: true
  retain:
    days: 3
  events:
    retain:
      default: 7

📲 Paso 4: Configurar el Bot Notificador de Telegram

Para recibir la foto de la persona detectada en el móvil al instante, crearemos un servicio ligero en Python.

1. Obtener las credenciales de Telegram

  1. Abre Telegram, busca al usuario @BotFather y envía el comando /newbot. Sigue los pasos y guarda el API TOKEN generado.
  2. Abre el chat de tu nuevo bot y pulsa Iniciar.
  3. Busca al bot @userinfobot, envíale cualquier mensaje y anota el número que aparece en Id:.

2. Crear el script de Python (script.py)

Crea el archivo ~/camara-ia/notifier/script.py:

import json
import os
import time
import requests
import paho.mqtt.client as mqtt

MQTT_HOST = os.getenv("MQTT_HOST", "mosquitto")
TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
FRIGATE_URL = os.getenv("FRIGATE_URL", "http://frigate:5000")

def on_connect(client, userdata, flags, rc, properties=None):
    if rc == 0:
        print("[NOTIFIER] -> Conectado con éxito al Broker MQTT.")
        client.subscribe("frigate/events")
        print("[NOTIFIER] -> Suscrito al canal 'frigate/events'. Esperando detecciones...")
    else:
        print(f"[NOTIFIER] -> Error de conexión a MQTT. Código: {rc}")

def on_message(client, userdata, msg):
    try:
        payload = json.loads(msg.payload.decode())
        event_type = payload.get("type")
        
        # 'new' avisa al entrar en escena, 'end' cuando finaliza el evento
        if event_type in ["new", "end"]:
            after = payload.get("after", {})
            label = after.get("label", "")
            camera = after.get("camera", "")
            event_id = after.get("id", "")
            
            if label == "person":
                print(f"[NOTIFIER] -> ¡Persona detectada ({event_type})! Enviando alerta...")
                snapshot_url = f"{FRIGATE_URL}/api/events/{event_id}/snapshot.jpg"
                caption = f"⚠️ Detección: {label.upper()}\nCámara: {camera}"
                
                # Descargar snapshot de Frigate y enviar por Telegram
                res = requests.get(snapshot_url, timeout=5)
                if res.status_code == 200:
                    tg_res = requests.post(
                        f"https://api.telegram.org/bot{TOKEN}/sendPhoto",
                        data={"chat_id": CHAT_ID, "caption": caption},
                        files={"photo": ("snapshot.jpg", res.content)},
                        timeout=10
                    )
                    if tg_res.status_code == 200:
                        print("[NOTIFIER] -> Foto enviada correctamente a Telegram.")
                    else:
                        print(f"[NOTIFIER] -> Error Telegram API: {tg_res.text}")
                else:
                    print(f"[NOTIFIER] -> No se pudo obtener snapshot (Status {res.status_code})")
    except Exception as e:
        print("[NOTIFIER] -> Error procesando evento:", e)

# Compatibilidad con Paho MQTT v2
try:
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
except AttributeError:
    client = mqtt.Client()

client.on_connect = on_connect
client.on_message = on_message

print(f"[NOTIFIER] -> Conectando a {MQTT_HOST}:1883...")

# Bucle de reintento automático
connected = False
while not connected:
    try:
        client.connect(MQTT_HOST, 1883, 60)
        connected = True
    except Exception as err:
        print(f"[NOTIFIER] -> Esperando a Mosquitto... ({err})")
        time.sleep(3)

client.loop_forever()

3. Crear el Dockerfile del notificador

Crea el archivo ~/camara-ia/notifier/Dockerfile:

FROM python:3.11-slim
RUN pip install paho-mqtt requests
COPY script.py /script.py
CMD ["python", "-u", "/script.py"]

🚀 Paso 5: Despliegue con Docker Compose

Crea el archivo ~/camara-ia/docker-compose.yml para orquestar todos los servicios:

services:
# Servidor MQTT
mosquitto:
container_name: mosquitto
image: eclipse-mosquitto:latest
restart: unless-stopped
ports:
– «1883:1883»
volumes:
– ./mosquitto/config/mosquitto.conf:/mosquitto/config/mosquitto.conf
– ./mosquitto/data:/mosquitto/data
– ./mosquitto/log:/mosquitto/log

# Frigate NVR
frigate:
container_name: frigate
privileged: true
restart: unless-stopped
image: ghcr.io/blakeblackshear/frigate:stable
shm_size: «256mb»
devices:
– /dev/video0:/dev/video0
– /dev/video1:/dev/video1
volumes:
– /etc/localtime:/etc/localtime:ro
– ./frigate/config:/config
– /media/frigate:/media/frigate
– type: tmpfs
target: /tmp/cache
tmpfs:
size: 1000000000
ports:
– «8971:8971» # Panel Web con contraseña
– «127.0.0.1:5000:5000» # Acceso interno sin contraseña
– «8554:8554» # Streams RTSP
– «8555:8555/tcp»
– «8555:8555/udp»
environment:
FRIGATE_RTSP_PASSWORD: «CambiaEstaPasswordSegura»
depends_on:
– mosquitto

# Notificador de Telegram
frigate-notifier:
container_name: frigate-notifier
build: ./notifier
restart: unless-stopped
environment:
– MQTT_HOST=mosquitto
– FRIGATE_URL=http://frigate:5000
– TELEGRAM_BOT_TOKEN=TU_TOKEN_AQUI # <– Pega tu Token
– TELEGRAM_CHAT_ID=TU_CHAT_ID_AQUI # <– Pega tu Chat ID
depends_on:
– frigate
– mosquitto

🚦 Paso 6: Puesta en marcha y verificación

  1. Arranca todos los contenedores y compila el notificador localmente:Bashdocker compose up -d --build
  2. Comprueba los registros del bot de Telegram para verificar que está esperando eventos:Bashdocker logs -f frigate-notifier (Debes ver [NOTIFIER] -> Conectado con éxito al Broker MQTT).
  3. Accede al panel web seguro de Frigate desde tu navegador: https://IP_DE_TU_RASPBERRY_PI:8971 (La primera vez te pedirá definir usuario y contraseña de administrador).

¡Listo! Pasa por delante de tu webcam y en 2-3 segundos recibirás un aviso en Telegram con la imagen de la persona detectada.

 


Categories:

,

Comments

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *