Gladys et Domoticz (Encore)

Bonjour

J’ai un petit serveur Domoticz qui tourne et je trouve le concept de Gladys plutôt intéressant.

J’ai lu avec attention plusieurs articles sur ce forum sur Gladys vs Domoticz, et j’ai l’impression que la conclusion à chaque fois était que Gladys remplace Domoticz, si on veut de nouveau périphériques il faut ajouter le support.

Je suis assez surpris de cette stratégie, et je verrai de nombreux avantages à les faire cohabiter:

  • Le point fort de Gladys me semble le front-end, qui discute nativement avec des protocoles haut-niveau (Wifi, Http, etc).
  • A l’inverse, Domoticz a une interface fonctionnelle mais assez basique, par contre son énorme point fort c’est la compatibilité avec des centaines de périphériques, de prototocoles très variés (RXLink, RFXCom, EnOcean, Zigbee, …), qui ont certainement demandé des années de travail.

Domoticz a une API qui est très claire, bien documentée, qui permet même de lister et controller les périphériques:

Je pense que Gladys aurait tout intérêt à ajouter cette compatibilité, qui rajouterait de base des centaines de devices. Rien n’empêche pas la suite de mettre les plus demandés en natif sur Gladys.

Je programme beaucoup, essentiellement en Python mais avec quelques bases en JS, avec quelques pistes de départ je pourrais sans doute proposer un prototype si rien n’existe déjà.

Cédric

Salut, perso je trouve l’idée intéressante :slight_smile:

Il est clair que ce serait intéressant car actuellement je ne peux utiliser totalement mes périphériques RF433 et Z-Wave qu’avec Domoticz, que j’ai remis en route pour gérer mes modules Z-Wave Qubino de chauffage.
Du coup, Gladys ne me sert pas à grand chose, à part voir ma caméra.

Je suis tout à fait d’accord !

SI tu veux nous aider, ce serait avec grand plaisir.

Je pense d’ailleurs qu’une telle compatibilité demande plus de réflexion que de code, la première étape est donc plus de la spécification fonctionnelle et technique que se lancer dans du développement :slight_smile:

A mon avis, pour une 1ère intégration, on devrait :

  • Faire une interface pour configurer l’intégration avec l’URL du serveur Domoticz + la clé d’API.
  • Faire en sorte que Gladys se connecte à Domoticz via l’API, récupère la liste des périphériques dans Domoticz, et propose à l’utilisateur d’ajouter manuellement ces appareils à Gladys. Ne proposer que les types appareils que Gladys gère pour pas que l’utilisateur se retrouve avec des périphériques inutiles.

Rien qu’avec ça, ça ajouterait effectivement pas mal de périphériques et le développement ne me semble pas si long !

La next step à mon avis si tu veux nous aider, c’est de décortiquer l’API Domoticz, et faire le mapping entre leur format de donnée (à quoi ressemble leur device niveau modélisation DB? ) et nos données dans Gladys 4.

Niveau modélisation, la DB de Gladys est définie ici :

Chaque fichier = une entitée.

Ici ce qui t’intéresse c’est le duo Device -> DeviceFeature.

Si tu as des questions là dessus, n’hésite pas .

Je suis d’accord aussi.

Pour le front-end je pense qu’il y a besoin:

  • D’une page de configuration qui demande username/password (Avec une case à cocher car optionnel), adresse IP, port, SSH ou pas (Optionnel pour le moment s’ils tournent sur la même machine).
  • D’une page pour ajouter les devices en fonction de la liste disponible (Filtre selon ceux disponibles).

J’ai commencé à regarder les fichiers sources pour le front-end. Je ne suis pas habitué à Node.js et React donc pour le moment c’est assez compliqué. Si j’ai bien compris, au moins pour le front-end, il faudrait:

  • Ajouter une clé avec image dans front/src/config/integrations/devices.json (domoticz)
  • Mettre les strings dans front/src/config/{en,fr}.json
  • Créer un répertoire front/src/routes/integration/all/domoticz avec au minimum un fichier DomoticzPage.js, puis des pages avec actions
  • Importer et ajouter les routes des pages dans src/components/app.jsx

J’ai pu lancer en mode dev le front-end et back-end pour tester sur mon PC.

Au niveau de la DB, si je comprends bien cette page et le source code:

  • Un service (Domoticz) peut proposer plusieurs devices, qui sont liés à une Room
  • Un device a un UUID et un nom (Thermomètre 1). Par contre je n’ai pas compris à quoi sert “selector”. Je pense qu’external_id on peut s’en servir pour construire la requete vers Domoticz?
  • Un device peut avoir plusieurs Features. Par exemple un thermomètre peut avoir des categories TEMPERATURE_SENSOR, HUMIDITY_SENSOR, BATTERY, qui ont tous un Type, typiquement SENSOR et BATTERY.

Et donc pour le server il faudrait créer:

  • Un répertoire server/services/domoticz, à l’intérieur au moins des fonctions start/stop, qui vérifient la configuration, et un fichier package.json
  • Un fichier server/services/domoticz/api/domoticz.controller.js qui liste les differentes fonctions d’API.
  • Un fichier server/services/domoticz/lib/index.js qui contient un DomoticzManager

Par contre je ne sais pas trop quels events doivent etre supportés et quelles commandes, ou comment c’est lié au front-end. Je pense que comme commandes il y a besoin:

  • De pouvoir lister les devices disponibles et pas encore activés
  • De pouvoir ajouter des devices
  • D’avoir un event en cas de mise à jour de l’utilisateur (Switch par exemple) ou sur polling.

