Intégrations externes : mettre à jour vers Gladys 5.3, le SDK JS 0.16 et le store

Bonjour à tous !

Beaucoup de choses ont bougé ces dernières semaines côté intégrations externes : nouvelle version du SDK JavaScript (@gladysassistant/integration-sdk v0.16.0), nouveaux champs dans le manifest, nouvelles règles de validation dans le store… Ce post rassemble tout ce que vous devez faire pour mettre votre intégration à jour, et ce que vous pouvez faire en plus si vous le souhaitez.

Bonne nouvelle : il n’y a pas de changement cassant obligatoire. Une intégration publiée aujourd’hui reste indexée. Mais quelques points méritent une vérification, et les nouveautés valent le détour :slightly_smiling_face:


:white_check_mark: La checklist rapide

  • Passer le SDK en ^0.16.0 (Node.js ≥ 20)
  • Vérifier vos poll_frequency : en millisecondes, et uniquement parmi les valeurs autorisées
  • Utiliser publishChangedStates si vous publiez beaucoup d’états (limite de 300 états/minute)
  • Ajouter categories (et éventuellement keywords / countries) au manifest
  • Vérifier que gladys_version couvre bien tous les champs que vous déclarez
  • Avoir docs/en.md et docs/fr.md (300 caractères minimum chacun)
  • Vérifier la cover : JPEG ou PNG, 800×534 px exactement, 150 Ko maximum
  • Lancer le validateur local : npx github:GladysAssistant/integration-store
  • Publier : incrémenter version + docker_image, en poussant l’image avant le manifest

Le détail de chaque point est ci-dessous.


1. Mettre à jour le SDK

npm install @gladysassistant/integration-sdk@^0.16.0

Le SDK demande Node.js ≥ 20. Pensez à vérifier l’image de base de votre Dockerfile.

Ce qui a changé depuis la v0.11 :

Version Nouveautés principales
0.12 Synchro avec Gladys 4.86 : capteurs réseau électrique / gaz, caméras PTZ, wakeOnLan(), champ de config account_link
0.13 Six nouveaux phénomènes météo dans le format pivot, sirènes, recharge de batterie, format des résultats de scan
0.14 Déclencheurs et actions de scènes, widgets de tableau de bord, getHouses(), capteurs carbone du réseau et fumée
0.15 DEVICE_POLL_FREQUENCIES, Gladys factice pour vos tests, parseMdnsTxt(), publishChangedStates(), type calendar, contrats d’énergie, formulaires dans les boutons de widgets, sélecteur de maison, publishEnergyConsumption()
0.16 Lecteurs de musique, types ai et tts, should_poll devient facultatif

Le changelog complet est sur GitHub.


2. Les points à vérifier dans votre code

:stopwatch: poll_frequency : en millisecondes, et seulement certaines valeurs

C’est le piège le plus fréquent. poll_frequency est exprimé en millisecondes, et seules ces valeurs sont acceptées : 1 s, 2 s, 10 s, 15 s, 30 s ou 1 min. Toute autre valeur (300 pensé en secondes, 300000 pour 5 minutes…) fait échouer publishDiscoveredDevices avec une erreur 400.

Utilisez les constantes exportées par le SDK :

import { DEVICE_POLL_FREQUENCIES } from '@gladysassistant/integration-sdk';

await gladys.publishDiscoveredDevices([
  {
    name: 'Station météo',
    external_id: ids.device,
    should_poll: true,
    poll_frequency: DEVICE_POLL_FREQUENCIES.EVERY_MINUTES, // 60000 ms
    features: [/* … */],
  },
]);

Quelques précisions :

  • Une minute, c’est le rythme le plus lent. Pour aller plus lentement (API cloud avec quota, réglage utilisateur en minutes), gardez EVERY_MINUTES et ignorez les polls inutiles dans onPoll, ou utilisez votre propre timer.
  • Depuis Gladys 5.3, poll_frequency suffit : le core active should_poll tout seul. Si votre gladys_version accepte des versions plus anciennes, gardez should_poll: true. Si vous mettez should_poll, ce doit être un booléen.
  • Ces deux champs sont lus à la création de l’appareil : les modifier ensuite ne met pas à jour un appareil déjà créé.

:chart_decreasing: Limite de 300 états par minute : publishChangedStates

L’API hôte limite POST /state à 300 états par minute et par intégration. Si vous interrogez beaucoup d’appareils, ne publiez que ce qui a changé :

// remplace publishStates : seules les valeurs modifiées partent vers Gladys
await gladys.publishChangedStates(states);

