Capteurs Bluetooth (BLE) : ouvrir la voie à une intégration externe

Suite à un échange avec le créateur de Theengs / OpenMQTTGateway, un manque a été identifié : Gladys a bien une intégration Bluetooth, mais elle ne couvre qu’une poignée d’appareils — alors que l’écosystème des capteurs BLE (température, humidité, plantes, etc. : Xiaomi, SwitchBot, RuuviTag…) est énorme, et que des projets comme Theengs savent en décoder des centaines.

Pour moi, ça doit passer par une intégration externe, pas par du code dans le core. Mais aujourd’hui, le framework d’intégrations externes ne donne pas accès au Bluetooth de la machine, et pour de bonnes raisons : contrairement à une clé Zigbee (un simple périphérique USB qu’on peut monter dans le conteneur), donner l’accès Bluetooth à un conteneur implique de lui donner des privilèges réseau très larges sur la machine, incompatible avec le modèle de sécurité du store (des intégrations tierces non auditées, installables en un clic).

La piste envisagée : un accès Bluetooth médié, sur le même modèle que la découverte réseau déjà en place, le core écoute la radio et relaie les trames brutes, l’intégration les décode et publie capteurs et états via les API existantes. L’adaptateur reste sous le contrôle du core, ce qui sera de toute façon indispensable le jour où on fera du commissioning Matter/Thread en BLE.

À noter : pour ceux qui utilisent des passerelles ESP32 avec OpenMQTTGateway, une intégration externe est déjà possible dès aujourd’hui via MQTT, sans rien changer au framework.

Le sujet ici, c’est l’utilisation de l’adaptateur Bluetooth de la machine qui fait tourner Gladys.

Salut,

En effet si l’acces au Bluetooth est possible ca devrait nous permettre de decoder les trames et de rendre Gladys compatible en lecture avec tous ces appareils

Voici ce dont un décodeur comme Theengs a besoin, côté API :

1. C’est l’intégration qui pilote le scan — le core exécute et arbitre. Même philosophie que scanNetwork() : l’intégration demande une fenêtre de scan bornée, par exemple gladys.scanBluetooth({ mode, durationSeconds, filters }), et le core garde la main sur l’adaptateur. Deux nuances par rapport à scanNetwork :

  • les trames doivent être streamées pendant la fenêtre (callback au fil de l’eau), pas seulement rendues en bloc à la fin, la latence compte pour les états ;
  • la fenêtre doit être renouvelable (modèle de bail) : c’est l’intégration qui décide de sa cadence — soutenue pendant une découverte, duty cycle relâché en régime de croisière (ex. 10 s de scan toutes les 60 s), arrêt quand l’utilisateur désactive.

Le core reste seul arbitre : durée max par fenêtre, quotas, partage entre intégrations, et préemption immédiate quand Matter/Thread a besoin de la radio.

2. Le contenu de trame minimal. Pour décoder, Theengs a besoin de :

  • mac (+ type d’adresse public/random) — c’est l’identifiant stable de l’appareil
  • rssi
  • name (local name) si présent
  • manufacturerdata (bytes, hex ou base64)
  • servicedata + servicedatauuid
  • serviceUuids annoncés
  • un timestamp, et l’indication trame d’advertising vs scan response

Un champ brut (payload_base64 des AD structures, cohérent avec scanNetwork) en complément des champs parsés serait idéal : ça couvre les cas exotiques sans figer le parsing côté core.

3. Scan passif ET actif, au choix de la requête. Certains capteurs très répandus n’exposent leurs données que dans la scan response (donc scan actif requis). Le mode est un paramètre de la requête de scan ; le manifest, lui, déclare la capacité maximale autorisée (ex. "bluetooth": { "modes": ["passive", "active"] }) que l’utilisateur accorde à l’installation.

4. Filtrage côté core, paramétré par la requête. Optionnel mais précieux pour ne pas saturer le WebSocket : filtres par préfixe MAC, manufacturer_id ou service_uuid passés dans les options de scan, et un throttle par MAC (ex. max 1 trame/MAC/seconde, les capteurs répètent la même trame en rafale).

5. Gestion des adaptateurs : au niveau du core, propriétaire unique. C’est le point qui rend le modèle médié vraiment supérieur à un accès direct :

  • le core inventorie les adaptateurs (hci0, dongles USB…), les tient à jour (hotplug), surveille leur santé et les réinitialise en cas de blocage, les adaptateurs BLE bon marché gèlent régulièrement, un watchdog centralisé profite à tout le monde ;
  • le core est l’unique propriétaire de chaque adaptateur et multiplexe tous les consommateurs : service Bluetooth core (GATT/présence), commissioning Matter/Thread, et fenêtres de scan des intégrations, fini les conflits d’ownership entre processus ;
  • côté utilisateur : si plusieurs adaptateurs sont présents, c’est dans la config core qu’il assigne les rôles (ex. hci0 réservé à Matter, dongle USB pour le scan des intégrations) ;
  • côté intégration : jamais de chemin /dev ni de nom d’adaptateur physique, au plus un identifiant logique optionnel dans les options de scan quand l’utilisateur a assigné plusieurs adaptateurs. L’intégration demande « un scan », pas « l’adaptateur X ».

Bonus à terme : plusieurs adaptateurs assignés au scan = plusieurs antennes, meilleure couverture —et l’API n’a pas à changer, le core agrège les trames.

6. Consentement utilisateur. Comme pour les classes matérielles existantes : l’écoute BLE révèle la présence de personnes (téléphones, wearables) — un écran d’autorisation à l’installation, distinct des autres permissions, semble la bonne granularité.

7. Hors périmètre pour un v1 du relais (de notre point de vue) : pas de connexion GATT ni d’écriture depuis les intégrations, l’advertising en lecture seule couvre déjà l’immense majorité des capteurs, et ça garde le modèle de sécurité simple.

Quelques ressources:

https://www.npmjs.com/package/theengs-decoder

Salut tout le monde !

Ce sujet est désormais en cours de développement.

Une PR a été ouverte pour spécifier le streaming des advertisements BLE (capteurs Bluetooth) :

N’hésitez pas à suivre la PR, à tester (optionnel, surtout pour les petites demandes) et à faire vos retours ici si besoin.

@1technophile J’ai proposé une spec avec Fable 5, tu en penses quoi ? :slight_smile:

@pierre-gilles Cela va ouvrir la voie pour une intégration externe OTBR ?

Merci, qq commentaires mais rien de bloquant

Merci pour tes retours @1technophile !

Non je ne pense pas !