# Intégrations externes dans Gladys Assistant

**URL:** <https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343>\
**Category:** Demandes livrées\
**Created:** [Juillet 13, 2026, 9:09 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343 "2026-07-13T09:09:55Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Juillet 19, 2026, 6:20 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/41 "2026-07-19T06:20:07Z")

</div>

Trop cool ces investigations, franchement c’est bluffant on dirait des intégrations natives !

Ce qui est cool, c’est qu’une fois que tu te sens prêt sur ces intégrations, il te suffit de mettre ton repo dans le topic github que le store scanne toutes les heures, et hop il sera publié sur les instances Gladys 😁

Il y a de la validation automatique sur le manifest et l’image Docker, et c’est tout !

> [@Terdious](#):
>
> - sauf si erreur de ma part, en dev, il serait possible de pouvoir mettre à jour plus facilement l’image, notamment quand le manifest ne change pas ?

Tu peux le faire avec le bouton « forcer la mise à jour » ! 😉

> [@Terdious](#):
>
> - On ne peut pas passer les intégrations externe en favoris

Je vais regarder !

> [@Terdious](#):
>
> - Pouvoir filtrer les intégrations externes pourrait être top

Carrément !!

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 19, 2026, 8:55 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/42 "2026-07-19T08:55:18Z")

</div>

> [@pierre-gilles](#):
>
> Trop cool ces investigations, franchement c’est bluffant on dirait des intégrations natives !

En effet, l’intégration visuelle est vraiment excellente, et pour 1 user, d’une simplicité extrême !

D’un autre côté, il va falloir bosser sur la doc, car ici toutefois, aucune possibilité d’afficher de l’information.

Et pour les systèmes plus complexes comme Tuya avec son implémentation locale, il manque encore des briques (ouh làlà !! aucune critique hein 😅 ce nouveau système à été implémenté avec une vitesse complètement folle et fait déjà ses preuves 😂 👏)

> [@pierre-gilles](#):
>
> > [@Terdious](#):
> >
> > - sauf si erreur de ma part, en dev, il serait possible de pouvoir mettre à jour plus facilement l’image, notamment quand le manifest ne change pas ?
> 
> Tu peux le faire avec le bouton « forcer la mise à jour » ! 😉

Alors il nous manque (à Fable et à moi) une connaissance sur ce point car non ça ne fonctionne pas sur une image dev, et si le manifest change !

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/7/4/743a0ecd334485885f84eb347b2e8efc44f7627f.png)  
 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/d/2/d213c1ce1d1c2a10112ad1556820e93ae1724b93.png)

De ce qu’on voit il se porte sur le numéro de version dans le nom de l’image ?

Logs :

```auto
2026-07-19T10:53:49+0200 <warn> externalIntegration.update.js:43 (ExternalIntegration.update) Unable to pull image ghcr.io/terdious/gladys-tuya:1.0.0 Error: (HTTP code 404) unexpected - manifest unknown
    at /home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/docker-modem/lib/modem.js:336:17
    at IncomingMessage.<anonymous> (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/docker-modem/lib/modem.js:363:9)
    at IncomingMessage.emit (node:events:530:35)
    at endReadableNT (node:internal/streams/readable:1698:12)
    at processTicksAndRejections (node:internal/process/task_queues:90:21) {
  reason: undefined,
  statusCode: 404,
  json: null
}
2026-07-19T10:53:49+0200 <debug> errorMiddleware.js:26 (errorMiddleware) BadParameters [Error]: UNABLE_TO_PULL_IMAGE: image may not exist or may not be available for your architecture
    at ExternalIntegration.update (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/lib/external-integration/externalIntegration.update.js:44:11)
    at processTicksAndRejections (node:internal/process/task_queues:105:5)
    at update (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/api/controllers/externalIntegration.controller.js:97:25)
From previous event:
    at /home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/api/middlewares/asyncMiddleware.js:4:18
    at Layer.handle [as handle_request] (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/express/lib/router/route.js:144:13)
    at adminMiddleware (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/api/middlewares/adminMiddleware.js:6:5)
    at Layer.handle [as handle_request] (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/express/lib/router/route.js:144:13)
    at /home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/api/middlewares/authMiddleware.js:28:7

```

Mais peut-être dû au fait qu’on le fasse tourner pour les essais hors docker ?

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 19, 2026, 12:33 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/43 "2026-07-19T12:33:18Z")

</div>

J’aurais une autre question, pour les sonnettes Tuya, nous sommes en train de bosser avec @GBoulvin :  
En creusant le SDK on a réalisé que **Pulsar lui-même n’est pas bloquant** : le container peut ouvrir la connexion temps réel Tuya et pousser les événements (dont l’appui sonnette) via `publishState`. Le vrai manque côté sonnette, c’est **la publication d’une image de caméra** depuis une intégration externe — le SDK ne gère aujourd’hui que number/text/état passé, pas l’équivalent de `camera.setImage`. J’ai préparé une PR en ce sens sur le SDK (enfin j’espère que c’est bien ce que tu souhaites que l’on fasse sur les choses qui peuvent etre manquante à l’heure actuelle 😅)

Et pour le Tuya **local** (super complémentaire du cloud), deux briques nous aideraient — je vois qu’elles recoupent tes #2680 et #2677 :

1. l’ **accès au réseau local** depuis le container (pour joindre les appareils en 192.168.x) ;
2. la possibilité d’ **exposer/éditer des `params` d’appareil** (IP, protocole, bascule cloud/local) et de **déclencher une action sur un appareil** avec retour de résultat (ex. une « lecture locale des DP » — une opération qu’un utilisateur non initié ne devinera jamais, d’où l’intérêt d’un bouton dédié).

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 19, 2026, 12:36 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/44 "2026-07-19T12:36:03Z")

</div>

Et sinon :

- côté Zendure, tout est maintenant fonctionnel pour cette V1 🥳 Prêt à la proposer.  
On a même créé les issues pour avancer et se donner une roadmap d’implémentation 😍
- côté Tuya, on est presque au bout !! Le local fonctionne pour les appareils trouvés en UDP (3 appareils / 10). Les commandes passent en local ET en cloud. Reste le retour d’état via cloud qui ne passe pas 😅

**EDIT** : J’ai lancé la release gladys-zendure + ajouté le topic, rien d’autre à faire ?

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/b/0/b0be807977509613d1630e6db2716ec369c91df9.png)

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 19, 2026, 1:43 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/45 "2026-07-19T13:43:24Z")