// et on renvoie quand même une valeur inchangée toutes les 30 minutes
await gladys.publishChangedStates(states, { heartbeat: 30 * 60 * 1000 });

Le SDK découpe les lots de plus de 100 états, renvoie ce que Gladys a refusé et oublie les valeurs d’un appareil quand l’utilisateur le crée, le modifie ou le supprime.

:label: Utilisez les constantes, pas des chaînes en dur

DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES et DEVICE_FEATURE_UNITS sont une copie conforme de server/utils/constants.js dans Gladys, et elles sont tenues à jour à chaque version. Si vous avez recopié des chaînes à la main, c’est le bon moment pour passer aux constantes : vous évitez les fautes de frappe et vous avez l’autocomplétion.

:sun_behind_rain_cloud: Intégrations météo : night est déprécié

La condition night reste acceptée mais elle est dépréciée. Une nuit pluvieuse s’écrit weather: 'rain', is_day: false. Pensez aussi aux nouvelles conditions du format pivot et au champ type des alertes (WEATHER_ALERT_TYPES).

:clapper_board: Déclencheurs et actions de scènes : les clés sont définitives

Si vous déclarez des scene_triggers / scene_actions, une clé publiée ne doit jamais être renommée. Et ajouter un champ required sans default à une action existante casse les scènes qui l’utilisent.


3. Mettre à jour le manifest

La règle d’or : gladys_version doit couvrir ce que vous déclarez

Les anciennes versions de Gladys refusent les champs qu’elles ne connaissent pas. Le store vérifie donc que le minimum de votre gladys_version couvre chaque champ déclaré, sinon l’intégration est rejetée. Comme ça, l’utilisateur voit simplement « nécessite Gladys ≥ X » dans le catalogue, au lieu d’une installation qui échoue sans explication.

Vous déclarez… gladys_version minimum
categories >=4.86.0
type: "provider", widgets, scene_triggers, scene_actions >=5.1.0
type: "calendar", account_schema, energy_contracts, un champ avec source: "houses" >=5.2.0
type: "ai", type: "tts", music, keywords, countries >=5.3.0

:warning: Dans l’autre sens, ne montez pas gladys_version sans raison : votre intégration serait masquée pour les utilisateurs qui n’ont pas encore mis à jour Gladys.

:card_index_dividers: categories : votre place dans le catalogue

Entre 1 et 3 catégories parmi : climate, lighting, energy, security, multimedia, appliances, environment, protocols, network, notifications, assistants, services, transport, vehicles, servers, leisure.

Les quatre dernières (transport, vehicles, servers, leisure) viennent d’être ajoutées. Sans categories, votre intégration reste visible dans « Toutes » et dans la recherche, mais n’apparaît dans aucune rubrique. Pour les intégrations déjà publiées, le store applique en attendant un mapping de secours (data/category-fallback.json). Déclarer vous-même vos catégories est le meilleur moyen d’être bien placé. Une catégorie inconnue est simplement ignorée, avec un avertissement.

:magnifying_glass_tilted_right: keywords et countries (Gladys ≥ 5.3)

{
  "gladys_version": ">=5.3.0",
  "categories": ["energy"],
  "keywords": ["linky", "enedis", "téléinfo"],
  "countries": ["FR"]
}
  • keywords : 1 à 10 termes de 2 à 30 caractères, jamais affichés, utilisés uniquement par la recherche (marques, modèles, synonymes, villes ou réseaux desservis…).
  • countries : 1 à 20 codes pays ISO en majuscules. Ne le mettez pas si votre intégration fonctionne partout (c’est le comportement par défaut). Si vous le déclarez, les instances situées dans un autre pays ne verront plus l’intégration dans les rubriques du catalogue (elle reste trouvable via la recherche). Pensez-y pour une intégration régionale : service météo national, réseau de transport, fournisseur d’énergie, FAI…

N’oubliez pas : déclarer keywords ou countries impose gladys_version ≥ 5.3.0.


4. Documentation et cover

  • Documentation obligatoire : docs/en.md et docs/fr.md à la racine du dépôt, 300 caractères minimum chacun, en suivant les sections du template (Présentation / Prérequis / Configuration / Dépannage). S’il en manque une, l’intégration est rejetée. Les fichiers sont hébergés par le store et affichés dans les écrans d’installation et de configuration de Gladys.
  • Nouveau : docs/de.md et docs/es.md sont facultatifs. S’ils sont présents (300 caractères minimum), ils sont affichés aux utilisateurs allemands et espagnols.
  • Cover : JPEG ou PNG, exactement 800×534 px, 150 Ko maximum, URL https directe (sans redirection). Le plus simple : une URL raw.githubusercontent.com vers un fichier de votre dépôt. Une cover invalide ne bloque pas l’indexation, mais vous aurez une image par défaut dans le catalogue.

