Hack caméra PTZ
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.

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/…

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.

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- !