Bonjour à tous ! ![]()
Je viens partager un retour d’expérience complet qui s’est transformé en projet d’intégration pour Gladys. Au menu : comment j’ai fait fonctionner en 100 % local une caméra que TP-Link a volontairement bridée (pas de RTSP, pas d’ONVIF), avec de la détection d’objets IA (personne, chien, chat… et même cheval
), le tout sur un mini-PC qui fait déjà tourner 2 Gladys et un Home Assistant. Et à la fin, la proposition de développement que je compte lancer.
Accrochez-vous, c’est un peu long, mais tout est reproductible. ![]()
La problématique de départ
J’ai plusieurs caméras Tapo, dont une C660 (4K, pan/tilt, solaire/batterie — mais branchée sur secteur chez moi, la batterie n’est qu’un secours).
Je voulais la même chose que tout le monde ici : contrôler mes caméras et recevoir les alertes de détection (personne, animal…) en local, dans Gladys / Node-RED via MQTT, sans dépendre du cloud TP-Link.
Premier mur : sur toute la gamme batterie/solaire (C425, C460, C660, C645D, D230…), TP-Link désactive RTSP et ONVIF. C’est assumé et documenté par le constructeur : « économie d’énergie ». Le fait que la caméra soit alimentée en permanence sur secteur n’y change rien, c’est le firmware qui décide. ![]()
Vérification qui ne laisse aucun doute :
$ nmap -Pn -p 443,554,2020,8800 10.6.0.222
PORT STATE SERVICE
443/tcp open https
554/tcp closed rtsp ← RTSP fermé
2020/tcp closed onvif ← ONVIF fermé
8800/tcp open ??? ← tiens tiens... 👀
RTSP et ONVIF fermés… mais un mystérieux port 8800 ouvert.
Second mur, valable même pour les caméras Tapo avec RTSP (ma C520WS par exemple) : la remontée des événements de détection via ONVIF est cassée sur plusieurs modèles (bug firmware connu). Donc même en RTSP, pas d’alertes fiables en local.
Le contournement : go2rtc parle le « Tapo »
Le port 8800, c’est le protocole propriétaire TP-Link — celui qu’utilise l’app Tapo. Et il se trouve que go2rtc (le couteau suisse vidéo d’AlexxIT, embarqué dans Frigate ET dans Home Assistant) sait le parler nativement via une source tapo://.
L’architecture complète devient :
Caméra (tapo://, rtsp://, onvif://, ...) → go2rtc → Frigate (détection IA) → MQTT → Gladys / Node-RED
Et le point clé : c’est Frigate qui fait la détection d’objets, pas le firmware de la caméra. Donc plus besoin d’ONVIF, plus besoin du cloud, et une détection meilleure que celle de TP-Link — l’app Tapo me dit « animal » pour tout, Frigate distingue person, dog, cat, horse (labelmap COCO, 91 classes). Pour ma part j’ai besoin de détecter précisément les chevaux, autant dire que ça change tout. ![]()
Les pièges rencontrés (pour vous éviter des heures de debug)
Ça n’a pas marché du premier coup, et chaque piège vaut le coup d’être documenté :
1. Le mot de passe doit être URL-encodé. La source c’est tapo://MOT_DE_PASSE@IP avec le mot de passe de votre compte cloud Tapo (pas de « compte caméra » sur ces modèles). Si votre mdp contient #, ^, %, @… il faut l’encoder (# → %23, etc.), sinon go2rtc tronque l’URL silencieusement. Astuce :
bash
python3 -c "import urllib.parse,getpass; print(urllib.parse.quote(getpass.getpass('mdp: '), safe=''))"
2. Le flux principal 4K = écran noir. Bug connu (SPS/PPS non propagés, cf. issue go2rtc #2202) : la caméra envoie bien la vidéo mais go2rtc n’arrive pas à la parser. Le substream fonctionne parfaitement :
tapo://MDP_ENCODE@10.6.0.222?channel=0&subtype=1
640×360, c’est moche à l’œil mais c’est exactement ce que veut Frigate pour la détection (les modèles travaillent en 300-640 px de toute façon). Le 4K reste sur la carte SD de la caméra pour la relecture.
3. Les timestamps pourris (LE piège). Le flux tapo génère des DTS non monotones → ffmpeg s’emballe à 190 % de CPU, le watchdog Frigate le tue en boucle, aucun clip ne s’enregistre. Le correctif qui a tout réparé :
yaml
input_args: -avoid_negative_ts make_zero -fflags +genpts+discardcorrupt -rtsp_transport tcp -use_wallclock_as_timestamps 1
La clé c’est -use_wallclock_as_timestamps 1 : ffmpeg ignore les timestamps de la source et les régénère.
4. L’iGPU Intel change tout. Mon serveur est un modeste Beelink U59 (Celeron N5105) qui héberge déjà HA + 2 Gladys. En détecteur CPU, il était à genoux (86 % système). En activant OpenVINO sur l’iGPU + décodage VAAPI :
| Métrique | CPU | iGPU (OpenVINO + VAAPI) |
|---|---|---|
| Inférence | 94,6 ms | 15,8 ms |
| Process détecteur | 191,8 % | 8,5 % |
| CPU système | 86 % | 22 % |
| Frames jetées | 7/s | 0 |
Un Celeron à 22 % de CPU qui fait de la détection d’objets temps réel en plus de HA et 2 Gladys. ![]()
Le résultat
Côté MQTT, Frigate publie tout ce dont on rêve :
frigate/c660/person → 1 / 0 (binaire, parfait pour Gladys)
frigate/c660/dog → 1 / 0
frigate/events → JSON riche (label, score, box, trajectoire, zones...)
frigate/reviews → alertes avec thumbnail
frigate/stats → santé complète (fps, inférence, stockage...)
Détection validée en réel (person à 0,93 de score, dog reconnu là où Tapo dit « animal »), clips enregistrés, snapshots, zéro cloud. Une caméra « officiellement impossible à intégrer » qui fonctionne mieux en local que les modèles « compatibles ». ![]()
:gear: Configurations complètes validées (docker-compose + config Frigate) — cliquez pour déplier
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 depuis la 0.17 !)
- "8554:8554" # RTSP restream
- "1984:1984" # go2rtc
config/config.yml :
yaml
mqtt:
enabled: true
host: <votre_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://MDP_URL_ENCODE@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
Notes d’exploitation :
- Frigate 0.17 : l’UI est en HTTPS sur le port 8971 (certificat auto-signé), compte admin généré au premier démarrage (mdp dans les logs).
shm_size: 128 Mo ne suffit pas, même pour 1 caméra.- Les caméras Tapo limitent les flux concurrents → toujours consommer via go2rtc (qui mutualise en 1 connexion), jamais en direct.
- Petit warning
connection reset by peerpériodique sur le port 8800 : la caméra coupe de temps en temps, go2rtc reconnecte tout seul. Non bloquant.
Et maintenant : proposition d’intégration Gladys
Tout ça fonctionne, mais soyons honnêtes : entre le nmap, l’URL-encoding, les input_args ffmpeg et la config OpenVINO, ce n’est pas accessible au commun des mortels. Et c’est exactement le genre de complexité que Gladys sait masquer. ![]()
Je compte donc développer une intégration « Vidéosurveillance locale » (nouveau service ou extension de rtsp-camera, à discuter) dont le principe est de ne PAS réinventer la roue :
- go2rtc = couche d’abstraction protocolaire (il parle rtsp://, tapo://, onvif://, Ring, Nest, Dahua, USB… et c’est maintenu par AlexxIT + une grosse communauté). Une intégration = toutes les caméras.
- Frigate = détection d’objets + enregistrements + MQTT.
- Gladys = orchestration, configuration simple, et exposition des features.
Ce que ferait l’intégration
- Gestion des conteneurs Frigate/go2rtc depuis l’UI Gladys (installation, démarrage, restart) — sur le même modèle que ce qui existe déjà pour Zigbee2MQTT.
- Configuration intelligente automatique : détection du matériel (iGPU Intel présent ? → OpenVINO + VAAPI ; sinon CPU), calcul du
shm_sizeselon le nombre de caméras, défauts stables — le tout surchargeable en mode expert. - Ajout de caméra simplissime : nom, type (RTSP / Tapo / ONVIF…), IP, mot de passe (encodé automatiquement !), choix des objets à détecter (person, dog, cat, horse… multi-select). L’intégration génère la config Frigate et applique les correctifs connus (substream Tapo, input_args timestamps…) sans que l’utilisateur ait à savoir que ça existe.
- Features Gladys créées automatiquement par caméra :
- la caméra live classique ;
- un binaire de détection par type d’objet (
frigate/<cam>/person→ capteur présence Gladys → scènes !) ; - une « caméra image » par type : la dernière image capturée de chaque détection (probablement un nouveau type de feature image-only, sans live — à discuter).
- Santé : statut par caméra, compteur de reconnexions, stats Frigate remontées.
Questions ouvertes pour la communauté (et @pierre-gilles
)
- Nouveau service ou extension de
rtsp-camera? Mon intuition : nouveau service (le périmètre est très différent), mais l’existant doit rester le chemin simple pour qui ne veut qu’un flux RTSP. - Nouveau type de feature « caméra image-only » (affichage de la dernière image, pas de player live) : ça vous semble la bonne modélisation pour « dernière détection de type X » ?
- Politique conteneurs compagnons : Frigate embarque son propre go2rtc, donc un seul conteneur suffit. OK pour suivre le pattern Z2M ?
- Live view : intégration du web component
video-stream.jsde go2rtc (WebRTC/MSE) avec fallback snapshots pour les flux capricieux. Question du proxy via le server Gladys à creuser (mixed content HTTPS/HTTP).
Je démarre le développement par une phase d’analyse de l’existant, puis un MVP (conteneur + caméra RTSP générique + binaires de détection MQTT), puis les sources avancées (tapo://, onvif://) et le live. PRs petites et découpées, comme d’habitude.
Tous les retours sont bienvenus : cas d’usage, caméras que vous aimeriez voir supportées, avis sur les questions ci-dessus… Et si certains veulent tester le setup manuel en attendant, les configs complètes sont dans le déplié ci-dessus — je réponds aux questions ! ![]()
À très vite, Terdious