5. Valider en local avant de publier

Plus besoin d’attendre l’indexation horaire pour découvrir un rejet ! À la racine de votre dépôt :

npx github:GladysAssistant/integration-store

Le validateur fait exactement les mêmes vérifications que le robot du store (schéma, règles gladys_version, catégories, documentation, existence des images Docker, cover) et affiche tous les problèmes d’un coup. Code de sortie 0 = l’intégration serait indexée, 1 = elle serait rejetée.

Dans la CI de vos pull requests

Dans une PR qui incrémente la version, l’image Docker n’est généralement pas encore publiée : ajoutez --skip-image-check pour sauter seulement cette vérification.

- uses: actions/setup-node@v4
  with:
    node-version: 24
- run: npx github:GladysAssistant/integration-store --skip-image-check

Relancez-le sans l’option une fois les images publiées, par exemple en dernière étape de votre workflow de release.


6. Publier la nouvelle version

  1. Incrémentez version (semver strict) et docker_image (avec un tag explicite) dans le manifest.
  2. Publiez l’image Docker avant que le manifest qui la référence n’arrive sur la branche par défaut : le store vérifie que l’image existe et qu’elle est téléchargeable sans authentification. Si l’image manque, l’intégration est retirée du catalogue jusqu’à la prochaine indexation.
  3. Poussez. À la prochaine indexation (toutes les heures), Gladys affichera « mise à jour disponible » à vos utilisateurs.

Votre intégration n’apparaît pas ? Regardez le fichier public rejected.json du store : chaque rejet y est listé avec sa raison (error = non indexée, warning = indexée avec une dégradation, par exemple la cover par défaut).


7. Testez votre intégration avec le Gladys factice

Le SDK fournit maintenant un Gladys en mémoire pour vos tests unitaires : c’est un vrai GladysIntegration, branché sur un faux Gladys au lieu du réseau.

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { createFakeGladys } from '@gladysassistant/integration-sdk/testing';
import { registerHandlers } from '../src/app.js';

test('publie la température au poll', async () => {
  const gladys = createFakeGladys({ config: { api_key: 'key' } });
  registerHandlers(gladys);
  await gladys.connect();

  const [device] = gladys.fake.discoveredDevices;
  assert.deepEqual(await gladys.fake.poll(device), { success: true });
  assert.equal(gladys.fake.lastState(`${device.external_id}:temperature`), 21.5);
});

Il applique les mêmes vérifications que l’API hôte (préfixe des external_id, catégories/types/unités connus, poll_frequency…) et répond avec les mêmes erreurs 400. Vous voyez donc les erreurs dans vos tests plutôt que chez vos utilisateurs.


8. Pour aller plus loin (facultatif)

Si vous voulez enrichir votre intégration, voici tout ce qui est maintenant possible :

Fonctionnalité Manifest SDK Gladys
Widgets de tableau de bord widgets onWidgetGet, onWidgetAction, requestWidgetRefresh ≥ 5.1
Déclencheurs / actions de scènes scene_triggers, scene_actions publishSceneEvent, onSceneAction ≥ 5.1
Intégration « capacités seules » type: "provider" — ≥ 5.1
Fournisseur de calendrier type: "calendar", account_schema publishCalendars, publishCalendarEvents… ≥ 5.2
Contrats et calendriers d’énergie energy_contracts publishEnergyCalendar, onEnergyPrice… ≥ 5.2
Consommation datée (relevés reçus après coup) — publishEnergyConsumption ≥ 5.2
Choix d’une maison dans un formulaire source: "houses" — ≥ 5.2
Fournisseur d’IA (compatible OpenAI) type: "ai" onAiChat ≥ 5.3
Synthèse vocale type: "tts" onTtsSynthesize ≥ 5.3
Lecteurs de musique (navigation, recherche, file d’attente) music publishNowPlaying, onMusicBrowse, onMusicPlay… ≥ 5.3
Wake-on-LAN network_wake: true wakeOnLan ≥ 4.86
Connexion à un compte sans redirection (QR code…) champ account_link onOAuthAuthorizeUrl ≥ 4.86

Tout est documenté dans le README du SDK, et toutes les règles du manifest sont dans le README du store.


Si vous bloquez sur une migration ou si une règle de validation vous paraît bizarre, répondez dans ce sujet ou ouvrez une issue sur integration-sdk-js / integration-store.

Merci à tous ceux qui développent des intégrations, le catalogue grandit très vite ! :folded_hands:

2 « J'aime »