Intégration externe - Daikin Cloud

Salut @prohand, super boulot, j’ai regardé le code de la branche et le résultat est cohérent avec ce que fait le core. Tu peux pousser, la mécanique est bonne. Trois points quand même, dont deux qui méritent une correction avant ou juste après la mise en prod.

1. Le parent est un compteur qui se remet à zéro, pas un index

Tu publies « Énergie aujourd’hui » en energy-sensor / energy, que Gladys documente comme « la consommation d’énergie cumulée » et traite comme un index. Le job calculateConsumptionFromIndex fait index(t) − index(t−1) et jette les deltas négatifs (« counter reset detected »). Donc rien n’est compté deux fois — c’est bien pour ça que ton total journalier tombe juste — mais tout ce qui est consommé entre le dernier poll avant minuit et le premier poll après est perdu, chaque nuit. Avec 900 s de polling ça fait le dernier quart d’heure de la journée ; et si Daikin ne remplit son bucket 22h–24h qu’après minuit, c’est deux heures qui disparaissent.

Le correctif propre : que l’intégration tienne son propre cumul (dans son store, total += max(0, today − today_précédent)) et publie un vrai energy-sensor / index monotone. Le core dérive alors exactement, et le cas minuit disparaît.

2. Les buckets de 2 h faussent le coût en HP/HC et Tempo

Daikin n’expose que 12 tranches de 2 h. Ta série 30 minutes va donc ressembler à 0, 0, 0, 1.8 kWh, 0, 0, 0, …. Le total du jour est juste (d’où la correspondance avec l’app Onecta), mais la répartition dans la journée ne l’est pas. Or calculateCostFrom tarifie chaque fenêtre de 30 min au prix de cette fenêtre-là : sur un contrat Base c’est sans conséquence, sur heures pleines/creuses ou Tempo le coût peut être franchement faux, selon l’heure à laquelle le poll est tombé.

Deux options : le documenter clairement (« coût fiable en Base, indicatif en HP/HC »), ou mieux — saveStates accepte un created_at, tu peux donc publier les états de l’index horodatés aux bornes des buckets Daikin plutôt qu’à l’heure du poll. La conso retombe alors dans les bonnes demi-heures.

3. Dériver toi-même les UUID, c’est mon problème, pas le tien

Choisir les id des features pour pouvoir pointer energy_parent_id avant que les lignes existent, ça marche (le device.create insère les features puis résout les liens dans une seconde passe), et ton garde-fou — ne nommer que les features que Gladys ne connaît pas encore — est le bon. Mais publier un id dans le payload de découverte n’est pas dans la spec des intégrations externes : ça passe aujourd’hui parce que rien ne le valide, et je ne veux pas que ça devienne un contrat implicite.

Je vais donc câbler addEnergyFeatures() (celui de Zigbee2mqtt/Tasmota) sur les intégrations externes, dans getDiscoveredDevices : toute intégration qui publie un index aura la paire 30 min automatiquement, ids et liens gérés par le core. Garde ton code bien isolé (featureUuid.js + le bloc dans buildDevice) pour pouvoir le retirer d’un bloc quand ce sera dispo.

La demande :

Et deux détails :

  • Le palier energy de ton échelle de capacités ne sert à rien : energy_parent_id est arrivé dans Gladys en août 2025, bien avant les intégrations externes. Toute instance capable de faire tourner ton conteneur a déjà le suivi d’énergie.
  • « Énergie ce mois-ci » et « Énergie cette année » doivent rester au niveau 0, c’est normal et il ne faut surtout pas les rattacher : elles sont typées energy elles aussi, donc elles apparaissent comme parents possibles dans Réglages → Suivi de l’énergie, et un utilisateur qui les câble compterait les mêmes kWh plusieurs fois. Une ligne dans la doc pour dire « ne rattachez que la conso du jour » évitera la question.

Bref : go pour la prod, et je m’occupe du point 3 côté core.