DOMOSYS.ORG

Hack caméra PTZ

2026-02-25

#Hack #Caméra #Interface #GTK #IA

Introduction

J’avais fait l’acquisition, il y a longtemps, d’une caméra-dôme PTZ (Pan-Tilt-Zoom) de surveillance, sur IP ethernet -pas WIFI-, placée à l’extérieur, à l’angle du toit pour un angle de vue maximal.

Caméra

Problème : son interface de gestion est en Java, et je n’ai jamais eu l’intention de faire tourner du java sur mes PC.

Par chance, cette caméra possède un accès SSH.

J’ai donc entrepris d’investiguer son fonctionnement.

Fonctionnement interne

Sans la moindre surprise : c’est du Linux !

  • parfeu iptables
  • connexion SSH
  • flux caméra rtsp (avec login/passwd)
  • Pilotage PTZ sur DBus
  • Commandes internes CGI, pour la partie http

HTTP

Au début, j’avais juste fait un hack en “auditant” les commandes passées par http sur le site

Bilan : la session est renégociée à chaque fois, ce qui fait que le temps de réaction est assez pénible.

SSH

Même chose : une commande passée individuellement, renégocie le login (ça reste une petite machine) → latence importante.

DBus

Il y a de quoi faire :

$ grep -E "<(interface|method|property|signal)" PTZ.Coordinator.xml
  <interface name="org.freedesktop.DBus.Introspectable">
    <method name="Introspect">
  <interface name="org.freedesktop.DBus.Properties">
    <method name="Get">
    <method name="Set">
    <method name="GetAll">
  <interface name="com.axis.PTZ.Coordinator">
    <method name="Command">
    <method name="UpdateStaticProperties">
    <method name="GetStaticProperties">
    <method name="RegisterDriver">
    <method name="Queue">
    <method name="GetDriverName">
    <method name="GetSupportParameters">
    <method name="SetDevicePreset">
    <method name="RemovePresetNumber">
    <method name="RemovePresetName">
    <method name="UpdatePreset">
    <method name="CreatePreset">
    <method name="SetPresetNumber">
    <method name="SetPresetName">
    <method name="OsdMenu">
    <method name="FieldAngles">
    <method name="QueryZoomDelim">
    <method name="QueryPosition">
    <method name="QueryPresets">
    <method name="QuerySpeed">
    <method name="AreaZoom">
    <method name="GetAuxiliary">
    <method name="Auxiliary">
    <method name="Image">
    <method name="GotoHome">
    <method name="GotoDevicePreset">
    <method name="GotoPresetNumber">
    <method name="GotoPresetName">
    <method name="MoveLL">
    <method name="MoveCmd">
    <method name="Move">
    <method name="MovePTZ">
    <signal name="PtzStaticPropsUpdated">
    <signal name="PtzParametersSetup">
    <signal name="DriverUninstalled">
    <signal name="DriverState">
    <signal name="DriverCapabilities">
    <signal name="SpeedControlEnable">
    <signal name="DefaultSpeed">
    <signal name="PtzPreset">
    <signal name="PtzAction">
    <signal name="PtzMoveEnabledChanged">
    <signal name="PtzLockedChanged">
    <signal name="PtzEnabledChanged">
    <signal name="CamPort">
    <signal name="TiltFlipped">
    <signal name="PanFlipped">
    <signal name="CtlQueueEnabled">
    <property name="TiltFlipped" type="b" access="read"/>
    <property name="PanFlipped" type="b" access="read"/>
    <property name="DriverExtraCapabilities" type="i" access="read"/>
    <property name="DriverMoveCapabilities" type="i" access="read"/>
    <property name="Name" type="s" access="readwrite"/>
    <property name="PTZEnabled" type="b" access="readwrite"/>
    <property name="PTZLocked" type="b" access="readwrite"/>
    <property name="CamPort" type="i" access="readwrite"/>
    <property name="Various" type="s" access="write"/>
    <property name="Support" type="s" access="write"/>

Méthode

Je créé donc une instance SSH persistante (avec échange de clés), à partir d’un petit script bash, appelé par mon appli Python/GTK :

#!/bin/sh
START_CMD='ssh -M -S ~/.ssh/cam_mux -fNT user@cam'
STOP_CMD='ssh -S ~/.ssh/cam_mux -O exit user@cam'
case "$1" in
  start) eval $START_CMD ;;
  stop)  eval $STOP_CMD  ;;
  *) echo "usage: $0 [start|stop]"; exit 2 ;;
esac

Dans l’application :

cmd = f'ssh -S {self.ssh_socket} {self.user}@{self.host} \
            dbus-send --system {command_line}'

Et voilà !

IA de détection

En ce qui concerne l’IA de détection, j’utilise tensorflow, avec le modèle très light :

ssd_mobilenet_v2_coco_quant_postprocess.tflite 6,2M

à cette adresse :

https://github.com/google-coral/edgetpu/tree/master/test_data

Pour mon petit ordi, ça fait le taf, sans être trop gourmand en ressources (sur CPU -pas de GPU-)

Le Code

Aujourd’hui, j’ai au final une interface GTK de pilotage complet, avec IA de détection de présence et identification⁽¹⁾, tracking automatique, tours de garde, enregistrement automatique et alerte via un bot sur mobile avec snapshot (capture d’image).

⁽¹⁾ Je ne fais pas pour l’heure de véritable contrôle d’identité automatisée (ça reste encore intrusif et peu légal). Uniquement de l’identification de formes : chat/chien/voiture/personne/…

Cat

y’a écrit “cat” - ‘faut que je change la couleur 😋 -

Améliorations en cours

En ayant installé sur mon VPS un serveur matrix-synapse (matrix.domosys.org), j’ai pu développer un bot en Python pour l’y connecter.

Ainsi, à détection de présence, le bot nous envoit un message via l’application Element sur mobile, avec une capture d’image. Nous pouvons alors lui passer un appel en Visio-conférence, et nous avons la caméra en direct.

Bot

Conclusion

Évidemment la caméra d’origine ne faisait pas tout ça, et le modèle n’est même plus vendu, ni même mis à jour… Merci !

J’étais bon pour en acheter une autre, alors qu’elle fonctionne parfaitement et que j’ai pas les moyens !

Finalement, je me suis tout simplement retrouvé dans la même situation que Richard Stallman avec sa Xerox -histoire bien connue des Libristes : c’est la base de tout !-.

Et enfin, mon obligation morale tiendrait de fournir le code de mon hack, sous licence GNU/GPL. Il me faudra m’employer à le finaliser et le poster en ligne, afin que d’autres personnes dans le Monde possesseur du même modèle, bénéficient de ce travail.

NON : pas sur Github qui appartient à Micro$oft qui a donc là une mine de travail et d’idées gratuits, pour vous vendre ses produits -payés avec vos impôts- !