Intégration Homekit - Nouvelles fonctionnalités

Bonjour à tous,

après avoir fait l’intégration externe pour mes chauffages Neomitis, j’ai poursuivi l’utilisation de mon compte pro Claude :slight_smile:

Je me suis attaqué à porter tout ce qui est possible de l’être d’Homekit sur Gladys.

Il y a X PR faites. Je n’ai pas encore pu tester donc les testeurs sont les bienvenus :wink:

Tout a entièrement été fait par Claude. Si j’ai mal fait certaines choses, je suis preneur de vos critiques et aides pour corriger le tir (la programmation n’est pas mon métier).

Ci-après vous trouverez un état des lieux de ce qui a été fait et reste à faire (by Claude) :

## Où on en est

Le pont HomeKit de Gladys exposait 12 types d’appareils. Le reste — détecteurs de fumée, serrures, thermostats, batteries, boutons — restait invisible côté iPhone, **sans message d’erreur** : les appareils n’apparaissaient simplement pas.

**Mergé :** [#2781](feat(homekit): expose light, CO, CO2 and air quality sensors by Dreamthy · Pull Request #2781 · GladysAssistant/Gladys · GitHub) — capteurs de luminosité, CO, CO2 et qualité de l’air.

**En attente de relecture :**

- [#2792](feat(homekit): expose sirens as a Switch by Dreamthy · Pull Request #2792 · GladysAssistant/Gladys · GitHub) — **Sirène** (`Switch`)

- [#2793](feat(homekit): expose smoke sensors by Dreamthy · Pull Request #2793 · GladysAssistant/Gladys · GitHub) — **Détecteur de fumée** (`SmokeSensor`)

- [#2794](Feat/homekit lock by Dreamthy · Pull Request #2794 · GladysAssistant/Gladys · GitHub) — **Serrure** (`LockMechanism`)

- [#2795](feat(homekit): expose buttons as stateless programmable switches by Dreamthy · Pull Request #2795 · GladysAssistant/Gladys · GitHub) — **Bouton, télécommande** (`StatelessProgrammableSwitch`)

- [#2796](Feat/homekit fan by Dreamthy · Pull Request #2796 · GladysAssistant/Gladys · GitHub) — **Ventilateur** (`Fanv2`)

- [#2797](feat(homekit): expose device batteries by Dreamthy · Pull Request #2797 · GladysAssistant/Gladys · GitHub) — **Niveau de batterie** (`Battery`)

- [#2798](feat(homekit): expose PM2.5 and PM10 densities on the air quality sensor by Dreamthy · Pull Request #2798 · GladysAssistant/Gladys · GitHub) — **Particules PM2.5 et PM10** (`AirQualitySensor`)

- [#2799](Feat/homekit thermostat by Dreamthy · Pull Request #2799 · GladysAssistant/Gladys · GitHub) — **Thermostat et climatisation** (`Thermostat`)

Côté intégrations, ça touche surtout **Zigbee2mqtt**, **Z-Wave**, **Matter** et **Xiaomi**, plus **Nuki** pour les serrures, **Netatmo** et **MELCloud** pour le thermostat, et **Bluetooth** pour les batteries.

Une neuvième PR arrive : le **choix des appareils exposés**. Aujourd’hui le pont expose tout ce qu’il sait exposer, ce qui noie l’app Maison sur une grosse installation. Elle ajoute une option pour n’exposer qu’une sélection.

Chaque PR couvre une catégorie, est relisable seule, et porte 100 % de couverture de tests sur les lignes ajoutées.

## Couverture réelle

`hap-nodejs`, la bibliothèque utilisée par Gladys comme par Homebridge, expose 73 services. Mais tous ne sont pas des types d’appareils : 38 sont de la plomberie du protocole (appairage, transport, firmware), des pièces qui n’existent qu’à l’intérieur d’autres services, ou des doublons obsolètes.

Il reste donc **35 services réellement exposables**. Le pont en couvrait **12** avant ce chantier, il en couvrira **15** avec les PR en cours — soit **43 %**, plus des caractéristiques ajoutées à des services existants.

### D’où sort ce chiffre de 73 — et pourquoi la doc Apple n’est pas la bonne référence

Piège classique au démarrage : la documentation HomeKit sur le site développeur d’Apple décrit le **framework** HomeKit, celui qui sert à écrire une app iOS qui *pilote* des accessoires. Un pont, lui, relève de **HAP**, le HomeKit Accessory Protocol.

Apple publie une *HomeKit Accessory Protocol Specification (Non-Commercial Version)*, dont la Release R2 est la dernière version publique. La version commerciale est sous NDA, réservée au programme MFi.

Détail intéressant trouvé dans le code de `hap-nodejs` : elle ne transcrit pas le PDF de la spec, elle **génère** ses définitions depuis des ressources d’Apple présentes sur macOS — `HomeKitDaemon.framework` et les métadonnées du HomeKit Accessory Simulator.

Conséquence pratique : elle suit ce qu’iOS implémente réellement, pas ce que la R2 de 2019 décrivait. On y trouve des services annotés « depuis iOS 15 », absents de la spec publique. Et ça donne un référentiel vérifiable en local, avec les caractéristiques, leurs bornes et leurs unités.

## Cinq pièges, pour qui voudrait contribuer

### 1. Une catégorie ne suffit pas : c’est le couple catégorie + type

Le plus vicieux des cinq. Une feature Gladys a une **catégorie** et un **type**. Le pont vérifie que le couple existe dans sa table de correspondance. Si le type n’y est pas, la feature est ignorée — **sans erreur ni log**.

Or une intégration peut réassigner la catégorie d’une feature *sans toucher à son type*. Deux cas réels, tous deux trouvés en cours de route :

- **Z-Wave** reclasse des capteurs binaires en `co2-sensor`, en leur laissant `type: binary`. J’avais mappé `co2-sensor` pour les types décimal et entier, pas binaire → tous les détecteurs de CO2 Z-Wave restaient invisibles. Trouvé en relecture de la première PR.

- **Nuki** remonte son niveau de batterie en `lock:integer`, là où les autres utilisent `sensor:integer`. Mapper les types attendus seuls aurait silencieusement écarté toutes les serrures Nuki.

La méthode qui les évite : lister les couples **réellement produits** par les intégrations, et ne jamais supposer les types « évidents » d’une catégorie.

### 2. Les unités ne se devinent pas

HomeKit attend les densités de particules en **µg/m³**. Gladys laisse une intégration les déclarer en milligrammes, microgrammes **ou** nanogrammes par mètre cube. Sans conversion, un capteur en mg/m³ s’affiche mille fois trop bas, et rien ne le signale.

Même sujet pour les COV, mais avec une issue différente : Gladys les stocke en **ppb**, HomeKit veut des µg/m³. La conversion demande la masse molaire du composé, qu’une feature « COV » générique ne porte pas. Aucun facteur ne peut être choisi honnêtement, donc les COV restent hors du pont, volontairement.

### 3. Le pont temporise 5 secondes par défaut

Utile pour ne pas inonder l’iPhone de changements d’état. Rédhibitoire pour un **bouton** : un appui est un événement, pas un état. Avec 5 secondes de retard, HomeKit réagit trop tard, ou avale l’appui si un second suit. Il faut mettre ce délai à zéro explicitement.

### 4. Gladys est parfois plus riche qu’HomeKit

`BUTTON_STATUS` compte **plus de cent valeurs** : clic, double-clic, appui long, mais aussi rotation, secousse, flèches directionnelles, gestes de luminosité. HomeKit n’en connaît **que trois**.

Le choix fait : ne remonter que les trois qui ont un équivalent exact, et **ignorer les autres** plutôt que de les rabattre sur l’une des trois. Déclencher la mauvaise automatisation chez quelqu’un est pire que de n’en déclencher aucune.

### 5. Un appareil, un service, pas trois

HomeKit modélise en un seul service ce que Gladys éclate en plusieurs catégories :

- Le service `Thermostat` ← consigne chaud, consigne froid, mode, capteur de température

- Le service `AirQualitySensor` ← indice de qualité, PM2.5, PM10

- Le service `Battery` ← niveau, alerte batterie faible

Sans regroupement, l’app Maison affiche trois tuiles pour un seul appareil. Le cas s’est produit avec un ventilateur Matter : il apparaissait en **trois ventilateurs distincts**.

## Ce qui est bloqué, et pourquoi

Ce sont des limites du **cœur de Gladys**, pas du pont.

**`GarageDoorOpener`, `Outlet`, `Door`, `Window`** — il n’existe pas de `device_class` dans le modèle Gladys permettant de dire « ce volet est une porte de garage » ou « cette prise est une prise, pas un interrupteur ». C’est le blocage le plus structurant : il ferme quatre services d’un coup. Le lever dépasse largement le pont HomeKit et mériterait sa propre discussion.

**`SecuritySystem`** — l’alarme maison n’est pas un appareil : elle vit dans `t_house.alarm_mode`, or le pont itère sur les appareils.

**`Valve`** — les sept types `water-valve` sont *tous en lecture seule* : débit, volume d’arrosage, état de fonctionnement. Aucune commande d’ouverture. Une tuile de vanne inactionnable serait pire que rien — et ces vannes sont déjà pilotables, leur commande passant par une feature `switch:binary` que le pont expose déjà.

**`OccupancySensor`** — HomeKit attend un booléen stable, alors que Gladys remonte la présence en `sensor:push`, un événement sans état persistant. Il faudrait synthétiser un état avec une temporisation d’extinction choisie arbitrairement : c’est de la logique métier, pas du mapping.

**`HeaterCooler`** — la catégorie `heater` n’a qu’un type, `pilot-wire-mode`. Le fil pilote est une spécificité française sans équivalent HomeKit.

**`Television` et `CameraRTPStreamManagement`** — hors périmètre volontairement : ce sont des chantiers à part entière, pas des ajouts de correspondance.

## Et pourquoi pas une intégration externe ?

Ce n’est **pas possible aujourd’hui**, pour trois raisons structurelles :

1. Le pont doit s’annoncer en **mDNS sur le réseau local** pour que l’iPhone le découvre. Une intégration externe tourne dans un réseau isolé où le multicast ne passe pas.

2. Il doit **écouter sur un port fixe**, joignable depuis le LAN.

3. Il doit voir **tous les appareils** de toutes les intégrations, alors que le modèle externe isole chaque intégration dans son propre espace de noms.

Attention à une confusion fréquente : il existe des discussions sur une intégration **HomeKit Controller**, qui va dans l’*autre* sens — piloter des accessoires HomeKit depuis Gladys. Celle-là serait portable en externe. Le pont, non.

## Où aider

**Tester sur du vrai matériel.** C’est le besoin numéro un. Tout est couvert par des tests automatisés, mais l’appairage réel n’a pas été validé sur tous les types d’appareils. Si vous avez une serrure, un thermostat, un ventilateur ou un détecteur de fumée et un iPhone, votre retour vaut plus que n’importe quel test unitaire.

**Relire les PR**, en particulier les décisions de correspondance : seuils de détection de gaz, bandes de qualité de l’air, états de serrure. Elles sont toutes documentées et justifiées dans les descriptions.

**Reste faisable, non fait :** `FilterMaintenance`, pour le suivi de filtre HEPA. Un seul producteur aujourd’hui, donc faible valeur — mais c’est une contribution simple pour qui veut se lancer.

Merci pour tes PRs @jeromeme !! :smiley:

J’ai lancé les reviews Cursor automatique sur tes PRs !