[NODE-RED] Logitech Hub Harmony

Hub Harmony dans Gladys


Bonjour, je vais essayer de vous faire un petit tutoriel pour intégrer le Hub Harmony qui permet, pour ceux qui ne connaissent pas, de contrôler les appareils hi-fi et vidéo et même un peu de domotique (Pas très utile comme on utilise Gladys pour centraliser).

Ce Hub permet de lancer une combinaison de commandes selon des séquences ou activités pré-enregistrées par l’utilisateur et c’est cela que nous allons intégrer.

J’ai fait le choix d’utiliser Node-Red pour sa flexibilité et je m’appuierai donc dessus tout au long de ce tuto.

Sommaire


  1. Prérequis
  2. Installation du Node
  3. Activités du Hub
  4. Changement de chaîne
  5. Volume de l’ampli

1. Prérequis


Il ne faut pas grand-chose mais il les faut quand même :wink:

Installation des prérequis


1.1 Installation Gladys

Pour Gladys, normalement ça devrait être facile.

1.2 Installation Mqtt

Passons à Mqtt. Là, non plus ce n’est pas trop compliqué.
Voici le tuto

1.3 Installation Node-Red

Si c’est une installation toute neuve, Vous pouvez faire les commandes suivantes:

Node-Red

Installation de Node-Red depuis Docker

docker run -d \
–log-opt max-size=10m \
–restart=always \
–privileged \
-u root \
–network=host \
–name node_red \
-u node-red:dialout \
-v /var/lib/node-red:/data \
nodered/node-red

puis celle-ci

sudo chown -R 1000:1000 /var/lib/node-red

2. Installation Node Harmony

Maintenant, nous allons pouvoir aller sur Node-Red.

L’adresse IP du Raspberry ou du nom de domaine de votre machine sur le port 1880
Ex: 192.168.1.XX:1880 ou XX.local:1880

Quand vous êtes arrivés là, faites Ctrl+Maj+P, ou dans l’angle en haut à droite il faudra cliquer sur le menu Manage palette.
Nous arrivons sur la page des nodes déjà installé
Par la suite il faut cliquer sur l’onglet install.
Nous chercherons node-red-contrib-harmony-websocket.
Et bien évidemment l’installer.


3. Intégration des activités

Ne vous inquiétez pas, si je l’ai fait, tout le monde peut le faire.

3.1. Mqtt

Voici un exemple d’une intégration Mqtt dans Gladys. pour le nom de l’activité, ici « tv ». Cela permettra d’identifier plus facilement dans Node-Red.

Faites toutes les activités à la fois :wink:
Retour d’expérience :
Si vous avez des noms d’activités avec des mots identiques, il faut les différencier avec des majuscules car la fonction dans Node-Red qu’on utilisera tient la case.

Et surtout Intégrer-les au tableaux de bord

3.2. Mqtt dans Node-Red

Nous commencerons par intégrer tous les nœuds MQTT dans Node-Red et mettre en route le serveur qui va avec.

Node-Red-mqtt

Je ne l’indique pas, mais pensez à déployer.

3.2.1 Configuration serveur Mqtt dans Node-Red.

Nous ouvrons un des Node pour configurer le serveur comme ci-dessous.

Serveur Mqtt

Nous allons cliquer sur le crayon

Ce sont les identifiants et mots de passe de l’intégration MQTT dans Gladys

3.2.2. Topic Mqtt.

Après la validation du serveur, nous allons mettre dans le topic le lien du topic d’écoute de l’intégration dans Gladys. Évidemment chaque node a un lien différent.

Topic Mqtt

3.3. Configuration du serveur du Node Harmony.

Après tout ça, nous mettrons en place le Node du Hub. C’est à peu près le même principe sauf que là, normalement, il devrait trouver l’adresse IP de celui-ci tout seul comme un grand.
Si tout se passe comme prévu, quand vous validerez la configuration, vous devriez voir, dans le menu déroulant, toutes vos activités que vous avez programmées avec des chiffres.
Ceci représente l’ID de chaque activité. Comme cela est important, nous allons les copier quelque part avec leur nom.