</div>

Et une remarque de Claude après qu’on est rencontré des soucis de poll sur les 2 intégrations Zendure et Tuya, je ne sais pas si il a raison, mais ça semble avoir résolu le souci côté Zendure :

Salut Pierre-Gilles,

En finalisant ma première intégration externe (gladys-zendure), j’ai buté sur  
le `poll_frequency` des appareils, et en comparant avec tes autres intégrations  
je crois avoir trouvé une incohérence dans le template qui vaut le coup d’être  
remontée.

Le constat : le `poll_frequency` de l’OBJET device (celui du payload de  
`publishDiscoveredDevices`) est validé strictement par le core des intégrations  
externes — il doit être une valeur de `DEVICE_POLL_FREQUENCIES`, EN  
MILLISECONDES (1000/2000/10000/15000/30000/60000), et l’appareil doit porter  
`should_poll: true` pour être pollé. Sinon : 422 «&nbsp;invalid poll frequency&nbsp;»  
(ou pas de polling du tout si `should_poll` manque).

C’est exactement ce que fait gladys-melcloud, et c’est correct :  
poll\_frequency: POLL\_FREQUENCY, // = 10 \* 1000 ms  
should\_poll: true,

Mais le template integration-template-js, lui, est incohérent avec ce contrat :

- ses devices de démo font `poll_frequency: config.poll_frequency`
- avec un défaut `poll_frequency: 300` dans config.js (donc 300, interprété  
comme des secondes… mais passé tel quel comme fréquence device)
- et ils ne mettent pas `should_poll`.  
Donc si on installe le template tel quel et qu’on crée/polle un device de démo,  
le core le rejette (300 n’est pas une valeur de DEVICE\_POLL\_FREQUENCIES en ms)  
ou ne le polle jamais (should\_poll absent).

La confusion vient surtout du fait qu’il y a DEUX «&nbsp;poll\_frequency&nbsp;» homonymes :

