¡Hola a todos! ![]()
Vengo a compartir una experiencia completa que se transformó en un proyecto de integración para Gladys. En el menú: cómo hice funcionar al 100% localmente una cámara que TP-Link ha intencionalmente limitado (sin RTSP, sin ONVIF), con detección de objetos de IA (persona, perro, gato… e incluso caballo
), todo en un mini-PC que ya ejecuta 2 Gladys y un Home Assistant. Y al final, la propuesta de desarrollo que planeo lanzar.
Aguanten, es un poco largo, pero todo es reproducible. ![]()
El problema inicial
Tengo varias cámaras Tapo, incluida una C660 (4K, pan/tilt, solar/batería — pero conectada a la corriente en mi casa, la batería es solo un respaldo).
Quería lo mismo que todos aquí: controlar mis cámaras y recibir las alertas de detección (persona, animal…) localmente, en Gladys / Node-RED a través de MQTT, sin depender de la nube de TP-Link.
Primer obstáculo: en toda la gama de batería/solar (C425, C460, C660, C645D, D230…), TP-Link desactiva RTSP y ONVIF. Esto está asumido y documentado por el fabricante: «ahorro de energía». El hecho de que la cámara esté alimentada permanentemente no cambia nada, es el firmware quien decide. ![]()
Verificación que no deja lugar a dudas:
$ nmap -Pn -p 443,554,2020,8800 10.6.0.222
PORT STATE SERVICE
443/tcp open https
554/tcp closed rtsp ← RTSP cerrado
2020/tcp closed onvif ← ONVIF cerrado
8800/tcp open ??? ← vaya vaya... 👀
RTSP y ONVIF cerrados… pero un misterioso puerto 8800 abierto.
Segundo obstáculo, válido incluso para las cámaras Tapo con RTSP (mi C520WS, por ejemplo): la transmisión de eventos de detección a través de ONVIF está rota en varios modelos (error conocido del firmware). Por lo tanto, incluso con RTSP, no hay alertas confiables localmente.
La solución: go2rtc habla «Tapo»
El puerto 8800 es el protocolo propietario de TP-Link — el que usa la aplicación Tapo. Y resulta que go2rtc (la navaja suiza de video de AlexxIT, integrada en Frigate Y en Home Assistant) sabe hablarlo nativamente a través de una fuente tapo://.
La arquitectura completa se convierte en:
Cámara (tapo://, rtsp://, onvif://, ...) → go2rtc → Frigate (detección IA) → MQTT → Gladys / Node-RED
Y el punto clave: es Frigate quien realiza la detección de objetos, no el firmware de la cámara. Por lo tanto, no se necesita ONVIF, no se necesita la nube, y una detección mejor que la de TP-Link — la aplicación Tapo me dice «animal» para todo, Frigate distingue person, dog, cat, horse (mapa de etiquetas COCO, 91 clases). En mi caso, necesito detectar con precisión los caballos, lo cual cambia todo. ![]()
Las trampas encontradas (para ahorrarles horas de depuración)
No funcionó a la primera, y cada trampa vale la pena documentarla:
1. La contraseña debe estar codificada en URL. La fuente es tapo://CONTRASEÑA@IP con la contraseña de su cuenta en la nube Tapo (no hay «cuenta de cámara» en estos modelos). Si su contraseña contiene #, ^, %, @… debe codificarse (# → %23, etc.), de lo contrario go2rtc truncará la URL en silencio. Truco:
bash
python3 -c "import urllib.parse,getpass; print(urllib.parse.quote(getpass.getpass('mdp: '), safe=''))"
2. El flujo principal 4K = pantalla negra. Error conocido (SPS/PPS no propagados, cf. issue go2rtc #2202): la cámara envía el video pero go2rtc no puede analizarlo. El substream funciona perfectamente:
tapo://CONTRASEÑA_CODIFICADA@10.6.0.222?channel=0&subtype=1
640×360, es feo a la vista pero es exactamente lo que Frigate quiere para la detección (los modelos trabajan en 300-640 px de todos modos). El 4K se queda en la tarjeta SD de la cámara para la reproducción.
3. Los timestamps corruptos (LA trampa). El flujo tapo genera DTS no monotónicos → ffmpeg se dispara al 190% de CPU, el watchdog de Frigate lo mata en bucle, ningún clip se graba. La corrección que lo arregló todo:
yaml
input_args: -avoid_negative_ts make_zero -fflags +genpts+discardcorrupt -rtsp_transport tcp -use_wallclock_as_timestamps 1
La clave es -use_wallclock_as_timestamps 1: ffmpeg ignora los timestamps de la fuente y los regenera.
4. El iGPU Intel lo cambia todo. Mi servidor es un modesto Beelink U59 (Celeron N5105) que ya aloja HA + 2 Gladys. Como detector de CPU, estaba de rodillas (86% del sistema). Al activar OpenVINO en el iGPU + decodificación VAAPI:
| Métrica | CPU | iGPU (OpenVINO + VAAPI) |
|---|---|---|
| Inferencia | 94,6 ms | 15,8 ms |
| Proceso del detector | 191,8 % | 8,5 % |
| CPU del sistema | 86 % | 22 % |
| Frames descartadas | 7/s | 0 |
Un Celeron al 22% de CPU que hace detección de objetos en tiempo real además de HA y 2 Gladys. ![]()
El resultado
En MQTT, Frigate publica todo lo que soñamos:
frigate/c660/person → 1 / 0 (binario, perfecto para Gladys)
frigate/c660/dog → 1 / 0
frigate/events → JSON rico (etiqueta, puntuación, caja, trayectoria, zonas...)
frigate/reviews → alertas con miniatura
frigate/stats → salud completa (fps, inferencia, almacenamiento...)
Detección validada en la práctica (persona con 0,93 de puntuación, perro reconocido donde Tapo dice «animal»), clips grabados, instantáneas, cero nube. Una cámara «oficialmente imposible de integrar» que funciona mejor localmente que los modelos «compatibles». ![]()
:gear: Configuraciones completas validadas (docker-compose + config Frigate) — haga clic para desplegar
docker-compose.yml:
yaml
services:
frigate:
container_name: frigate
image: ghcr.io/blakeblackshear/frigate:stable
restart: unless-stopped
shm_size: "256mb"
devices:
- /dev/dri/renderD128:/dev/dri/renderD128
volumes:
- ./config:/config
- ./storage:/media/frigate
- type: tmpfs
target: /tmp/cache
tmpfs:
size: 1000000000
ports:
- "8971:8971" # UI (HTTPS desde la 0.17 !)
- "8554:8554" # RTSP restream
- "1984:1984" # go2rtc
config/config.yml:
yaml
mqtt:
enabled: true
host: <su_mosquitto>
user: xxx
password: xxx
detectors:
ov:
type: openvino
device: GPU
model:
width: 300
height: 300
input_tensor: nhwc
input_pixel_format: bgr
path: /openvino-model/ssdlite_mobilenet_v2.xml
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
go2rtc:
streams:
c660:
- tapo://CONTRASEÑA_URL_CODIFICADA@10.6.0.222?channel=0&subtype=1
cameras:
c660:
ffmpeg:
hwaccel_args: preset-vaapi
inputs:
- path: rtsp://127.0.0.1:8554/c660
input_args: -avoid_negative_ts make_zero -fflags +genpts+discardcorrupt -rtsp_transport tcp -use_wallclock_as_timestamps 1
roles: [detect, record]
detect:
enabled: true
fps: 5
width: 640
height: 360
objects:
track: [person, dog, cat, horse]
record:
enabled: true
retain:
days: 7
mode: motion
snapshots:
enabled: true
retain:
default: 14
Notas de operación:
- Frigate 0.17: la interfaz de usuario está en HTTPS en el puerto 8971 (certificado auto-firmado), cuenta de administrador generada en el primer arranque (contraseña en los registros).
shm_size: 128 MB no es suficiente, incluso para 1 cámara.- Las cámaras Tapo limitan los flujos concurrentes → siempre consumir a través de go2rtc (que mutualiza en 1 conexión), nunca directamente.
- Pequeña advertencia
connection reset by peerperiódica en el puerto 8800: la cámara corta de vez en cuando, go2rtc se reconecta solo. No bloqueante.
Y mantenant : propuesta de integración Gladys
Todo esto funciona, pero seamos honestos: entre el nmap, el URL-encoding, los input_args de ffmpeg y la configuración de OpenVINO, esto no es accesible para el común de los mortales. Y es exactamente el tipo de complejidad que Gladys sabe ocultar. ![]()
Por lo tanto, planeo desarrollar una integración « Vigilancia de video local » (nuevo servicio o extensión de rtsp-camera, por discutir) cuyo principio es no reinventar la rueda :
- go2rtc = capa de abstracción protocolar (habla rtsp://, tapo://, onvif://, Ring, Nest, Dahua, USB… y es mantenido por AlexxIT + una gran comunidad). Una integración = todas las cámaras.
- Frigate = detección de objetos + grabaciones + MQTT.
- Gladys = orquestación, configuración simple y exposición de las características.
Lo que haría la integración
- Gestión de contenedores Frigate/go2rtc desde la interfaz de Gladys (instalación, inicio, reinicio) — siguiendo el mismo modelo que lo que ya existe para Zigbee2MQTT.
- Configuración inteligente automática: detección de hardware (¿iGPU Intel presente? → OpenVINO + VAAPI; de lo contrario, CPU), cálculo del
shm_sizesegún el número de cámaras, valores predeterminados estables — todo esto sobrescribible en modo experto. - Añadir cámara simplificado: nombre, tipo (RTSP / Tapo / ONVIF…), IP, contraseña (codificada automáticamente), selección de objetos a detectar (persona, perro, gato, caballo… multi-selección). La integración genera la configuración de Frigate y aplica las correcciones conocidas (substream Tapo, input_args timestamps…) sin que el usuario tenga que saber que existen.
- Características de Gladys creadas automáticamente por cámara:
- la cámara en vivo clásica;
- un binario de detección por tipo de objeto (
frigate/<cam>/person→ sensor de presencia de Gladys → escenas!); - una « cámara de imagen » por tipo: la última imagen capturada de cada detección (probablemente un nuevo tipo de característica de solo imagen, sin transmisión en vivo — por discutir).
- Salud: estado por cámara, contador de reconexiones, estadísticas de Frigate reportadas.
Preguntas abiertas para la comunidad (y @pierre-gilles
)
- Nuevo servicio o extensión de
rtsp-camera? Mi intuición: nuevo servicio (el alcance es muy diferente), pero lo existente debe seguir siendo el camino simple para quienes solo quieran un flujo RTSP. - Nuevo tipo de característica « cámara de solo imagen » (visualización de la última imagen, sin reproductor en vivo): ¿les parece la buena modelización para « última detección de tipo X »?
- Política de contenedores compañeros: Frigate incluye su propio go2rtc, por lo que un solo contenedor es suficiente. ¿De acuerdo en seguir el patrón Z2M?
- Vista en vivo: integración del componente web
video-stream.jsde go2rtc (WebRTC/MSE) con retroceso de instantáneas para flujos caprichosos. Pregunta del proxy a través del servidor Gladys a profundizar (contenido mixto HTTPS/HTTP).
Comienzo el desarrollo con una fase de análisis de lo existente, luego un MVP (contenedor + cámara RTSP genérica + binarios de detección MQTT), luego las fuentes avanzadas (tapo://, onvif://) y el modo en vivo. PRs pequeñas y divididas, como de costumbre.
Todos los comentarios son bienvenidos: casos de uso, cámaras que les gustaría ver soportadas, opiniones sobre las preguntas anteriores… Y si algunos quieren probar la configuración manual mientras tanto, las configuraciones completas están en el desplegable de arriba — ¡respondo a las preguntas! ![]()
¡Hasta pronto, Terdious