1

Sur l’image ci-dessus, nous voyons ce que le Node nous renvoie quand on l’active manuellement. Donc nous allons l’envoyer de cette façon pour ne pas trop encombrer les flows. (Évidemment entre les guillemets, Il y aura l’identifiant de l’activité)

3.3.1 Id des activités dans une variable.

Pour faciliter tout ça, nous allons les sauvegarder dans une variable qui va pouvoir être utilisé dans le flow. Mettons tout ça dans une fonction.

Il y a 3 types de variables:

  • global: utilisable partout.
  • flow: comme le nom l’indique utilisable dans tout le flow où il est déclaré.
  • context: utilisable uniquement dans une fonction.
const a = flow.get('activitesHub') || 
{
    "activites": [ //Création tableau activités
        {
            "name": "tv", //Nom de l'activité (le même que le MQTT)
            "commande": ""//Entre les " " le numéro de l'activité
        },
        {
            "name": "",
            "commande": ""
        }
    ]
}
flow.set('activitesHub', a);

Faites attention à la syntaxe hein :wink:
Faites gaffe surtout à la virgule entre chaque entrée du tableau et n’en mettez pas à la dernière.

Puis on mettra en place comme sur les images ci-dessous.

2022-09-15 14.44.05 gladys.local a36edaff7540

Et dans le node « inject » Il faut cliquer comme sur l’image ci-dessous
Cela permettra, en cas de redémarrage de Node-Red, que cette variable se réinitialise toute seule.
Il y a aussi une autre solution en modifiant le fichier de configuration de Node-Red, mais restons sur le plus simple pour l’instant.

Inject

Pour vérifier que la variable et bien initialisée, nous allons regarder Ici et actualisé au niveau de Flow.

Vérifier variable

Normalement si tout s’est bien passé, vous devriez voir votre variable. Et entre les crochets, le nombre d’activités que vous avez enregistrées…

3.3.2. Vérification Mqtt + Récupération du code d’activité.

Maintenant, nous allons mettre en place une fonction(A2) pour vérifier de quelle lien MQTT vient l’information, récupérer le code de l’activité et une petite chose en plus que nous verrons par la suite.

//Récupération de la variable crée dernièrement
const activitesHub = flow.get("activitesHub");
//On fait une boucle pour comparer le message reçu avec la précédente variable
for (const i in activitesHub.activites) {
    var verifCommande = msg.topic.includes(activitesHub.activites[i].name);
    //Si ça correspond il renvoie "true"
    if (verifCommande) {
        const activite = activitesHub.activites[i].name;
        switch (msg.payload) {
            case 1:
                //Création de l'objet pour activer le node
                msg.payload = {
                    activity: activitesHub.activites[i].commande,
                };
                //Pour plus tard
                msg.commande = {
                    commande: activite, //Mets activité demandé
                    etat: true //Quand elle est activée
                };
                return msg;//Première sortie du node seulement
            case 0:
                msg.payload = null;
                msg.commande = {
                    commande: activite,
                    etat: false //Quand il est désactivé
                };
                return [null, msg];//Deuxième sortie seulement
            default:
                break;
        }
    }
}

Dans la fonction ci-dessus, nous faisons un test pour savoir quelle activité on demande grâce à une recherche dans le msg.topic qui est simplement le même message que celui récupéré dans Gladys dans le topic d’écoute.

Cette fonction sera reliée au node du Hub harmony Activity.
Recherche topique

Pour avoir une deuxième sortie, ou plus:

3.3.3 Sauvegarde de l’État du hub.

Nous allons sauvegarder l’état du Hub dans une deuxième variable flow, et en plus nous le mettrons dans un fichier texte qui permettra de la retrouver plus facilement en cas de redémarrage complet de Node-Red. Cela permet d’éviter de refaire la variable à chaque fois.

Dans une nouvelle fonction.
Accrocher au mêmes node inject que la précédente variable flow.