1. le champ config\_schema du manifeste = une simple valeur de formulaire  
(secondes, choisie par l’intégrateur, sans lien automatique avec le polling) ;
2. le champ poll\_frequency de l’objet device = contraint à  
DEVICE\_POLL\_FREQUENCIES (ms) par le core.  
Le template les relie en passant (1) directement dans (2), ce qui ne peut pas  
marcher.

Trois pistes, au choix :

- corriger le template pour qu’il soit fonctionnel «&nbsp;out of the box&nbsp;» : soit  
hardcoder une valeur ms valide + should\_poll: true (comme melcloud), soit  
faire le snap secondes→ms comme j’ai dû le faire dans zendure ;
- ou rendre le core plus tolérant : accepter des secondes et faire le snap  
côté serveur ;
- ou au minimum documenter que le poll\_frequency du payload device est  
contraint à DEVICE\_POLL\_FREQUENCIES (ms) et nécessite should\_poll: true.

Pour info, côté zendure j’ai un petit helper qui snappe la valeur config  
(secondes, 10–3600) vers la valeur ms autorisée la plus proche — je peux le  
partager si ça t’intéresse pour le template.

Rien de bloquant pour moi (zendure fonctionne), c’est juste un retour de  
première expérience qui pourra éviter le même piège aux prochains.

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 19, 2026, 3:10 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/46 "2026-07-19T15:10:44Z")

</div>

Egalement :

Retour sur le framework external-integration (en testant gladys-tuya en conditions réelles).

Constat : quand une intégration externe republie un appareil déjà créé via  
publishDiscoveredDevices (même external\_id) avec des params mis à jour, les  
params de l’appareil existant ne sont PAS mis à jour côté Gladys, et aucune  
option « Mettre à jour » n’apparaît dans l’écran de découverte pour les  
intégrations externes (contrairement aux services natifs).

Cas d’usage concret : un appareil Tuya est créé en mode cloud. Plus tard,  
l’utilisateur active le mode local (l’intégration redécouvre l’appareil avec  
ip / local\_key / protocol\_version / local\_override après un scan LAN). Mais  
l’appareil déjà créé conserve ses anciens params : impossible de basculer en  
local sans le supprimer puis le recréer.

Questions :

- Est-ce voulu / prévu ? Un re-publish d’un device découvert existant  
devrait-il faire un upsert des params (par external\_id) ?
- Ou l’écran de découverte des intégrations externes pourrait-il exposer une  
action « Mettre à jour » (comme les services natifs le font sur leur page  
d’appareil) pour ré-appliquer les params issus d’une nouvelle découverte ?

Pour l’instant le contournement utilisateur est « supprimer + recréer »  
l’appareil, ce qui est peu ergonomique dès qu’un paramètre local change  
(IP, clé locale rotée, passage cloud→local).

Merci !

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 19, 2026, 3:24 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/47 "2026-07-19T15:24:26Z")

</div>

> [@Terdious](#):
>
> - côté Zendure, tout est maintenant fonctionnel pour cette V1 🥳 Prêt à la proposer.  
> On a même créé les issues pour avancer et se donner une roadmap d’implémentation 😍

Je viens d’implémenter 4 types d’appareils supplémentaire + la gestion en mqtt local en 35 minutes !!! C’est bluffant !!

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Juillet 19, 2026, 3:55 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/48 "2026-07-19T15:55:01Z")

</div>

