Aller au contenu principal

Domotique — Networking

Le réseau domotique leukOS relie les devices physiques, les cartes de contrôle, la box locale et les interfaces utilisateur. Chaque protocole intervient à une couche précise afin de ne jamais exposer directement le matériel au smartphone ou à Internet.

Architecture réseau complète entre la box leukOS, les PCB et les devices

Communication entre les interfaces, la box, les contrôleurs et les circuits. Cliquer pour ouvrir le schéma en pleine résolution.

Vue d'ensemble des communications

Le smartphone ne commande normalement jamais un relais ou une vanne directement. Il appelle le hub local, qui valide l'action et la transmet au contrôleur concerné. Le retour d'état remonte ensuite par le chemin inverse.

Rôle et état des protocoles

ProtocoleUsageÉtat dans leukOS
UARTHeartbeat, mesures et commandes entre le daemon et un MCU localImplémenté par le Device Bridge
TCP/IPTransport commun à HTTP, MQTT, WebSocket et gRPCImplémenté
HTTP/RESTÉtats, commandes et onboardingImplémenté
WebSocketMise à jour temps réel de la Web IHMImplémenté
MQTTÉtats, présence, commandes et discoveryImplémenté en réseau local
Ethernet / PoERéseau filaire stable et alimentation possibleArchitecture cible supportée
Wi-FiAccès smartphone et contrôleurs IP sans câbleSupporté par l'OS et la topologie
Bluetooth / BLEProvisioning de proximitéScénario prévu, pas encore intégré au daemon
mDNS / DNS-SDDécouverte automatique sur le LANService externe possible ; intégration native à ajouter
X.509 / mTLSIdentité et chiffrement mutuelsVérification X.509 implémentée ; MQTT mTLS à finaliser

UART — liaison directe avec une carte

UART est utilisé lorsqu'un microcontrôleur est raccordé physiquement à la box, par exemple sur /dev/ttyUSB0 ou /dev/ttyACM0. Le Device Bridge ouvre le port en mode non bloquant, applique le débit configuré et sonde périodiquement la carte.

/etc/leukos/node.json
{
"device_bridge": {
"enabled": true,
"probe_interval_s": 15,
"plugins": [
{
"name": "arduino_atmega2560",
"enabled": true,
"transport": "serial",
"port": "/dev/ttyUSB0",
"baud": 115200,
"heartbeat_cmd": "PING\n",
"heartbeat_ack": "PONG"
}
]
}
}

Le cycle réel vérifie le port, configure termios, envoie PING, attend PONG pendant 300 ms, puis met à jour connected, last_seen_ts et last_error. Une réponse telle que temperature=21.4 humidity=48 peut également être convertie en métriques.

Extrait simplifié de l'ouverture série :

int fd = open(plugin.port.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);

termios tty{};
tcgetattr(fd, &tty);
cfmakeraw(&tty);
cfsetispeed(&tty, B115200);
cfsetospeed(&tty, B115200);
tty.c_cflag |= CLOCAL | CREAD;
tcsetattr(fd, TCSANOW, &tty);

UART convient aux cartes proches de la box. Il évite une dépendance réseau, mais sa portée et le nombre de périphériques restent limités par le câblage et les ports disponibles.

TCP/IP — transport commun du réseau local

TCP assure une livraison ordonnée et fiable entre la box, les contrôleurs Ethernet/Wi-Fi et les interfaces. Il transporte notamment :

  • l'API HTTP locale du daemon sur le port 8080 ;
  • l'API et la Web IHM du hub Go sur le port 8123 ;
  • MQTT via Mosquitto sur le port 1883 ;
  • les WebSockets de mise à jour temps réel ;
  • gRPC sur le port 9080 lorsqu'il est activé.

TCP ne définit pas le sens métier d'un message : HTTP, MQTT, WebSocket ou gRPC fournissent la structure applicative au-dessus de la connexion.

MQTT — bus de messages local

MQTT découple les producteurs et les consommateurs. Un contrôleur publie son état sans connaître les interfaces qui l'afficheront ; le hub publie une commande sans ouvrir une liaison spécifique vers chaque circuit.