let flowEtatHub = flow.get('etatHub') || 
    {
        "etatHub": [] // On initialise un tableau
    }

flow.set('etatHub', flowEtatHub);

Dans une nouvelle fonction(A3) encore une fois.

let flowEtatHub = flow.get('etatHub') 

let a = false; //test si déjà inscrit
let testArray = flowEtatHub.etatHub.length; //test si le tableau est vide

//si déjà inscrit-> changement d'état
for (const i in flowEtatHub.etatHub) {
    const hub = flowEtatHub.etatHub[i].commande;
    if (msg.commande.commande === hub) {//Compare la commande envoyer s'il est déjà dans la variable
        flowEtatHub.etatHub[i].etat = msg.commande.etat;
        a = true
    }
}
//Si c'est pas le cas, nous le rajoutons au tableau
if (!a || !testArray) {
  flowEtatHub.etatHub.push(msg.commande);
}

msg.payload = flowEtatHub;
return msg;

Et celui-là, relié à la sauvegarde dans un fichier texte.

Réglage fichier texte

Normalement, les activités devraient s’activer (En désactivant le Node du Hub, cela évite de tout mettre en route). Mettez-les toutes en route, vous devriez voir un défaut, aucun bouton ne revient en position arrêtée quand vous en actionner un autre. Désactiver les tous saufs celui du off.
En faisant cela, vous avez résolu la moitié du problème. Nous allons voir ce qu’il y a dans la variable EtatHub.

Comme dans la précédente vérification de variables et en réactualisant

Comme d’habitude, si tout se passe bien, vous devriez voir l’état des boutons du tableau de bord de Gladys. C’est grâce à cela que nous allons finir avec ce souci. Nous allons faire une fonction qui compare l’état du bouton activer par rapport au précédemment allumé.
Comme cela, nous enverrons une information à Gladys en MQTT pour l’inverser.
Dans la fonction A4.

Quand on envoie en Mqtt, Il faut utiliser le lien de 'Topic MQTT pour publier" de Gladys, ou niveau du topic du Node

const flowEtatHub = flow.get("etatHub");

for (const i in flowEtatHub.etatHub) {
    //Si le bouton off est activé
    if (flowEtatHub.etatHub[i].commande === "extinction" && flowEtatHub.etatHub[i].etat) {
        //Alors on vérifie le nouveau message si il est différent
        if (msg.commande.etat && msg.commande.commande != "extinction") {
            //Si c'est le cas en envoi à Gladys 0 pour désactiver le bouton
            msg.payload = "0";
            //Et en modifier la variable d'État du hub
            msg.commande = {
            commande : "extinction",
            etat : false
            }
        return msg;
        }
    }
    //On répète l'opération avec chaque activité mais on envoie l'information sur la sorti numéro 2 du Node etc.
    else if (flowEtatHub.etatHub[i].commande === "tv" && flowEtatHub.etatHub[i].etat) {
        if (msg.commande.etat && msg.commande.commande != "tv") {
            msg.payload = "0";
            msg.commande = {
            commande : "tv",
            etat : false
            }
        return [null, msg];
        }
    }
}

Avec cela, quand on sélectionne une activité la précédente se met en mode off

3.3.4. Réinitialisation du bouton off (au cas où).

Mettons en place un Node fonction pour que si vous désactiver le bouton off, il se réinitialisera.
Il faudra le mettre entre les entrées MQTT et la fonction qui envoie le code.

//Remis à zéro de l'État hub Off en cas d'erreur s'il n'y a pas d'activité
if (msg.payload === 0) {
    var verifCommande = msg.topic.includes("powerextinction");//Mettre entre guillemets le nom de l'activité off que vous avez mis dans Gladys
    if (verifCommande) {
        msg.payload = "1";
        return [null, msg];
    }
}
return msg;

Et nous allons le relier à sa deuxième sortie au node MQTT qui correspond au bouton off.

3.3.5. Réinitialisation de la variable état hub