> [@Terdious](#):
>
> De ce qu’on voit il se porte sur le numéro de version dans le nom de l’image ?

Ah bizarre, je vais regarder, effectivement il faudrait qu’il pull «&nbsp;dev&nbsp;» dans ce cas

> [@Terdious](#):
>
> le SDK ne gère aujourd’hui que number/text/état passé, pas l’équivalent de `camera.setImage`. J’ai préparé une PR en ce sens sur le SDK (enfin j’espère que c’est bien ce que tu souhaites que l’on fasse sur les choses qui peuvent etre manquante à l’heure actuelle 😅)

Ah bien, merci ! En général je faisais dans le sens :

Modification Spec → Modification Gladys → Modification SDK → Modification template

Comme ça tout reste cohérent, mais je vais regarder ta PR 🙂

> [@Terdious](#):
>
> 1. l’ **accès au réseau local** depuis le container (pour joindre les appareils en 192.168.x) ;

Ok je vais voir avec Claude

> [@Terdious](#):
>
> 1. la possibilité d’ **exposer/éditer des `params` d’appareil**

C’est pas le cas ça ? Tu peux pas exposer params dans `publishDiscoveredDevices` ?

> [@Terdious](#):
>
> 1. **déclencher une action sur un appareil** avec retour de résultat (ex. une « lecture locale des DP » — une opération qu’un utilisateur non initié ne devinera jamais, d’où l’intérêt d’un bouton dédié

Tu peux préciser cette partie ? Notamment «&nbsp;DP&nbsp;» je ne sais pas ce que ça veut dire 😅

> [@Terdious](#):
>
> - côté Zendure, tout est maintenant fonctionnel pour cette V1 🥳 Prêt à la proposer.  
> On a même créé les issues pour avancer et se donner une roadmap d’implémentation 😍

Excellent !!

> [@Terdious](#):
>
> **EDIT** : J’ai lancé la release gladys-zendure + ajouté le topic, rien d’autre à faire ?

Tu peux voir l’état de ta release sur cette URL :

- Les intégrations listées : [https://integration-store-storage.gladysassistant.com/index.json](https://integration-store-storage.gladysassistant.com/index.json)
- Les intégrations rejetées : [https://integration-store-storage.gladysassistant.com/rejected.json](https://integration-store-storage.gladysassistant.com/rejected.json)

Après, dans ton cas tu te bases sur une version du SDK qui n’est pas encore mergé donc je pense que le store va rejeter car le manifest est pas valide pour lui (normal, il faut attendre que je merge la PR)

> [@Terdious](#):
>
> Mais le template integration-template-js, lui, est incohérent avec ce contrat :

Bien vu, c’est une erreur côté template, je vais coriger ça !!

> [@Terdious](#):
>
> Je viens d’implémenter 4 types d’appareils supplémentaire + la gestion en mqtt local en 35 minutes !!! C’est bluffant !!

Incroyable !! J’ai hâte de mettre tout ça en prod 😁

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 20, 2026, 7:18 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/49 "2026-07-20T07:18:35Z")

</div>

Salut @pierre-gilles , et merci pour tes retours

1. Bouton « Mettre à jour » / version d’image  
Oui, c’est bien ça : le bouton tente de pull la version figée du manifest (ex. :1.0.0) au lieu de **«&nbsp;:dev&nbsp;»**. Pour l’itération en dev, pull « dev » serait parfait. Penser au fait qu’une image dev de PR puisse se nommer avec un tag allonger comme **«&nbsp;:dev-test-mqtt-local&nbsp;»** et l’inscrire dans la spec pour imposer les tags d’image de dev.

2. « Exposer/éditer des params d’appareil » — je précise  
Exposer les params à la découverte : OK, ça marche, je le fais déjà dans publishDiscoveredDevices (ip, local\_key, protocol\_version, local\_override…).  
Le manque n’est pas là : c’est la MISE À JOUR des params d’un appareil DÉJÀ CRÉÉ. Quand je republie un device découvert (même external\_id) avec des params qui ont changé — typiquement l’IP LAN qui bouge en DHCP, ou un passage cloud→local après un nouveau scan — les params de l’appareil existant ne sont pas ré-appliqués, et l’utilisateur n’a aucun moyen de les éditer/rafraîchir.  
Aujourd’hui le seul contournement est supprimer + recréer l’appareil.  
→ Besoin : soit un upsert des params sur re-publish (par external\_id), soit une action « Mettre à jour » dans l’écran de découverte des intégrations externes

3. « DP » et « action avec retour de résultat »  
DP = Data Point (terminologie Tuya). Chaque appareil Tuya expose des datapoints numérotés (DP 1 = interrupteur, DP 20 = luminosité, etc.) ; l’état complet = la « DPS map ». La « lecture locale des DP » consiste à lire cette map EN DIRECT sur le LAN via le protocole local Tuya. Deux usages :

- valider que la connexion locale + la version de protocole fonctionnent  
AVANT d’activer le mode local (sinon on active un local qui timeout) ;
- découvrir/confirmer le mapping DP→feature.

C’est une action déclenchée par l’utilisateur, AVEC un résultat renvoyé à l’UI (les DP lus, ou l’erreur). Le besoin générique pour les intégrations externes : pouvoir exposer une action utilisateur « exécute cette opération et montre-moi le résultat » (test de connexion locale, lecture DP, ré-appairage, identify…), puisqu’on n’a pas d’UI custom. Le SDK ne gère aujourd’hui que le push d’états et poll/setValue — pas ce type d’action requête/réponse à la demande.  
On ne peut déclencher cette recherche de version de protocol et DP que si on connait l’IP, et si l’UDP ne l’as pas trouvé, on doit pouvoir renseigner l’IP manuellement pour lancer cette recherche automatique (il scan en tentant de lancer des poll pour chaque version) - Et c’est une opération assez longue - jusqu’à 15s je crois - pour éviter de spam l’appareil.

## Autre retours :

- Par erreur, j’ai pu installer un 2ème container dev alors que je n’avais pas désinstaller l’ancien. Aucune erreur, il s’est installer en **«&nbsp;-2&nbsp;»**. A l’installation on devrait être averti et que ce soit impossible d’installer 2 images identiques (par contre on devrait pouvoir installer un prod et un dev comme actuellement)  
 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/2/6/26aaa3ee26305df21e8f3bf97b50e9e2d75f81a4.png)

- Installer un container avec tag **«&nbsp;:dev&nbsp;»** (ou tag **«&nbsp;:dev-xxxxxx&nbsp;»** ) devrait afficher une alerte de prévention : si une instance prod tourne à côté cela peut impacter/casser l’autre instance, conseiller d’arreter le container prod avant installation du tag «&nbsp;:dev&nbsp;» - par contre une très bonne chose de pouvoir installer une dev et une prod cote à cote

- Afficher dans la page de configuration l’heure de démarrage du container

- Lorsqu’un container externe est arrêté, il faudrait arrêter le polling (et tout autre tentative d’échange si c’est le cas), pour la pollution de logs :

```auto
2026-07-20T07:43:19+0200 <error> device.poll.js:23 (DeviceManager.poll) There was an error while polling device ambiance-salon
2026-07-20T07:43:19+0200 <error> device.poll.js:24 (DeviceManager.poll) ExternalIntegrationUnavailableError: EXTERNAL_INTEGRATION_NOT_CONNECTED
    at ExternalIntegration.sendCommand (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/lib/external-integration/externalIntegration.sendCommand.js:23:11)
    at Object.poll (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/lib/external-integration/externalIntegration.registerProxyService.js:42:20)
    at DeviceManager.poll (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/lib/device/device.poll.js:21:26)
    at Promise.map.concurrency (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/lib/device/device.pollAll.js:13:87)
    at tryCatcher (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/bluebird/js/release/util.js:16:23)
    at MappingPromiseArray._promiseFulfilled (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/bluebird/js/release/map.js:68:38)
    at MappingPromiseArray.PromiseArray._iterate (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/bluebird/js/release/promise_array.js:115:31)
    at MappingPromiseArray.init (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/bluebird/js/release/promise_array.js:79:10)
    at MappingPromiseArray._asyncInit (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/bluebird/js/release/map.js:37:10)
    at _drainQueueStep (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/bluebird/js/release/async.js:97:12)
    at _drainQueue (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/bluebird/js/release/async.js:86:9)
    at Async._drainQueues (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/bluebird/js/release/async.js:102:5)
    at Immediate.Async.drainQueues (/home/gladys/GladysDev/gladys-external-integration-test/Gladys/server/node_modules/bluebird/js/release/async.js:15:14)
    at processImmediate (node:internal/timers:491:21)

```

- Lorsqu’une intégration peut etre cloud et local avec des appareils qui peuvent être local ou cloud, on devrait imposé une spec :
  - Global Intégration en local ou en cloud =\> un interrupteur «&nbsp;Mode local&nbsp;» qui privilégie pour tous les appareils le local si coché, fallback par appareil en cloud si pas de local ou cassé ; sinon 100% cloud  
 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/3/a/3a6d561f4e8755c8b4c59e9aa2ddda29a0457a84.png)
  - un macaron global sur la vue Appareil qui spécifie si l’application est définie en local ou en cloud
  - un macaron par appareil qui spécifie si l’appareil est en local ou en cloud.  
On a vraiment besoin de ça pour Tuya par exemple. Et je rencontre le meme cas sur Zendure (les tests pendant l’implémentation du mqtt local sur zendure m’ont permis de me rendre compte que j’avais 2 appareils qui n’avaient pas le mqtt local activé, j’ai galéré 30 minutes, un macaron visible m’aurait fait comprendre et passer au vrai diag rapidement).  
Ensuite la documentation de l’integration externe pourra comporter une section «&nbsp;FAQ&nbsp;» ou d’aide aux recherches/résolutions de problèmes

- D’ailleurs côté documentation ? Je n’ai pas cherché dans tes specs, mais as-tu prévu de l’imposer pour valider une intégration ?  
Ce serait bien de définir par exemple (comme HA), un format de fond de page et les chapitres principaux à imposer - avec un template comme pour le container. Possible ?

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Juillet 20, 2026, 7:53 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/50 "2026-07-20T07:53:05Z")

</div>

Salut @Terdious ce sont de très bons retours 🙂

J’ai adapté la spec et l’implémentation va suivre :

Les sept retours sont intégrés, avec pour chacun la décision de design qui va avec :

**1. Params après création — les deux mécanismes demandés, avec une frontière nette.** Les `params` sont la _donnée technique de l’intégration_ : sur re-publication d’un device déjà créé (même `external_id`), le superviseur les **upsert silencieusement** (l’IP DHCP qui bouge, le passage cloud→local), sans écho `device-updated` vers l’intégration (sinon boucle : republier → événement → republier). Le `name`, la pièce et les features restent propriété de l’utilisateur : si la _structure_ publiée diffère, l’écran Découverte affiche un bouton « **Mettre à jour** » — geste utilisateur via le `POST /api/v1/device` standard. Fini le supprimer/recréer.

**2. Boutons d’actions — nouveau champ `actions` du manifeste** (max 10) : `key`, label/description multi-langues, et surtout deux choses dimensionnées sur le cas Tuya : un **`fields` optionnel au format exact du `config_schema`** (le mini-formulaire « saisir l’IP » est rendu par le même moteur, validé pareil) et un **`timeout_seconds` par action (5–120, défaut 30)** qui remplace la règle des 5 s pour `action.run` — le scan de versions de protocole à ~15 s passe. Chaîne complète : bouton → `POST .../action/:key` → WS `action.run` → résultat dans `command-result.data.message` (string ou multi-langue) affiché sous le bouton. SDK : `onAction('detect_protocol', async (fields) => '...')`.

**3. Double instance dev/prod** : à l’installation (tous modes), si une intégration installée partage la même image _sans le tag_ (`:dev` à côté de `:1.2.0`) ou le même `name` de manifeste → avertissement explicite (conflit possible sur le même compte cloud / les mêmes appareils, conseil d’arrêter l’autre instance pendant les tests), mais **l’installation reste possible** — dev à côté de prod est un usage voulu, les selectors `ext-dev-*` garantissent l’absence de collision technique.

**4. Heure de démarrage** : `started_at` du conteneur principal (et de chaque sous-conteneur) dans le détail admin, affiché dans le bloc de supervision (« en fonctionnement depuis… »).

**5. Poll d’une intégration arrêtée** : le `poll` planifié devient un **no-op silencieux** quand l’intégration n’est pas `RUNNING`/`DEGRADED` — ni throw ni ligne de log toutes les N secondes pour un état déjà connu. `setValue` continue de throw : l’utilisateur qui actionne doit voir l’erreur.

**6. Types de champs** : `boolean` existait déjà (rendu interrupteur/case à cocher — précisé) ; ajout de **`multi_select`** (cases à cocher, valeur = array) et de **`display: "radio"`** sur les `select`.

**7. Documentation obligatoire sur le store** : publier exige désormais [`docs/en.md`](https://github.com/gladysassistant/gladys/blob/claude/focused-turing-q9vf41/docs/en.md) **et** [`docs/fr.md`](https://github.com/gladysassistant/gladys/blob/claude/focused-turing-q9vf41/docs/fr.md), structurés selon le template livré dans le repo template (Présentation / Prérequis / Configuration / Dépannage). L’indexeur vérifie présence + taille minimale (rejet `error` sinon), **re-héberge** les fichiers sur Pages comme les covers (`docs` dans `index.json`), et l’écran d’installation gagne un lien « Documentation » (langue utilisateur, fallback `en`).

> [@Terdious](#):
>
> - Lorsqu’une intégration peut etre cloud et local avec des appareils qui peuvent être local ou cloud, on devrait imposé une spec :

Je trouve que c’est un peu trop spécifique à ce que tu fais là, je préfère du générique 🙂

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 20, 2026, 7:53 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/51 "2026-07-20T07:53:19Z")

</div>

> [@pierre-gilles](#):
>
> Tu peux voir l’état de ta release sur cette URL :
> 
> - Les intégrations listées : [https://integration-store-storage.gladysassistant.com/index.json](https://integration-store-storage.gladysassistant.com/index.json)
> - Les intégrations rejetées : [https://integration-store-storage.gladysassistant.com/rejected.json](https://integration-store-storage.gladysassistant.com/rejected.json)
> 
> Après, dans ton cas tu te bases sur une version du SDK qui n’est pas encore mergé donc je pense que le store va rejeter car le manifest est pas valide pour lui (normal, il faut attendre que je merge la PR)

Alors en effet, Zendure n’est ni dans `https://integration-store-storage.gladysassistant.com/index.json`, ni dans `https://integration-store-storage.gladysassistant.com/rejected.json` ^^  
Par contre gladys-tuya (dont je n’ai pas encore mergé les PR) se retrouve bien dans `https://integration-store-storage.gladysassistant.com/rejected.json` :

```auto
[
  {
    "store_slug": "Terdious/gladys-tuya",
    "level": "error",
    "reason": "docker_image: image is not publicly pullable (registry auth denied, HTTP 403)",
    "checked_at": "2026-07-20T07:24:35.428Z"
  }
]

```

Par contre il va falloir que tu nous fasses une vrai page visuelle hein 🫣 😅

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Juillet 20, 2026, 7:54 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/52 "2026-07-20T07:54:15Z")

</div>

> [@Terdious](#):
>
> Par contre il va falloir que tu nous fasses une vrai page visuelle hein 🫣 😅

Fable 5 nous fera ça, t’inquiète pas 🤣

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Juillet 20, 2026, 7:58 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/53 "2026-07-20T07:58:42Z")

</div>

@Terdious du coup tu faisais des tests depuis la PR [#2680](https://github.com/GladysAssistant/Gladys/pull/2680) ? Tu me confirmes que ça fonctionnait bien ?

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 20, 2026, 8:00 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/54 "2026-07-20T08:00:32Z")

</div>

Ma foi, oui, je dirais parfaitement 🙂

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Juillet 20, 2026, 8:21 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/55 "2026-07-20T08:21:00Z")

</div>

Pour les nouvelles features que tu as demandée, j’ai demandé à GPT 5.6 Sol 1M High de review, et il trouve que c’est trop générique Zendure, et je suis plutôt d’accord avec lui 🙂

La review: [Add solar-battery device feature category - gladys-zendure external integration by Terdious · Pull Request #2682 · GladysAssistant/Gladys · GitHub](https://github.com/GladysAssistant/Gladys/pull/2682#issuecomment-5020150205)

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 20, 2026, 8:26 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/56 "2026-07-20T08:26:47Z")

</div>

Merci Pierre-Gilles, dans l’ensemble c’est tout bon pour moi :

**Merci pour tous les correctifs / implémentations**

> [@pierre-gilles](#):
>
> Je trouve que c’est un peu trop spécifique à ce que tu fais là, je préfère du générique 🙂

Un seul point où je pousse un peu — le « trop spécifique / plutôt générique » sur  
le mode local/cloud + macarons :

Je pense que c’est justement un besoin GÉNÉRIQUE, pas propre à Tuya. Le motif  
récurrent = « une intégration qui couvre cloud ET local, avec des appareils dont  
le transport effectif peut différer d’un appareil à l’autre et évoluer dans le  
temps ». Exemple au pied levé :

| Intégration | Dualité cloud/local | Statut |
| --- | --- | --- |
| Tuya | cloud + LAN par appareil | dans Gladys (→ externe) |
| Netatmo | météo = full cloud ; caméras/sonnette = cloud + local (local bien plus rapide sur l’image, plus fiable car le lien cloud saute) | dans Gladys, en cours de passage externe |
| Zendure | cloud + MQTT local | externe (le tien) |
| Shelly | HTTP/WS local + Shelly Cloud | convertible / à venir |
| eWeLink / Sonoff | cloud + mode LAN | convertible / à venir |
| Somfy TaHoma | cloud + API locale | convertible / à venir |

La brique à mettre dans le framework, ce n’est pas la logique Tuya,  
c’est :

1. un STATUT DE TRANSPORT PAR APPAREIL, standard et agnostique  
(local / cloud / injoignable), que l’intégration remonte et que Gladys  
affiche en macaron — + un macaron global sur la vue Appareils ;
2. optionnellement une PRÉFÉRENCE DE CONNEXION standard (« privilégier le local  
quand disponible, cloud sinon ») — c’est exactement le libellé de ton toggle  
« Mode local (LAN) ».  
L’intégration remplit, Gladys rend → 100 % générique, zéro sémantique Tuya  
dans le core.

La valeur est surtout diagnostique et universelle : sans macaron visible,  
l’utilisateur ne peut pas savoir pourquoi un appareil est lent ou figé. Mon  
propre cas Zendure (2 appareils sans MQTT local, 30 min perdues) : un macaron  
m’aurait mis sur la piste tout de suite.

Et ce n’est pas qu’une intégration, la même logique est valable pour tous les appareils du tableau ci-dessus. L’autre jour tu me parlais de Shelly, c’est pareil, il faut activer le mqtt sur l’interface web local http pour avoir le MQTT local et/ou le cloud. Le  
motif revient dès qu’un fabricant offre les deux canaux — d’où l’intérêt d’une  
primitive « transport status + preference » réutilisable plutôt qu’un traitement  
par intégration.

En plus c’est assez simple à mettre en oeuvre côté Gladys core : Un toggle défini coté configuration (qui serait le meme pour tous) et un param côté device (idem défini en spec). Ensuite c’est de la tambouille interne au container !

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Juillet 20, 2026, 8:36 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/57 "2026-07-20T08:36:56Z")

</div>

Ok merci pour l’explication, c’est bon pour moi j’ai adapté la spec !

Je suis entrain de voir avec Claude pour l’accès au réseau local

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Juillet 20, 2026, 8:38 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/58 "2026-07-20T08:38:59Z")

</div>

Pour l’accès local normalement c’est déjà possible, tu es sûr que ça te bloquait ?

Mon avis : **c’est déjà possible dans le design — et c’est important de ne pas « réparer » ce qui n’est pas cassé**. Le bridge NAT ne bloque pas l’unicast sortant vers le LAN : un conteneur sur `gladys-integrations` peut ouvrir une connexion TCP/UDP vers `192.168.1.50` (le protocole local Tuya port 6668, l’API HTTP locale Shelly…) exactement comme il joint un cloud — Docker masquerade la sortie, rien n’est filtré. `enable_icc=false` n’isole que les conteneurs _entre eux_ sur le bridge, pas le trafic vers l’extérieur. La seule vraie limite, déjà documentée en B.2/B.16, c’est la **réception** de broadcast/multicast (le scan UDP de découverte) — et je soupçonne que c’est la source du malentendu : «&nbsp;pas de broadcast&nbsp;» a été lu comme «&nbsp;pas de LAN&nbsp;». S’il a _réellement_ constaté un échec unicast dans son environnement de dev, la cause est extérieure au framework — le cas classique étant un pare-feu hôte strict (ufw) qui DROP le FORWARD bridge→interface LAN : symptôme exact « cloud OK, LAN KO ».

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Juillet 20, 2026, 8:58 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/59 "2026-07-20T08:58:10Z")

</div>

Je revérifie si ce n’est pas lui (et moi qui a mal guidé…) qui a mal fait !! Si c’est ça désolé du dérangement.

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Juillet 20, 2026, 8:59 UTC](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343/60 "2026-07-20T08:59:16Z")

</div>

SDK en version 0.4.0 publié, Claude adapte le template-js, et je suis entrain de faire les merge Gladys vers la PR de base

Edit: merge effectué, tout est dans cette PR maintenant: [External integrations (RFC phase 1): Docker supervisor, host API, integration WebSocket, decentralized store and generic frontend by Pierre-Gilles · Pull Request #2665 · GladysAssistant/Gladys · GitHub](https://github.com/GladysAssistant/Gladys/pull/2665)

[Page précédente](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343.md?page=2)

[Page suivante](https://community.gladysassistant.com/t/integrations-externes-dans-gladys-assistant/10343.md?page=4)