TopicSensContenu
openautomation/<node_id>/statusnode → brokeronline ou LWT offline retenu
openautomation/<node_id>/statenode → brokerÉtat JSON publié environ toutes les 2 secondes
openautomation/<node_id>/cmd/relay/<id>broker → nodeon, off ou toggle
openautomation/<node_id>/cmd/valve/<id>broker → nodeopen, close ou open:600
# Observer la présence et les états du node
mosquitto_sub -h 127.0.0.1 -t 'openautomation/node-0001/#' -v

# Allumer un relais
mosquitto_pub -h 127.0.0.1 \
-t 'openautomation/node-0001/cmd/relay/relay1' \
-m 'on'

# Ouvrir une vanne pendant dix minutes
mosquitto_pub -h 127.0.0.1 \
-t 'openautomation/node-0001/cmd/valve/garden' \
-m 'open:600'

Le Last Will and Testament annonce automatiquement offline si un client disparaît brutalement. Sur un réseau partagé, le listener anonyme doit être remplacé par des comptes, des ACL et TLS.

Communication entre le smartphone et le circuit

Ce chemin évite d'exposer les protocoles des PCB au navigateur. Le hub applique l'authentification et les règles métier, puis l'interface affiche le retour réel du circuit plutôt que la seule intention de l'utilisateur.

Le frontend Vue utilise l'API REST pour son chargement initial, puis maintient un WebSocket sur /api/websocket. Il reçoit ainsi les événements state_changed sans interroger le hub en permanence.

Plug and Play sécurisé

Le plug-and-play automatise l'arrivée d'un contrôleur sans confondre découverte et confiance.

:::info État actuel de l'implémentation Le daemon implémente la réception d'une découverte, la vérification X.509, l'allowlist, le registre SQLite et l'activation manuelle. La découverte mDNS/DNS-SD doit aujourd'hui être réalisée par un service externe. Le transport MQTT avec mTLS et la génération d'ACL dynamiques restent à finaliser. :::

Configuration sécurisée

/etc/leukos/node.json
{
"secure_network": {
"enabled": true,
"require_activation": true,
"require_crl": false,
"discovery_ttl_s": 300,
"ca_cert_path": "/etc/leukos/pki/ca.crt",
"crl_path": "/etc/leukos/pki/crl.pem",
"mqtt_topic_prefix": "home",
"allowed_device_ids": [
"HOME-CTRL-000001",
"HOME-CTRL-000002"
]
}
}

Le service de découverte externe construit un document similaire :

discovery.json
{
"device_id": "HOME-CTRL-000001",
"ip": "192.168.20.41",
"device_type": "room-controller",
"firmware": "1.4.2",
"service": "_homecontroller._tcp.local",
"cert_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n"
}

Puis il appelle l'API locale :

# Soumettre le contrôleur à la vérification
curl -X POST http://127.0.0.1:8080/secure/discover \
-H 'Content-Type: application/json' \
--data-binary @discovery.json

# Lister les devices vérifiés en attente
curl http://127.0.0.1:8080/secure/pending

# Affecter le contrôleur à la pièce « salon »
curl -X POST \
http://127.0.0.1:8080/secure/activate/HOME-CTRL-000001/salon

# Contrôler le registre complet
curl http://127.0.0.1:8080/secure/devices

La vérification C++ refuse le device si le certificat est absent, si son Common Name ne correspond pas au device_id, si la chaîne n'est pas signée par la CA locale, si la CRL l'interdit ou si l'identifiant n'appartient pas à l'allowlist.

Scénarios de mise en réseau

1. Réseau domotique local isolé

La box et les contrôleurs sont reliés à un switch ou à un point d'accès dédié, sans route vers Internet. La box peut exécuter dnsmasq pour fournir DHCP et DNS.

Smartphone ─ Wi-Fi local ─ Box leukOS ─ Switch ─ Contrôleurs
├─ DHCP/DNS
├─ Hub Go
└─ MQTT