En cas de problème, dû à un redémarrage de Node-Red, nous allons mettre en place une petite fonction pour lire le fichier texte de sauvegarde et de le remettre dans la bonne variable, si seulement celle-ci est vide.

Dans read file, au niveau de path, Il faut mettre le même nom que dans l’enregistrement dans le fichier texte.
Dans la fonction.

let flowEtatHub = flow.get('etatHub');
let testArray = flowEtatHub.etatHub.length; //test si le tableau est vide
if (testArray === 0) {//S'il est vide, nous remettons chaque élément du tableau à sa place
    for (const i in msg.payload.etatHub) {

        flowEtatHub.etatHub.push(msg.payload.etatHub[i]);
    }
}

Normalement cela devrait ressembler à ça,


Vous pouvez bien évidemment changer chaque nom de variable selon votre guise dans la condition que vous les modifiez dans tout le reste du code.


4. Changement de chaîne

4.1 Intégration MQTT dans Gladys

Pensez à changer le nombre de chaînes que vous avez chez vous, la suite permettra d’aller jusqu’à 99.
Mais une petite modification peut se faire au cas où Il y en a plus.

Celle-ci permettra de conserver la dernière chaîne utilisée, comme cela, nous pourrons créer des scènes dans Gladys pour allumer l’activité de la télé et de changer de chaîne.

Pour commencer dans Node-Red, nous allons récupérer le code de chaque chiffre. Même principe que précédemment mais avec les nodes command, d’injection et de debug.

4.2 Récupération du code du numéro de la télécommande

Nous faisons à nouveau une variable flow comme ceci et nous le plaçons ici

4.3 Variable flow pour les numéros de chaînes

Toutes les variables

const a = flow.get('chaineTv') || {
    "chaines": [
        {
            "name": "0",
            "command": {
                "command": "0",
                "type": "IRCommand",
                "deviceId": "//Mettre ici l'id de la TV du Hub"
            }
        },
        {
            "name": "1",
            "command": {
                "command": "1",
                "type": "IRCommand",
                "deviceId": ""
            }
        },
        {
            "name": "2",
            "command": {
                "command": "2",
                "type": "IRCommand",
                "deviceId": ""
            }
        },
        {
            "name": "3",
            "command": {
                "command": "3",
                "type": "IRCommand",
                "deviceId": ""
            }
        },
        {
            "name": "4",
            "command": {
                "command": "4",
                "type": "IRCommand",
                "deviceId": ""
            }
        },
        {
            "name": "5",
            "command": {
                "command": "5",
                "type": "IRCommand",
                "deviceId": ""
            }
        },
        {
            "name": "6",
            "command": {
                "command": "6",
                "type": "IRCommand",
                "deviceId": ""
            }
        },
        {
            "name": "7",
            "command": {
                "command": "7",
                "type": "IRCommand",
                "deviceId": ""
            }
        },
        {
            "name": "8",
            "command": {
                "command": "8",
                "type": "IRCommand",
                "deviceId": ""
            }
        },
        {
            "name": "9",
            "command": {
                "command": "9",
                "type": "IRCommand",
                "deviceId": ""
            }
        }
    ]
}
flow.set('chaineTv', a)
4.4 Node complet + Réglages

Réglage Node

Sur l’image précédente, vous devriez savoir comment le remplir avec le topic d’écoute adéquate. Mais le plus important, pour faciliter la suite, c’est de bien régler le menu déroulant output en string

delay

Ci-dessus, l’image montre le réglage du Node delay pour l’utilisation qu’on souhaite ici. Nous laissons passer le premier message et le second attend un laps de temps en milliseconde qu’on déterminera dans la fonction B1

Puis dans la fonction B1

const commandeHubChaineTv = flow.get('chaineTv');
let flowEtatHub = flow.get("etatHub");
let chaines = msg.payload;
let commandEnvoi2 = {};
let sauvegardeChaine = {};
let etatTv = false;
let etatExtinction = false;
sauvegardeChaine.payload = msg.payload;

