Aller au contenu principal

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 offline avec 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.sh propose une IP libre pour ArgOS sur le réseau des caméras et active compose.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​

  1. 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.
  2. 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.
  3. 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é.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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​

  1. 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.
  2. 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.
  3. 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​

  1. 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.
  2. 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.
  3. 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.
  4. En tant qu'Administrateur, je veux que la Caméra ajoutée garde la MAC lue pendant l'essai.

Caméras sans MAC​

  1. 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.
  2. 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​

  1. 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.
  2. 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)​

  1. 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.
  2. 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.
  3. 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.
  4. En tant qu'installateur sur Linux, je veux que le script active seul le réseau des caméras (fichier Compose ajouté à COMPOSE_FILE dans .env), et qu'il ne le fasse jamais sur macOS, où Docker Desktop ne gère pas macvlan.
  5. 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​

  1. 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.
  2. 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​

  1. 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.
  2. 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.
  3. 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.
  4. En tant que développeur, je veux que docs/securite.md dé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.
  5. En tant que développeur, je veux que le glossaire définisse Appareil et que Caméra devienne le Flux d'un Appareil.
  6. 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 :
    • Appareil : matériel réseau reconnu par son adresse MAC, qui porte une ou plusieurs Caméras. Avoid : device, équipement, hôte.
    • Caméra : Flux d'un Appareil connu du Site, identifié par une URL RTSP. (Le reste du glossaire inchangé.)
  • ADR 0003 — macvlan sur la prise des caméras (remplace en partie 0002) : api garde 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 : colonne mac (texte, normalisée, facultative, non unique : un Appareil peut porter plusieurs Caméras) et raison_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 | None lit la table de voisinage du conteneur (/proc/net/arp, entrées complètes seulement) ; normaliser(saisie) -> str accepte :, -, ., sans séparateur, toute casse, et rend aa: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 (ou null). 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é gagne adresse_mise_a_jour: \{ancienne, nouvelle\} | null et, 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/essai renvoie aussi mac. 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_trouve avec appareil_deja_connu: \{id, nom\} ; l'UI avertit, l'ajout reste permis. POST /api/essai/camera enregistre 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 : GET renvoie mac et raison_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 403 avant 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 par api seul. compose.yaml reste 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. Ajoute compose.reseau-cameras.yaml à COMPOSE_FILE dans .env (Linux seulement). Exclut l'IP d'ArgOS des Candidats (comme ses autres adresses). Sur macOS : aucun changement.
  • Caméras simulées : mac_address et ipv4_address fixes pour les trois, dans compose.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/arp elle-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 :
  • tests/scripts/, prior art : test_configurer_detection.py : proposition d'IP libre, réponse ARP simulée, IP retenue sans terminal, avertissements, COMPOSE_FILE ajouté sur Linux et jamais sur macOS ; compose.reseau-cameras.yaml valide (docker compose config) avec un .env d'exemple.
  • tests/flux/ : MAC et IP fixes des Caméras simulées ; compose.yaml seul 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.