Ce scénario maximise l'autonomie. Le smartphone doit simplement rejoindre ce Wi-Fi pour accéder à la Web IHM.

2. Cohabitation avec le routeur Internet

La box et les contrôleurs rejoignent le LAN du routeur Internet existant. Le smartphone reste sur son Wi-Fi habituel et atteint la box par son adresse locale ou son nom DNS.

Internet

Routeur Internet / Wi-Fi / DHCP
├── Smartphone
├── Box leukOS
└── Contrôleurs Wi-Fi ou switch Ethernet

Dans ce mode :

  • le routeur domestique reste le seul serveur DHCP du segment ;
  • une réservation DHCP est recommandée pour la box ;
  • MQTT et l'API du daemon restent limités au LAN ;
  • aucune redirection Internet ne doit exposer 1883, 8080 ou 8123 ;
  • l'accès distant passe par un VPN ou un reverse proxy authentifié en TLS.

3. Box leukOS comme point d'accès Wi-Fi

La box crée son propre SSID domotique et distribue les adresses IP. Son interface Ethernet peut rester reliée au routeur Internet comme lien amont, avec routage/NAT facultatif.

Routeur Internet ─ Ethernet ─ Box leukOS )) Wi-Fi domotique
├── Smartphone
└── Contrôleurs Wi-Fi

Même si Internet tombe, le SSID local, le hub, MQTT et les automatismes continuent de fonctionner.

4. VLAN IoT séparé

Les contrôleurs sont placés dans un VLAN IoT. Le smartphone reste sur le LAN utilisateur et le pare-feu n'autorise que l'accès à la Web IHM de la box.

LAN utilisateurs ── HTTPS/WebSocket ── Box leukOS

MQTT / management

VLAN IoT

Le VLAN IoT ne doit pas initier librement des connexions vers les postes utilisateurs. Les règles autorisent seulement DHCP, DNS, NTP, MQTT vers le broker et les opérations de maintenance nécessaires. mDNS ne traverse pas naturellement les VLAN ; un réflecteur ne doit être ajouté que si la découverte l'exige.

5. Bluetooth/BLE pour la première association

BLE peut simplifier la mise en service d'un contrôleur Wi-Fi qui ne connaît pas encore le SSID :

  1. le device démarre en mode provisioning BLE ;
  2. le smartphone détecte son identifiant de proximité ;
  3. l'application transmet le SSID et un secret Wi-Fi de façon chiffrée ;
  4. le device rejoint le LAN puis lance l'onboarding X.509 ;
  5. BLE est désactivé ou réservé à la maintenance.

:::warning Fonctionnalité cible Ce provisioning BLE décrit le scénario recommandé mais n'est pas encore implémenté dans le Device Bridge C++ actuel, dont le transport actif est serial. BLE ne doit pas devenir un canal permanent de commande à la place de MQTT et de l'identité X.509. :::

Règles de cohabitation réseau

  1. Un seul DHCP par segment pour éviter des adresses et routes incohérentes.
  2. Une IP stable pour la box, de préférence par réservation DHCP.
  3. Pas d'exposition Internet directe des ports techniques.
  4. Séparation des identités : le secret Wi-Fi ne remplace ni le certificat du device ni l'autorisation applicative.
  5. ACL par zone : un contrôleur de salon ne publie et ne souscrit qu'aux topics qui lui sont nécessaires.
  6. Fonctionnement hors ligne : DNS local, MQTT, API, Web IHM et automatismes ne doivent pas dépendre d'un service cloud.

Diagnostic rapide

# Interfaces, adresses et route par défaut
ip address
ip route

# Ports attendus
ss -lntp | grep -E ':(1883|8080|8123|9080)\b'

# Daemon, hub et flux MQTT
curl http://127.0.0.1:8080/status
curl http://127.0.0.1:8123/api/
mosquitto_sub -h 127.0.0.1 -t '#' -v

# Ports UART présents
ls -l /dev/ttyUSB* /dev/ttyACM* 2>/dev/null

Pour aller plus loin