//Vérification que l'activité TV est allumée et que le bouton off est désactivé
for (const i in flowEtatHub.etatHub) {
    if (flowEtatHub.etatHub[i].commande === "tv" && flowEtatHub.etatHub[i].etat) {
        etatTv = true;
    }
    if (flowEtatHub.etatHub[i].commande === "extinction" && !flowEtatHub.etatHub[i].etat) {
        etatExtinction = true;
    }
}
if (etatTv && etatExtinction) {
    //vérification du chiffre de la chaîne puis récupération de la commande
    if (chaines.length === 1) {
    //On fait une boucle dans la variable de toutes les commandes de chaînes 
    //On compare avec la chaîne demandée et ensuite on récupère la commande qu'on envoie
        for (const i in commandeHubChaineTv.chaines) {
            if (chaines === commandeHubChaineTv.chaines[i].name) {
                msg.payload = commandeHubChaineTv.chaines[i].command;
                return [msg, sauvegardeChaine];
            }
        }
    }
    //vérification du nombre de la chaîne puis récupération des 2 commandes
    else if (chaines.length === 2) {
    //On fait la même chose 
        chaines = chaines.split(""); //Cela permet de diviser en 2 dans un tableau chaque numéro de la chaîne
       //récupère dans ce tableau les valeurs et on les compare comme précédemment
        var nbrChaine = chaines[0];
        var nbrChaine2 = chaines[1];
        for (const j in commandeHubChaineTv.chaines) {
            if (nbrChaine === commandeHubChaineTv.chaines[j].name) {
                msg.payload = commandeHubChaineTv.chaines[j].command;
                msg.rate = 500; //Temps millisecondes entre chaque message peut être changé
            }
        }
        for (const i in commandeHubChaineTv.chaines) {
            if (nbrChaine2 === commandeHubChaineTv.chaines[i].name) {
                commandEnvoi2.payload = commandeHubChaineTv.chaines[i].command;
            }
        }
        //Nous retournons dans la première sortie du Node le premier numéro puis le deuxième puis nous sauvegardons la chaîne avec la deuxième sortie en direction du mqtt
        return [[msg, commandEnvoi2], sauvegardeChaine];
    }
}


5. Volume de l’ampli

5 « J'aime »

Bonjour @dahut
Merci pour ce tuto je pouvoir automatiser mon systeme audio video.
Si je peux me permettre, il y a un petit apostrophe, qui genere une erreur dans ta fonction A1. Il est sur la premiere ligne, celui qui est juste avant flow.get, je l’ai supprimé et mon code est devenu bon

const a = `flow.get('activitesHub') ||

:wink:

J’ai corrigé

2 « J'aime »

Désolé pour cette petite faute et merci
@VonOx, Merci pour la correction.

2 « J'aime »

Bonjour @dahut
Merci pour le tuto :+1:, ça y est tout fonctionne correctement.
Les point 4 et 5 du tuto, seront développés plus tard ? :slightly_smiling_face:

Salut, @Psoy
je suis bien content que tout fonctionne car ce n’est pas vraiment évident de faire un tutoriel.

Les points 4 et 5 sont déjà écrits et même un retour à Gladys quand on utilise directement la télécommande. Cela permet de déclencher des scènes dans Gladys Grâce au retour du Hub.

Bonsoir @dahut
Ne maitrisant pas javascript, je t’avoue que j’ai un peu galéré, mais c’est bon ça fonctionne. :grinning:

Tu vas les publier bientôt ?
merci encore

Bonsoir @Psoy

Je viens de mettre le point 4, pour le changement de chaîne, en espérant qu’il n’y a pas de coquilles.

Ça été un peu plus long que prévu car j’ai essayé de simplifier mais ça avait tout buggé donc le temps de tout corriger et de vraiment simplifier avec un réglage de rien du tout en fin de compte.

Bonsoir @dahut ,
Je teste ça dès que je peux , et je te fais un retour.
Merci bien
Bonne soirée