Cédric

Une question additionnelle: j’ai trouvé la doc sur l’API (https://apidoc.gladysassistant.com/) par contre je ne sais pas comment l’utiliser avec curl par exemple. Il doit manquer une authentification, car j’ai à chaque fois:

No authorization header or api key found

Mais quelles sont les étapes pour s’authentifier sans front-end?

Ou plus généralement, est-ce possible de tester la partie server sans le front-end?

J’ai trouvé, il me manquait le login et la clé de session dans les headers suivants.

Tu as plutôt tout compris niveau front et back ! :smiley:

Le selector c’est unique id “human readable”, en général on le génère automatiquement à partir du nom en faisant un slug du nom. ça permet que l’API et les logs soit plus lisible, un UUID tu sais pas ce que c’est, par contre “lampe-bureau-salon” c’est plus lisible :wink:

Le external_id c’est l’ID de la ressource distance. Donc effectivement, ici l’external_id ça serait l’ID du device côté Domoticz.

En fait pour l’instant l’API de Gladys Assistant n’est que réservé au front, donc il faut un token du front que tu obtiens lors du login. Attention, ce token a une duré de vie limitée.

On a pour projet d’avoir un moyen de générer des tokens d’API “long-lived” pour pouvoir appeler l’API de Gladys en externe, mais bon c’est pas encore développé.

Bon il semble que je n’ai pas compris quelque chose. J’ai testé de mettre en place l’API de base dans le serveur avec une seule fonction mais j’ai cette erreur que je ne comprends pas:

2020-11-11T22:29:14+0100 <trace> errorMiddleware.js:49 (errorMiddleware) TypeError: domoticzManager.getVersion is not a function
  at getVersion (/docs/Cedric/Programmation/Node.js/gladys/server/services/domoticz/api/domoticz.controller.js:11:37)
  at /docs/Cedric/Programmation/Node.js/gladys/server/api/middlewares/asyncMiddleware.js:4:19
From previous event:
  at /docs/Cedric/Programmation/Node.js/gladys/server/api/middlewares/asyncMiddleware.js:4:11
  at Layer.handle [as handle_request] (/docs/Cedric/Programmation/Node.js/gladys/server/node_modules/express/lib/router/layer.js:95:5)
  at next (/docs/Cedric/Programmation/Node.js/gladys/server/node_modules/express/lib/router/route.js:137:13)
  at /docs/Cedric/Programmation/Node.js/gladys/server/api/middlewares/authMiddleware.js:28:7

J’ai un fichier services/domoticz/lib/commands/domoticz.getVersion.js qui contient:

const logger = require('../../../../utils/logger');
function getVersion() {
    logger.debug('Domoticz: getVersion');
}

module.exports = {
    getVersion,
}

Dans le fichier services/domoticz/lib/index.js il y a:

// Commands
const { getVersion } = require('./commands/domoticz.getVersion');

const DomoticzManager = function DomoticzManager(eventManager, serviceId) {
  this.eventManager = eventManager;
  this.serviceId = serviceId;

  // TODO
  const server = 'http://192.168.1.39';
  const port = 8080;

  this.client = axios.create({
    baseURL: `${server}:${port}/`,
    timeout: 2000,
  });
}

// Commands
DomoticzManager.prototype.getVersion = getVersion;

module.exports = DomoticzManager;

Et enfin le fichier services/domoticz/api/domoticz.controller.js:

const asyncMiddleware = require('../../../api/middlewares/asyncMiddleware');
const { ServiceNotConfiguredError } = require('../../../utils/coreErrors');

module.exports = function DomoticzController(gladys, domoticzManager, serviceId) {
  /**
   * @api {get} /api/v1/service/domoticz/status Get Domoticz status
   * @apiName getStatus
   * @apiGroup Domoticz
   */
  async function getVersion(req, res) {
    const version = domoticzManager.getVersion();
    res.json({
      build_time: version['build_time'],
      version: version['version'],
    });
  }

  return {
    'get /api/v1/service/domoticz/version': {
      authenticated: true,
      controller: asyncMiddleware(getVersion),
    },
  }
}

C’est initialisé dans le fichier services/domoticz/index.js:

const logger = require('../../utils/logger');
const DomoticzManager = require('./lib');
const DomoticzController = require('./api/domoticz.controller');
const { ServiceNotConfiguredError } = require('../../utils/coreErrors');

module.exports = function DomoticzService(gladys, serviceId) {
    const domoticzManager = new DomoticzManager(gladys.events, serviceId);

    /**
     * @public
     * @description This function starts the service
     * @example
     * gladys.services.domoticz.start();
     */
    async function start() {
        logger.info('Starting Domoticz service');
    }

    /**
     * @public
     * @description This function stops the service
     * @example
     * gladys.services.domoticz.stop();
     */
    async function stop() {
        logger.info('Stopping Domoticz service');
    }

    return Object.freeze({
        start,
        stop,
        device: domoticzManager,
        controllers: DomoticzController(domoticzManager, serviceId),
    })
}

Il y a sans doute un concept que je n’ai pas compris mais là j’ai besoin d’aide…

En cherchant un peu mieux, j’ai trouvé. Cétait dans l’instantiation du controlleur qu’il manquait un paramètre…