V0.4.2 — Identité stable des Appareils par adresse MAC
Publiée le 12/10/2026.
Documentation fonctionnelle
Ce que change la version pour les collaborateurs
Pourquoi
Une Caméra était connue par son URL RTSP, donc par l’IP de son appareil. Sur un vrai Site, les caméras prennent souvent leur adresse par DHCP : après une coupure, une caméra pouvait changer d’IP, passer offline, et réapparaître comme un nouveau Candidat, au risque d’un doublon. Pire, un autre appareil qui reprenait l’ancienne IP pouvait faire croire la Caméra online et montrer dans le Live le Flux d’une autre caméra. L’identifiant stable d’un appareil réseau est son adresse MAC, que l’API, derrière le NAT de Docker, ne voyait pas.
Ce qu'on peut faire maintenant
- Voir la MAC de l’Appareil (format
aa:bb:cc:dd:ee:ff, « — » si illisible) sur chaque Candidat, chaque Caméra et dans l’Aperçu, pour la comparer à l’étiquette. - Filtrer par MAC les Candidats d’une Détection, en la tapant telle qu’écrite sur l’étiquette (
AA-BB-…,aabb.ccdd.eeff, partielle). - Quand une caméra a changé d’IP, relancer une Détection : ArgOS met à jour seul l’URL de toutes les Caméras de cet Appareil (hôte seulement ; port, chemin et identifiants gardés), désactivées comprises, et l’affiche « adresse mise à jour (ancienne → nouvelle) ». Deux caméras qui ont échangé leurs IP sont corrigées ensemble. La Caméra revient dans le Live sans autre action.
- Si un autre appareil répond à l’adresse d’une Caméra, elle passe
offlineavec la raison « autre appareil à cette adresse », et le pont cesse de la relayer jusqu’au retour de la bonne MAC. - À l’ajout, un Flux déjà configuré sur le même Appareil est refusé (« Déjà configurée : <nom> ») même à une autre IP ; un autre chemin du même Appareil (enregistreur, encodeur multi-voies) est permis, avec un avertissement.
- Les Caméras ajoutées avant la 0.4.2 reçoivent leur MAC d’elles-mêmes, sans migration manuelle.
- En prod Linux, le script
configurer-detection.shpropose une IP libre pour ArgOS sur le réseau des caméras et activecompose.reseau-cameras.yaml: l’API y rejoint les caméras par macvlan, pour lire leurs MAC, sans y être joignable (toute requête arrivée par ce réseau est refusée). - Documentation : MAC, ARP, macvlan et changement d’IP expliqués dans « Réseau du Site et Détection des Caméras » ; réseau des caméras dans
docs/securite.md.
Documentation technique
Spec versionnée : docs/specs/v0.4.2-identite-stable-par-adresse-mac.md
Issue parente : #36
V0.4.2 — Identité stable des Appareils par adresse MAC
Problem Statement
Une Caméra est aujourd'hui connue par son URL RTSP, donc par l'IP de son appareil. Sur un vrai Site, les caméras prennent souvent leur adresse par DHCP : après une coupure ou un renouvellement de bail, une caméra peut changer d'IP. Elle passe alors offline dans ArgOS ; une Détection la montre comme un nouveau Candidat, que l'Administrateur risque d'ajouter une seconde fois, pendant que l'ancienne Caméra reste cassée. Pire : si un autre appareil reprend l'ancienne IP, ArgOS peut le croire online et montrer dans le Live le Flux d'une autre caméra sous le nom de la première.
L'identifiant matériel stable d'un appareil réseau est son adresse MAC. Mais l'API tourne dans un conteneur sur le réseau bridge de Docker : elle joint les caméras par NAT et ne voit jamais leurs MAC (ADR 0002). Enfin, pour reconnaître parmi les Candidats la caméra qu'il a dans la main, l'Administrateur n'a que l'IP, alors que l'étiquette de la caméra porte sa MAC.
Solution
L'API rejoint directement le réseau des caméras par une interface macvlan sur la (les) prise(s) des caméras (prod Linux). Elle y sort sans NAT : après chaque sonde d'une IP, sa table de voisinage donne la MAC de l'appareil. En dev, les Caméras simulées partagent déjà un réseau Compose avec l'API : même mécanisme, MAC fixes.
ArgOS retient la MAC de l'Appareil de chaque Caméra. À chaque Détection, un Candidat dont la MAC est celle d'un Appareil connu, mais à une autre IP, met à jour automatiquement l'URL RTSP de ses Caméras (seulement l'hôte) et se range dans « Déjà configurées » avec « adresse mise à jour ». La sonde vérifie aussi la MAC : si un autre appareil répond à l'IP d'une Caméra, celle-ci passe offline avec la raison « autre appareil à cette adresse », et le pont cesse de la relayer. La MAC s'affiche (format aa:bb:cc:dd:ee:ff) sur les Candidats, les Caméras et l'Aperçu, et un filtre par MAC dans les Candidats remplace l'« ajout manuel par MAC » prévu à la feuille de route.
User Stories
Identité et suivi d'adresse
- En tant qu'Administrateur, je veux qu'ArgOS retienne la MAC de l'Appareil de chaque Caméra dès qu'il la voit, pour reconnaître cet Appareil quand son IP change.
- En tant qu'Administrateur, je veux qu'une Détection qui trouve un Appareil connu à une nouvelle IP mette à jour seule l'URL RTSP de ses Caméras (hôte seulement : port, chemin et identifiants gardés), pour que ses Caméras repartent sans rien ressaisir.
- En tant qu'Administrateur, je veux voir ce Candidat dans « Déjà configurées » avec la mention « adresse mise à jour » (ancienne → nouvelle IP), pour savoir ce qu'ArgOS a changé.
- En tant qu'Administrateur, je veux que la Caméra mise à jour soit relayée à sa nouvelle adresse et revienne dans le Live, sans autre action.
- En tant qu'Administrateur, je veux que les Caméras désactivées de cet Appareil soient mises à jour aussi, pour qu'elles soient justes à leur réactivation.
- En tant qu'Administrateur, je veux que deux Appareils qui ont échangé leurs IP soient tous deux mis à jour par la même Détection, sans conflit.
- En tant qu'Administrateur, je veux, si une mise à jour reste impossible (l'URL est déjà prise par une Caméra sans MAC), que la Caméra ne soit pas modifiée et que le Candidat le dise, pour corriger à la main.
- En tant qu'Administrateur, je veux que la Détection reste lancée seulement par moi : ArgOS ne balaie jamais le réseau de lui-même quand une Caméra passe
offline.
Autre appareil à l'adresse d'une Caméra
- En tant qu'Administrateur, je veux qu'une Caméra dont l'IP répond avec une autre MAC que celle de son Appareil passe
offline, pour ne jamais voir le Flux d'une autre caméra sous son nom. - En tant qu'Administrateur, je veux lire dans l'Administration la raison « autre appareil à cette adresse » sur cette Caméra, pour comprendre qu'il faut relancer une Détection.
- En tant qu'Administrateur, je veux que le pont cesse de relayer cette Caméra tant que la bonne MAC n'est pas revue à son adresse.
Ajout et doublons
- En tant qu'Administrateur, je veux voir la MAC dans l'Aperçu pendant l'ajout, pour vérifier que c'est l'appareil de l'étiquette.
- En tant qu'Administrateur, je veux que l'ajout d'un Flux déjà configuré sur le même Appareil (même MAC, même chemin) soit refusé avec « Déjà configurée : <nom> », même si l'IP a changé, pour ne pas créer de doublon.
- En tant qu'Administrateur, je veux, pour un autre chemin du même Appareil (enregistreur ou encodeur multi-voies), un avertissement « Cet appareil porte déjà la Caméra <nom> » qui laisse ajouter, pour gérer un Appareil à plusieurs Caméras.
- En tant qu'Administrateur, je veux que la Caméra ajoutée garde la MAC lue pendant l'essai.
Caméras sans MAC
- En tant qu'Administrateur, je veux que les Caméras ajoutées avant la 0.4.2 reçoivent leur MAC d'elles-mêmes la première fois qu'une Détection ou la sonde voit leur Appareil à leur IP, sans migration manuelle.
- En tant qu'Administrateur, je veux qu'une Caméra dont la MAC est inconnue (réseau routé, Mac de dev avec de vraies caméras) garde le comportement de la 0.4.1, et affiche « — » comme MAC.
Affichage et filtre
- En tant qu'Administrateur, je veux voir la MAC de chaque Candidat et de chaque Caméra, au format
aa:bb:cc:dd:ee:ff, pour les rapprocher des étiquettes. - En tant qu'Administrateur, je veux filtrer les Candidats par MAC en la tapant telle qu'écrite sur l'étiquette (
AA-BB-…,aabb.ccdd.eeff, majuscules, MAC partielle), pour retrouver une caméra parmi beaucoup.
Réseau des caméras (installation)
- En tant qu'installateur sur Linux, je veux que le script de configuration de la Détection propose, au premier lancement, une IP libre (vérifiée par ARP) du sous-réseau de chaque prise des caméras pour ArgOS, et la retienne, pour ne pas avoir à comprendre macvlan.
- En tant qu'installateur, je veux pouvoir remplacer l'IP proposée, et qu'un lancement sans terminal (démarrage automatique) garde l'IP retenue sans question.
- En tant qu'installateur, je veux un avertissement clair si l'IP retenue n'est plus dans le sous-réseau de la prise, ou si elle est prise par un autre appareil.
- En tant qu'installateur sur Linux, je veux que le script active seul le réseau des caméras (fichier Compose ajouté à
COMPOSE_FILEdans.env), et qu'il ne le fasse jamais sur macOS, où Docker Desktop ne gère pas macvlan. - En tant qu'installateur, je veux que l'API n'accepte aucune requête arrivée par le réseau des caméras, pour qu'une caméra compromise ne puisse pas la joindre : ce réseau reste une sortie.
Caméras simulées et dev
- En tant que développeur, je veux que chaque Caméra simulée ait une MAC et une IP fixes, pour écrire des tests de changement d'adresse.
- En tant que développeur sur Mac, je veux que rien ne change au lancement (pas de macvlan), les Caméras simulées donnant déjà leur MAC par leur réseau Compose.
Documentation
- En tant qu'Administrateur non spécialiste du réseau, je veux que la doc « Réseau du Site et Détection » explique la MAC, l'ARP, pourquoi l'API ne la voyait pas derrière le NAT, ce que fait macvlan, l'IP d'ArgOS sur le réseau des caméras, et ce qui se passe quand une caméra change d'IP.
- En tant que développeur, je veux que la doc dise clairement qu'un Appareil peut porter plusieurs Caméras (même MAC), ce qu'ArgOS fait dans ce cas (mise à jour de toutes, avertissement à l'ajout), et ce qui reste à étudier.
- En tant que développeur, je veux une ADR 0003 « macvlan sur la prise des caméras » qui remplace en partie l'ADR 0002, pour savoir pourquoi l'API a deux réseaux.
- En tant que développeur, je veux que
docs/securite.mddécrive le réseau des caméras (sortie seulement, IP d'ArgOS sur ce réseau, ce que la sonde lit) et que le README présente la MAC et le suivi d'adresse. - En tant que développeur, je veux que le glossaire définisse Appareil et que Caméra devienne le Flux d'un Appareil.
- En tant que développeur, je veux que la feuille de route note que l'ajout manuel par MAC est remplacé par le filtre par MAC.
Implementation Decisions
- Glossaire :
- ADR 0003 — macvlan sur la prise des caméras (remplace en partie 0002) :
apigarde le bridge (noms Compose, ports publiés) et gagne une interface macvlan par prise des caméras, avec une IP fixe hors DHCP. Options écartées : table ARP de l'hôte montée dans le conteneur (procfs fragile, Linux seulement), service sur l'hôte qui expose la table ARP (nouveau composant hors Docker), ONVIF (identifiants, hors périmètre),network_mode: host(déjà écarté). Conséquence : sous Docker Desktop, pas de MAC pour les vraies caméras. - Modèle : migration
0004: colonnemac(texte, normalisée, facultative, non unique : un Appareil peut porter plusieurs Caméras) etraison_etat(facultative) sur les Caméras. Pas de table Appareil à part en 0.4.2 : l'Appareil est la MAC partagée par ses Caméras. - Module de voisinage (interface étroite) :
mac_de(ip) -> str | Nonelit la table de voisinage du conteneur (/proc/net/arp, entrées complètes seulement) ;normaliser(saisie) -> straccepte:,-,., sans séparateur, toute casse, et rendaa:bb:cc:dd:ee:ff. Appelé après chaque sonde réussie (Détection, essai, surveillance) : la connexion TCP vient de remplir la table. - Détection : chaque Candidat porte
mac(ounull). Rapprochement avec les Caméras : d'abord par MAC (même MAC → Appareil connu), sinon comme en 0.4.1 (IP:port). Les mises à jour d'adresse d'une Détection s'appliquent en une seule transaction (échanges d'IP compris) ; une Caméra dont la nouvelle URL entre en conflit avec une Caméra sans MAC n'est pas modifiée. Réponse : chaque Candidat déjà configuré gagneadresse_mise_a_jour: \{ancienne, nouvelle\} | nullet, en cas de conflit,conflit: \{id, nom\}. Les Caméras désactivées suivent. Remplissage de la MAC manquante : une Caméra sans MAC dont l'IP:port correspond à un Candidat reçoit sa MAC. La réconciliation du pont suit les nouvelles URL. - Essai (ajout) :
POST /api/essairenvoie aussimac. Même MAC et même chemin qu'une Caméra existante →409« Déjà configurée : <nom> » (comme l'IP:port en 0.4.1). Même MAC, autre chemin →flux_trouveavecappareil_deja_connu: \{id, nom\}; l'UI avertit, l'ajout reste permis.POST /api/essai/cameraenregistre la MAC. - Surveillance : après une sonde réussie, si la Caméra a une MAC et que la table donne une autre MAC pour son IP →
offline,raison_etat = "autre_appareil", et la réconciliation du pont ne relaie pas cette Caméra. Bonne MAC revue → raison effacée, relais rétabli. MAC manquante et MAC lue → remplie. MAC illisible (entrée absente) → aucun changement de MAC ni de raison. - API Caméras :
GETrenvoiemacetraison_etat. La MAC n'est pas modifiable par l'Administrateur. - Écoute de l'API : l'API refuse toute requête arrivée sur une adresse locale du réseau des caméras (adresse macvlan), au plus tôt (connexion fermée ou
403avant tout traitement) ; le healthcheck (localhost) et le bridge restent servis. - Compose : nouveau fichier
compose.reseau-cameras.yaml(prod Linux seulement) : réseau(x) macvlan sur la (les) prise(s) retenue(s), sous-réseau et IP d'ArgOS lus dans.env, rejoint parapiseul.compose.yamlreste inchangé et fonctionne sans lui. - Script hôte (
configurer-detection.sh) : sur Linux, pour chaque prise retenue, propose une IP libre (vérifiée par ARP, en partant du haut du sous-réseau), la demande une fois en terminal, la retient dans.env; sans terminal, garde l'IP retenue ; avertit si elle sort du sous-réseau ou répond déjà en ARP. Ajoutecompose.reseau-cameras.yamlàCOMPOSE_FILEdans.env(Linux seulement). Exclut l'IP d'ArgOS des Candidats (comme ses autres adresses). Sur macOS : aucun changement. - Caméras simulées :
mac_addressetipv4_addressfixes pour les trois, danscompose.simulation.yaml. - UI (Administration) : colonne MAC dans la liste des Caméras et des Candidats (« — » si inconnue) ; raison « autre appareil à cette adresse » à côté de l'état ; « adresse mise à jour (ancienne → nouvelle) » ou conflit sur un Candidat déjà configuré ; champ « Filtrer par MAC » au-dessus des Candidats (normalisation identique au serveur, MAC partielle acceptée) ; MAC et avertissement « Cet appareil porte déjà la Caméra <nom> » dans l'Aperçu.
- Docs : section MAC / ARP / macvlan / changement d'IP / Appareil à plusieurs Caméras dans
docs/cameras/reseau-et-detection.md(et lien depuis « Ajouter une Caméra ») ; ADR 0003 ;docs/securite.md; README ; feuille de route (0.4.2 livrée avec filtre par MAC au lieu d'ajout par MAC) ; glossaire.
Testing Decisions
- Un bon test vérifie un comportement observable (réponse HTTP, URL d'une Caméra, chemins du pont, écran), jamais la lecture de
/proc/net/arpelle-même hors des tests unitaires du module de voisinage. - Tests unitaires (dans
tests/api/) : normalisation de la MAC (formats d'étiquette, casse, partielle pour le filtre, refus d'une saisie invalide) ; lecture d'une table de voisinage d'exemple (entrées incomplètes ignorées). tests/api/(stack avec simulation, sans mock), prior art : tests Détection 0.4.0 et essai 0.4.1 :- la Détection renvoie la MAC fixe de chaque Caméra simulée ; l'essai aussi, et la Caméra ajoutée la garde ;
- une Caméra simulée déplacée (
docker network disconnect/connect --ip, même MAC) : la Détection met à jour l'URL (hôte seulement), le Candidat porteadresse_mise_a_jour, le pont relaie la nouvelle adresse et la Caméra repasseonline; - deux Caméras simulées qui échangent leurs IP : les deux mises à jour en une Détection ;
- IP d'une Caméra prêtée à une autre Caméra simulée : la Caméra passe
offlineavecraison_etat = "autre_appareil", n'est plus relayée ; IP rendue →online, raison effacée ; - Caméra désactivée mise à jour ; Caméra sans MAC remplie par une Détection ou la sonde ; conflit avec une Caméra sans MAC → non modifiée,
conflitrenvoyé ; - essai : même MAC même chemin →
409; même MAC autre chemin →appareil_deja_connu. - Chaque test remet la Caméra simulée à son adresse d'origine.
tests/scripts/, prior art :test_configurer_detection.py: proposition d'IP libre, réponse ARP simulée, IP retenue sans terminal, avertissements,COMPOSE_FILEajouté sur Linux et jamais sur macOS ;compose.reseau-cameras.yamlvalide (docker compose config) avec un.envd'exemple.tests/flux/: MAC et IP fixes des Caméras simulées ;compose.yamlseul sans macvlan.tests/web/(pytest-playwright) : colonne MAC (Caméras, Candidats), filtre par MAC, « adresse mise à jour » après déplacement, raison « autre appareil à cette adresse », MAC et avertissement dans l'Aperçu.- Le refus des requêtes arrivées par le réseau des caméras se teste au niveau de l'API (adresse locale simulée), macvlan n'existant pas sous Docker Desktop.
- Mêmes règles qu'avant : jamais d'effacement de la base, noms uniques par test puis nettoyage.
Out of Scope
- Étude des Appareils à plusieurs Caméras (enregistreurs, encodeurs multi-voies : MAC partagée, chemins par voie) : version à ajouter à la feuille de route (
/afr). - Ajout manuel par MAC (remplacé par le filtre par MAC).
- Détection relancée automatiquement quand une Caméra passe
offline. - MAC des vraies caméras sous Docker Desktop (Mac), et derrière un routeur.
- ONVIF, serveur DHCP sur la machine ArgOS, modification de la MAC par l'Administrateur.
- Table Appareil séparée (nom, marque) : la MAC partagée suffit en 0.4.2.
Further Notes
- Une MAC n'est visible que sur le réseau local direct : l'ARP remplit la table de voisinage de la machine qui parle à l'IP. Derrière le NAT de Docker, c'est l'hôte qui fait l'ARP, jamais le conteneur ; d'où macvlan.
- Contexte : feuille de route de dev (section 0.4.2), spec 0.4.0 (#18) et 0.4.1 (#25), ADR 0001 et 0002,
docs/securite.md,docs/cameras/reseau-et-detection.md,docs/cameras/ajouter-une-camera.md.