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
- Prérequis
- Installation du Node
- Activités du Hub
- Changement de chaîne
- Volume de l’ampli
1. Prérequis
Il ne faut pas grand-chose mais il les faut quand même
- Gladys
- Mqtt
- Node-Red
- Quelques connaissances en JavaScript.
- Un petit peu de patience.
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
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.
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.
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.
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.
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
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.
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.
Pour vérifier que la variable et bien initialisée, nous allons regarder Ici et actualisé au niveau de Flow.
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.
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.
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.
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
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
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
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];
}
}