Introduction : pourquoi un code Matter ou Thread perdu ne se comporte pas comme du Zigbee
Lorsqu’on déploie un réseau domotique Matter-over-Thread ou Matter-over-Wi-Fi (voir notre guide Matter : Wi-Fi vs Thread sur coordinateur PoE SLZB-MR4U), l’association initiale repose sur un QR Code (MT:...) accompagné d’un code numérique à 11 ou 21 chiffres (par exemple 3497-011-2332). Or, ce code est très souvent imprimé sur la notice papier ou sur l’emballage carton qui finit à la poubelle quelques semaines après l’installation.
Une question revient alors systématiquement : est-il vrai que Thread et Matter sont excellents techniquement, mais que sans ce numéro d’appairage, réassocier un appareil devient très compliqué ?
La réponse technique, factuelle et nuancée tient en deux points :
- Oui, si l’appareil a subi une remise à zéro d’usine (Factory Reset) et que l’étiquette physique est perdue : contrairement au Zigbee où un simple appui de 5 secondes sur le bouton Reset permet d’associer n’importe quel capteur ouvert au
permit_joinsans aucun code, la norme Matter exige une preuve cryptographique PASE (Passcode-Authenticated Session Establishment) basée sur le protocole SPAKE2+. Sans le code PIN initial, aucun contrôleur ne peut établir la session d’appairage d’usine. - Non, tant que l’appareil est encore connecté à au moins un contrôleur ou que vos clés de Fabric sont sauvegardées : le protocole Matter intègre une porte de secours native très puissante appelée Enhanced Commissioning Window (
ECW) qui permet de générer un nouveau code d’appairage temporaire à 11 chiffres directement depuis Home Assistant,python-matter-server, Aqara ou Apple Home, sans jamais avoir besoin de l’autocollant d’origine.
Dans cet article, nous expliquons pourquoi le code initial n’est stocké en clair ni dans l’objet ni dans le serveur, comment récupérer la main sur un périphérique existant, quels 5 outils Open Source permettent d’extraire ou d’intercepter ces codes, et comment mettre en place un garde-fou hebdomadaire automatisé (SQLite + YAML Git + alerte Telegram).
1. Réalité cryptographique : pourquoi le code à 11 chiffres est introuvable après l’appairage
Pour comprendre pourquoi aucun bouton « Afficher le code d’origine » n’existe dans Home Assistant une fois un capteur Thread appairé, il faut comparer le modèle de sécurité de Zigbee à celui de Matter :
| Étape technique | Zigbee 3.0 (Classique) | Matter (sur Thread ou Wi-Fi) |
|---|---|---|
| Mode d’appairage par défaut | Ouverture du permit_join sur le coordinateur + appui physique sur le capteur | Scan du QR Code (MT:...) ou saisie du code manuel à 11 chiffres |
| Clé d’échange initiale | Clé de transport partagée universelle (ZigBeeAlliance09 : 5A:69:67:42:65:65:...) | Protocole PASE (SPAKE2+) à divulgation nulle de connaissance dérivé du PIN |
| Que stocke la puce radio en usine ? | Adresse MAC IEEE EUI-64 | Uniquement le vérifieur salé SPAKE2+ (w0 || L, 97 octets) + Discriminator (12 bits) |
| Que stocke le serveur après appairage ? | La clé réseau (Network Key) et l’adresse IEEE du nœud | Un certificat opérationnel X.509 (NOC) pour les sessions CASE ; le PIN initial est effacé de la RAM |
| Conséquence en cas de Factory Reset | Réappairage immédiat par simple appui sur le bouton physique | Impossible sans le code PIN/QR d’usine (aucun brute-force possible : verrouillage progressif après 10 essais) |
[!IMPORTANT] Pourquoi ne peut-on pas lire le code PIN dans le fichier
chip.jsondu serveur Matter ? Lorsqu’on inspecte le volume de persistance depython-matter-server(/data/chip.jsonet/data/<fabric_id>.json), on y trouve le numéro de série de l’appareil (cluster0x0028, attribut0x000F), sonVendorID, sonProductIDet ses clés de session CASE, mais jamais le code à 11 chiffres. C’est voulu par la spécification CSA : dès que le contrôleur a délivré au capteur son certificat opérationnel (Node Operational Certificate), le secret d’appairage initial est détruit en mémoire vive pour empêcher qu’un attaquant compromettant un contrôleur secondaire puisse usurper le secret d’usine.
2. Les 3 réflexes immédiats si vous avez perdu la boîte ou la notice
Avant de considérer un capteur Thread ou une prise Matter comme inutilisable, vérifiez ces trois niveaux de récupération :
2.1. Inspection matérielle : le second sticker caché
Les fabricants certifiés Matter ont l’obligation d’apposer le marquage sur le produit lui-même lorsque la surface le permet. Sur la majorité des capteurs Thread récents (Heiman, Eve, Aqara, Shelly, Tado X, Sonoff), un second exemplaire du QR Code ou des 11 chiffres (XXXX-XXX-XXXX) se trouve :
- À l’intérieur du capot de pile (souvent imprimé au laser sous la pile CR2032 ou CR123A) ;
- Sous le socle de fixation mural amovible ou sous le cache-vis ;
- Sur le cordon d’alimentation ou sur la tranche latérale du module encastrable.
2.2. L’appareil est encore connecté à une application ou un Hub : la fenêtre ECW (Partager l’appareil)
Si votre périphérique fonctionne déjà dans un écosystème (application mobile Aqara, Apple Maison, Alexa, Google Home ou Home Assistant) et que vous souhaitez l’ajouter à un autre serveur ou migrer votre installation : ne le réinitialisez surtout pas !
Le standard Matter inclut la fonctionnalité Multi-Admin via le cluster Administrator Commissioning (0x003C). Tout contrôleur déjà authentifié en CASE peut ordonner à l’appareil d’ouvrir une Fenêtre de mise en service améliorée (Enhanced Commissioning Window / ECW) :
- Dans Home Assistant : ouvrez la fiche de l’appareil Matter -> cliquez sur Partager l’appareil (Share device). Home Assistant génère instantanément à l’écran un nouveau QR Code et un nouveau code à 11 chiffres valables pendant 3 à 15 minutes.
- Dans l’application Aqara, Eve ou Apple Maison : ouvrez les Paramètres de l’appareil -> Exposer à Matter / Activer le mode d’association -> copiez le code temporaire généré.
2.3. La sauvegarde 3-2-1 des fichiers de Fabric (chip.json + Dataset Thread)
Si vous sauvegardez régulièrement deux ensembles de fichiers sur votre serveur domotique, vous n’aurez jamais besoin de réappairer vos appareils Matter/Thread, même si votre serveur tombe en panne ou si vous remplacez votre coordinateur PoE :
- La Fabric Matter (
python-matter-server) : les fichiers/data/chip.jsonet/data/<fabric_id>.jsoncontiennent l’autorité de certification locale (RCAC/ICAC) et les clés opérationnelles CASE. - Le Dataset Opérationnel Thread (
OTBR) : le fichier.storage/thread.datasetsde Home Assistant et la configuration NVS de l’otbr-agentcontiennent laNetwork Key128 bits, l’Extended PAN IDet le canal radio (Canal 25).
3. Cinq outils Open Source pour extraire, décoder et intercepter ses codes Matter & Thread
Voici la boîte à outils Open Source complète pour auditer vos équipements, décoder les charges utiles et automatiser la capture des codes d’appairage :
| Outil Open Source | Dépôt / Licence | Usage principal pour les codes Matter & Thread |
|---|---|---|
python-matter-server | home-assistant-libs/python-matter-server (Apache 2.0) | Ouvrir une fenêtre open_commissioning_window en WebSocket (:5580) et intercepter commission_with_code lors de l’appairage initial |
chip-tool & chip-repl | project-chip/connectedhomeip (Apache 2.0) | Décoder un QR Code MT:... en code 11 chiffres + Passcode + Discriminator, ou générer un vérifieur SPAKE2+ |
home-assistant-matter-hub | t0bst4r/home-assistant-matter-hub (Apache 2.0) | Extraire par API REST (/api/matter/bridges) les codes manualPairingCode et qrPairingCode des ponts Matter |
ot-ctl (OpenThread CLI) | openthread/openthread (BSD-3-Clause) | Exporter et sauvegarder le Dataset Thread actif au format hexadécimal TLV (ot-ctl dataset active -x) |
avahi-browse / bluetoothctl | avahi / bluez (LGPL / GPL) | Détecter les objets Matter en attente d’appairage sur _matterc._udp et lire leur Discriminator (D=) et VendorID/ProductID (VP=) |
Outil n°1 : Générer un nouveau code à 11 chiffres en CLI via python-matter-server (WebSocket :5580)
Si un nœud Thread (par exemple node_id: 12) est déjà appairé à votre instance python-matter-server, vous pouvez lui faire générer un code d’appairage frais à 11 chiffres et un QR Code MT:... via une simple commande Python interrogeant l’API WebSocket locale :
import asyncio
import json
import websockets
async def generate_new_pairing_code(node_id: int = 12):
uri = "ws://127.0.0.1:5580/ws"
async with websockets.connect(uri) as ws:
await ws.recv() # Message de bienvenue du serveur Matter
payload = {
"message_id": "ecw-1",
"command": "open_commissioning_window",
"args": {
"node_id": node_id,
"timeout": 300 # Fenêtre ouverte pendant 5 minutes
}
}
await ws.send(json.dumps(payload))
response = json.loads(await ws.recv())
print(json.dumps(response, indent=2))
# Retourne : {"result": {"pin": 12345678, "pairing_code": "34970112332", "qr_code": "MT:..."}}
asyncio.run(generate_new_pairing_code(12))
Outil n°2 : Décoder un QR Code MT:... ou un code manuel avec chip-tool (SDK officiel CSA)
L’outil officiel chip-tool du projet Open Source connectedhomeip permet de décomposer instantanément n’importe quelle chaîne QR Code MT:... ou code à 11 chiffres pour en extraire le Passcode (27 bits), le Discriminator (12 bits), le VendorID et le ProductID :
# Décoder le contenu d'un QR Code Matter (MT:...)
chip-tool payload parse-setup-payload MT:Y.K9042C00KA0648G00
# Sortie :
# Version: 0
# VendorID: 65521 (0xFFF1)
# ProductID: 32769 (0x8001)
# CommissioningFlow: 0 (Standard)
# RendezvousInfo: 2 (BLE)
# Discriminator: 3840 (0xF00)
# Passcode: 20202021
# ManualPairingCode: 34970112332
Outil n°3 : Intercepter automatiquement le code d’usine lors du premier appairage (commission_with_code Hook)
Puisque python-matter-server reçoit le code à 11 chiffres ou le QR Code MT:... en clair au moment précis où vous cliquez sur Ajouter un appareil (commande WebSocket commission_with_code), la meilleure pratique consiste à ajouter un intercepteur léger (Hook Python) dans le contrôleur Matter afin d’enregistrer immédiatement ce code sur disque et en base de données avant qu’il ne soit purgé de la RAM :
# Exemple de Hook sur MatterDeviceController.commission_with_code
orig_commission = MatterDeviceController.commission_with_code
async def hooked_commission_with_code(self, code: str, network_only: bool = False):
clean_code = str(code or "").strip()
result = await orig_commission(self, code, network_only=network_only)
node_id = result.get("node_id") if isinstance(result, dict) else getattr(result, "node_id", None)
# Archivage immédiat du code d'origine (11 chiffres ou MT:...) associé au node_id et au numéro de série
save_pairing_code_to_vault(node_id=node_id, raw_code=clean_code)
return result
MatterDeviceController.commission_with_code = hooked_commission_with_code
Outil n°4 : Exporter les codes des ponts Matter (home-assistant-matter-hub)
Si vous exposez des entités Home Assistant vers Alexa, Apple Home ou Google Home via un pont Open Source comme home-assistant-matter-hub, ses codes d’appairage sont directement requêtables en JSON sur son API locale :
curl -s http://127.0.0.1:8482/api/matter/bridges | jq '.[] | {
name: .name,
passcode: .commissioning.passcode,
discriminator: .commissioning.discriminator,
manualPairingCode: .commissioning.manualPairingCode,
qrPairingCode: .commissioning.qrPairingCode
}'
Outil n°5 : Sauvegarder le Dataset Thread actif avec ot-ctl
Sur votre conteneur OpenThread Border Router (otbr-agent), exportez la chaîne TLV hexadécimale complète de votre maillage Thread :
# Extraction du Dataset opérationnel Thread actif (TLV hexadécimal)
docker exec matter-otbr ot-ctl dataset active -x
# Exemple : 0e080000000000010000000300001935060004001fffe00208...
# Affichage détaillé (Canal, PAN ID, Extended PAN ID, Network Key)
docker exec matter-otbr ot-ctl dataset active
4. Construire un Garde-Fou Hebdomadaire (SQLite + Fichier YAML Git + Alerte Telegram)
Pour ne plus jamais dépendre d’une étiquette papier, nous recommandons d’automatiser une tâche hebdomadaire (par exemple chaque dimanche matin via APScheduler ou cron) qui :
- Scanne les ponts Matter, le dataset Thread OTBR et tous les nœuds Thread/Matter présents dans
python-matter-server(extraction automatique duSerialNumbervia l’attribut0/40/15, de l’adresse MACEUI-64, duVendorNameet duProductName) ; - Croise ces nœuds avec les codes d’appairage capturés et met à jour à la fois une base SQLite (
matter_pairing_bridges,matter_thread_nodes,matter_thread_datasets) et un fichier déclaratifmatter_thread_pairing_codes.yamlversionné sur un dépôt Git privé (Gitea) ; - Envoie une notification Telegram instantanée dès qu’un nouvel appareil Thread rejoint le maillage.
Voici la structure du fichier de configuration matter_thread_pairing_codes.yaml généré et versionné automatiquement :
schema_version: '1.0'
description: Registre déclaratif des codes d'appairage Matter & Thread
capture_hooks:
matter_server_ws_hook: custom_clusters.py -> commission_with_code
manual_cli_command: /matter_code <node_id> <code_11_chiffres_ou_MT>
weekly_guardrail_cron: Chaque dimanche à 09h10 + détection temps réel
matter_bridges:
- bridge_id: 7cb70ea4a5fb489db97fec04067dc6fe
name: Maison Matter Hub
port: 5540
passcode: 20202021
discriminator: 3840
manual_pairing_code: '34970112332'
manual_pairing_code_formatted: 3497-011-2332
qr_pairing_code: MT:Y.K9042C00KA0648G00
thread_datasets:
- dataset_id: otbr-primary
network_name: Homelab-OTBR
channel: 25
pan_id: '0x1234'
extended_pan_id: 0011223344556677
border_agent_id: aabbccddeeff00112233445566778899
thread_and_matter_nodes:
- node_id: 12
name: Détecteur Fumée Bureau (Matter-over-Thread)
vendor_name: HEIMAN
product_name: SmokeSensor-EF-3.0
serial_number: '26072104099000447'
mac_address: f4ce3616b8067532
manual_pairing_code: 3497-011-2332
qr_pairing_code: MT:Y.K9042C00KA0648G00
Conclusion : la check-list en 4 points pour un réseau Matter & Thread résilient
| Commande | Description |
|---|---|
`open_commissioning_window`
| Génère un nouveau code temporaire à 11 chiffres et un QR Code depuis Home Assistant ou python-matter-server tant que l'appareil est appairé. |
`chip-tool payload parse-setup-payload`
| Décode un QR Code MT:... en Passcode (27 bits), Discriminator (12 bits), VendorID et ManualPairingCode. |
`commission_with_code (Hook)`
| Intercepte et sauvegarde en SQLite + Git YAML le code à 11 chiffres dès l'appairage initial avant sa purge mémoire. |
`ot-ctl dataset active -x`
| Exporte le Dataset opérationnel Thread actif (TLV hexadécimal) depuis le conteneur OpenThread Border Router. |
`chip.json +
| Certificats opérationnels CASE de la Fabric Matter à sauvegarder en 3-2-1 pour restaurer le serveur sans jamais réappairer. |
En résumé, le protocole Matter-over-Thread apporte une sécurité cryptographique bien supérieure au Zigbee historique grâce à l’authentification PASE (SPAKE2+) et aux certificats opérationnels CASE (NOC), mais cette sécurité impose une vraie discipline sur la conservation des codes initiaux :
- Photographiez ou saisissez systématiquement le code à 11 chiffres (
XXXX-XXX-XXXX) et le QR Code (MT:...) au moment du déballage, et vérifiez la présence du second autocollant sous le capot de pile. - N’effectuez jamais de Factory Reset aveugle sur un appareil dont vous avez perdu la boîte : tant qu’il est connecté à un contrôleur, utilisez la Fenêtre de mise en service améliorée (
open_commissioning_window/ Partager l’appareil) pour générer un nouveau code valide. - Activez un hook sur
commission_with_codedanspython-matter-serveret un scanner hebdomadaire vers SQLite + YAML Git/Gitea avec alerte Telegram pour archiver chaque nouveau nœud Thread dès son apparition. - Sauvegardez vos fichiers
/data/chip.json,/data/<fabric_id>.jsonet votre Dataset Thread TLV (ot-ctl dataset active -x) selon la règle 3-2-1 : leur simple restauration permet de reconstruire tout votre serveur domotique sans jamais réappairer un seul capteur.
Si vous voulez plus d’information sur l’infrastructure vous pouvez voir mon repo à ce sujet : https://github.com/ravindrajob/InfraAtHome
