[NODE-RED] Logitech Hub Harmony

Hub Harmony in Gladys


Hallo, ich werde versuchen, euch einen kleinen Tutorial zu geben, um den Hub Harmony zu integrieren, der, für diejenigen, die ihn nicht kennen, es ermöglicht, Hi-Fi- und Video-Geräte sowie ein wenig Smart Home zu steuern (Nicht sehr nützlich, da wir Gladys verwenden, um alles zu zentralisieren).

Dieser Hub ermöglicht es, eine Kombination von Befehlen gemäß vorab vom Benutzer aufgezeichneten Sequenzen oder Aktivitäten auszulösen, und genau das werden wir integrieren.

Ich habe mich dafür entschieden, Node-Red wegen seiner Flexibilität zu verwenden, und werde mich daher im gesamten Tutorial darauf stützen.

Inhaltsverzeichnis


  1. Voraussetzungen
  2. Installation des Nodes
  3. Aktivitäten des Hubs
  4. Kanalwechsel
  5. Lautstärke des Verstärkers

1. Voraussetzungen


Man braucht nicht viel, aber man braucht es trotzdem :wink:

Installation der Voraussetzungen


1.1 Installation Gladys

Für Gladys, normalerweise sollte das einfach sein.

1.2 Installation Mqtt

Gehen wir zu Mqtt über. Auch hier ist es nicht zu kompliziert.
Hier ist der Tutorial

1.3 Installation Node-Red

Wenn es eine ganz neue Installation ist, könnt ihr die folgenden Befehle ausführen:

Node-Red

Installation von Node-Red über 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

und dann dieser hier

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

2. Installation Node Harmony

Jetzt können wir zu Node-Red wechseln.

Die IP-Adresse des Raspberry oder der Domainname deiner Maschine auf Port 1880
Beispiel: 192.168.1.XX:1880 oder XX.local:1880

Wenn du dort angekommen bist, drücke Strg+Umschalt+P, oder klicke oben rechts in der Ecke auf das Menü Manage palette.
Wir gelangen zur Seite der bereits installierten Nodes
Danach musst du auf die Registerkarte install klicken.
Wir suchen nach node-red-contrib-harmony-websocket.
Und installieren es natürlich.


3. Integration der Aktivitäten

Macht euch keine Sorgen, wenn ich es geschafft habe, kann es jeder.

3.1. Mqtt

Hier ist ein Beispiel für eine Mqtt-Integration in Gladys. Für den Namen der Aktivität, hier « tv ». Dadurch kann man in Node-Red leichter identifizieren.

Macht alle Aktivitäten auf einmal :wink:
Erfahrungsbericht:
Wenn ihr Aktivitäten mit identischen Wörtern im Namen habt, müsst ihr sie mit Großbuchstaben unterscheiden, da die Funktion in Node-Red, die wir verwenden, die Groß-/Kleinschreibung beachtet.

Und vor allem in das Dashboard integrieren

3.2. Mqtt in Node-Red

Wir beginnen damit, alle MQTT-Knoten in Node-Red zu integrieren und den dazugehörigen Server zu starten.

Ich erwähne es nicht, aber denkt daran, zu deployen.

3.2.1 Konfiguration des Mqtt-Servers in Node-Red.

Wir öffnen einen der Nodes, um den Server wie folgt zu konfigurieren.

Mqtt-Server

Wir werden auf den Stift klicken

Das sind die Anmeldedaten und Passwörter der MQTT-Integration in Gladys

3.2.2. Mqtt-Topic.

Nach der Serverbestätigung geben wir in das Topic den Link des Topics für den Empfang der Integration in Gladys ein. Natürlich hat jeder Node einen anderen Link.

Mqtt-Topic

3.3. Konfiguration des Node Harmony-Servers.

Nach alldem werden wir den Node des Hubs einrichten. Es ist etwa das gleiche Prinzip, außer dass er normalerweise die IP-Adresse davon allein finden sollte.
Wenn alles wie geplant läuft, solltest du, wenn du die Konfiguration bestätigst, im Dropdown-Menü alle Aktivitäten sehen, die du mit Zahlen programmiert hast.
Dies stellt die ID jeder Aktivität dar. Da dies wichtig ist, werden wir sie irgendwo mit ihrem Namen kopieren.

Auf dem obigen Bild sehen wir, was der Node zurückgibt, wenn wir ihn manuell aktivieren. Daher werden wir es auf diese Weise senden, um die Flows nicht zu sehr zu überlasten. (Natürlich werden zwischen den Anführungszeichen die Aktivitäts-ID stehen)

3.3.1 IDs der Aktivitäten in einer Variablen.

Um das alles zu erleichtern, werden wir sie in einer Variablen speichern, die im Flow verwendet werden kann. Legen wir alles in eine Funktion.

Es gibt 3 Arten von Variablen:

  • global: überall verwendbar.
  • flow: wie der Name schon sagt, im gesamten Flow verwendbar, in dem es deklariert wird.
  • context: nur in einer Funktion verwendbar.
const a = flow.get('activitesHub') || 
{
    "activites": [ //Erstellen eines Aktivitätentabellen
        {
            "name": "tv", //Name der Aktivität (derselbe wie bei MQTT)
            "commande": ""//Zwischen den " " die Nummer der Aktivität
        },
        {
            "name": "",
            "commande": ""
        }
    ]
}
flow.set('activitesHub', a);

Achtet auf die Syntax, okay :wink:
Achtet besonders auf das Komma zwischen jedem Tabelleneintrag und setzt kein Komma am letzten.

Dann werden wir es wie auf den unten stehenden Bildern einrichten.

2022-09-15 14.44.05 gladys.local a36edaff7540

Und im Node « inject » muss man wie auf dem unten stehenden Bild klicken
Das wird im Falle eines Neustarts von Node-Red ermöglichen, dass diese Variable sich von selbst zurücksetzt.
Es gibt auch eine andere Lösung, indem man die Konfigurationsdatei von Node-Red ändert, aber bleiben wir für den Moment bei der einfachsten Lösung.

Um zu überprüfen, ob die Variable korrekt initialisiert wurde, werden wir hier nachschauen und auf Flow aktualisieren.

Normalerweise, wenn alles gut gelaufen ist, solltest du deine Variable sehen. Und in den Klammern die Anzahl der Aktivitäten, die du gespeichert hast..

3.3.2. Überprüfung von Mqtt + Abruf des Aktivitätscodes.

Jetzt werden wir eine Funktion (A2) einrichten, um zu überprüfen, von welchem MQTT-Link die Information kommt, den Aktivitätscode abzurufen und eine kleine Sache mehr, die wir später sehen werden.

//Abruf der zuletzt erstellten Variablen
const activitesHub = flow.get("activitesHub");
//Wir machen eine Schleife, um die empfangene Nachricht mit der vorherigen Variablen zu vergleichen
for (const i in activitesHub.activites) {
    var verifCommande = msg.topic.includes(activitesHub.activites[i].name);
    //Wenn es übereinstimmt, gibt es "true" zurück
    if (verifCommande) {
        const activite = activitesHub.activites[i].name;
        switch (msg.payload) {
            case 1:
                //Erstellen des Objekts zum Aktivieren des Nodes
                msg.payload = {
                    activity: activitesHub.activites[i].commande,
                };
                //Für später
                msg.commande = {
                    commande: activite, //Gesuchte Aktivität einfügen
                    etat: true //Wenn sie aktiviert ist
                };
                return msg;//Nur erster Ausgang des Nodes
            case 0:
                msg.payload = null;
                msg.commande = {
                    commande: activite,
                    etat: false //Wenn sie deaktiviert ist
                };
                return [null, msg];//Nur zweiter Ausgang
            default:
                break;
        }
    }
}

In der obigen Funktion machen wir einen Test, um zu wissen, welche Aktivität wir anfordern, durch eine Suche im msg.topic, der einfach die gleiche Nachricht ist wie die, die in Gladys im Listentopic abgerufen wurde.

Diese Funktion wird mit dem Node des Hub harmony Activity verbunden.
Topic-Suche

Um einen zweiten Ausgang oder mehr zu haben:

3.3.3. Speichern des Hub-Status.

Wir werden den Status des Hubs in einer zweiten Flow-Variablen speichern, und zusätzlich werden wir ihn in eine Textdatei setzen, die es im Falle eines vollständigen Neustarts von Node-Red einfacher macht, ihn wiederzufinden. Dadurch wird vermieden, die Variable jedes Mal neu zu erstellen.

In einer neuen Funktion.
An denselben Node inject wie die vorherige Flow-Variable anhängen.

let flowEtatHub = flow.get('etatHub') || 
    {
        "etatHub": [] // Initialisieren eines Tabellen
    }

flow.set('etatHub', flowEtatHub);

In einer neuen Funktion (A3) noch einmal.

let flowEtatHub = flow.get('etatHub') 

let a = false; //Test, ob bereits eingetragen
let testArray = flowEtatHub.etatHub.length; //Test, ob die Tabelle leer ist

//Wenn bereits eingetragen -> Statusänderung
for (const i in flowEtatHub.etatHub) {
    const hub = flowEtatHub.etatHub[i].commande;
    if (msg.commande.commande === hub) {//Vergleicht den gesendeten Befehl, ob er bereits in der Variablen ist
        flowEtatHub.etatHub[i].etat = msg.commande.etat;
        a = true
    }
}
//Wenn nicht, fügen wir ihn der Tabelle hinzu
if (!a || !testArray) {
  flowEtatHub.etatHub.push(msg.commande);
}

msg.payload = flowEtatHub;
return msg;

Und dieser ist mit der Sicherung in einer Textdatei verbunden.

Normalerweise sollten die Aktivitäten aktiviert werden (Durch Deaktivieren des Hub-Nodes wird verhindert, dass alles gestartet wird). Aktivieren Sie alle, Sie sollten einen Fehler sehen, kein Knopf kehrt in die Aus-Position zurück, wenn Sie einen anderen betätigen. Deaktivieren Sie alle außer dem Aus-Knopf.
Dadurch haben Sie die Hälfte des Problems gelöst. Wir werden sehen, was in der Variable EtatHub enthalten ist.

Wie bei der vorherigen Variablenüberprüfung und beim Aktualisieren

Wie üblich, wenn alles gut läuft, sollten Sie den Status der Knöpfe des Gladys-Dashboards sehen. Dadurch können wir dieses Problem beheben. Wir werden eine Funktion erstellen, die den Status des aktivierten Knopfes mit dem zuvor eingeschalteten vergleicht.
Auf diese Weise senden wir eine Information an Gladys über MQTT, um sie umzukehren.
In der Funktion A4.

Wenn man über Mqtt sendet, muss man den Link von 'MQTT-Topic zum Veröffentlichen" von Gladys oder den Topic-Level des Nodes verwenden

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

for (const i in flowEtatHub.etatHub) {
    //Wenn der Aus-Knopf aktiviert ist
    if (flowEtatHub.etatHub[i].commande === "extinction" && flowEtatHub.etatHub[i].etat) {
        //Dann überprüfen wir die neue Nachricht, ob sie unterschiedlich ist
        if (msg.commande.etat && msg.commande.commande != "extinction") {
            //Wenn dies der Fall ist, senden wir an Gladys 0, um den Knopf zu deaktivieren
            msg.payload = "0";
            //Und ändern den Hub-Statusvariable
            msg.commande = {
            commande : "extinction",
            etat : false
            }
        return msg;
        }
    }
    //Wir wiederholen den Vorgang mit jeder Aktivität, aber wir senden die Information an den Node-Ausgang Nr. 2 usw.
    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];
        }
    }
}

Mit diesem, wenn man eine Aktivität auswählt, wird die vorherige in den Aus-Modus versetzt

3.3.4. Zurücksetzen des Aus-Knopfes (falls erforderlich).

Legen wir einen Funktions-Node an, damit, wenn Sie den Aus-Knopf deaktivieren, er zurückgesetzt wird.
Er muss zwischen den MQTT-Eingängen und der Funktion platziert werden, die den Code sendet.

//Zurücksetzen des Hub-Aus-Zustands im Fehlerfall, wenn keine Aktivität vorhanden ist
if (msg.payload === 0) {
    var verifCommande = msg.topic.includes("powerextinction");//Setzen Sie den Namen der Aus-Aktivität, die Sie in Gladys angegeben haben, in Anführungszeichen
    if (verifCommande) {
        msg.payload = "1";
        return [null, msg];
    }
}
return msg;

Und wir werden ihn mit seinem zweiten Ausgang an den MQTT-Node anschließen, der dem Aus-Knopf entspricht.

3.3.5. Zurücksetzen der Hub-Statusvariable

Im Falle eines Problems, das durch einen Neustart von Node-Red verursacht wird, werden wir eine kleine Funktion einrichten, um die Textdatei der Sicherung zu lesen und sie in die richtige Variable zurückzusetzen, wenn diese leer ist.

Textdatei lesen

In read file, im Pfad, müssen Sie denselben Namen wie bei der Aufzeichnung in der Textdatei angeben.
In der Funktion.

let flowEtatHub = flow.get('etatHub');
let testArray = flowEtatHub.etatHub.length; //Test, ob das Array leer ist
if (testArray === 0) {//Wenn es leer ist, setzen wir jedes Element des Arrays an seinen Platz zurück
    for (const i in msg.payload.etatHub) {

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

Normalerweise sollte es so aussehen,


Sie können natürlich jeden Variablennamen nach Belieben ändern, mit der Bedingung, dass Sie sie im Rest des Codes ändern.


4. Kanalwechsel

4.1 MQTT-Integration in Gladys

Denken Sie daran, die Anzahl der Kanäle zu ändern, die Sie zu Hause haben, die Folge ermöglicht es, bis zu 99 zu gehen.
Aber eine kleine Änderung kann vorgenommen werden, falls es mehr gibt.

Dieser ermöglicht es, den zuletzt verwendeten Kanal zu speichern, so dass wir Szenen in Gladys erstellen können, um die TV-Aktivität einzuschalten und den Kanal zu wechseln.

Um in Node-Red zu beginnen, werden wir den Code jeder Zahl abrufen. Gleiches Prinzip wie zuvor, aber mit den command-Nodes, Injektion und Debug.

4.2 Abrufen des Fernbedienungs-Nummerncodes

Kanal-Debug-Node

Wir erstellen erneut eine Flow-Variable wie folgt und platzieren sie hier

4.3 Flow-Variable für die Kanalnummern

const a = flow.get('chaineTv') || {
    "chaines": [
        {
            "name": "0",
            "command": {
                "command": "0",
                "type": "IRCommand",
                "deviceId": "//Hier die ID des TV-Hubs einfügen"
            }
        },
        {
            "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 Vollständiger Node + Einstellungen

Auf dem vorherigen Bild sollten Sie wissen, wie man es mit dem entsprechenden Listentopic ausfüllt. Aber das Wichtigste, um die weitere Arbeit zu erleichtern, ist, das Dropdown-Menü Ausgabe auf String einzustellen

Oben zeigt das Bild die Einstellung des Delay-Node für die hier gewünschte Verwendung. Wir lassen die erste Nachricht durch und die zweite wartet eine Zeit in Millisekunden, die wir in der Funktion B1 bestimmen werden

Dann in der Funktion 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;

//Überprüfung, ob die TV-Aktivität eingeschaltet ist und der Ausschaltknopf deaktiviert ist
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) {
    //Überprüfung der Kanalnummer und Abruf des Befehls
    if (chaines.length === 1) {
    //Wir durchlaufen die Variable aller Kanalbefehle
    //Wir vergleichen mit dem angeforderten Kanal und holen dann den Befehl, den wir senden
        for (const i in commandeHubChaineTv.chaines) {
            if (chaines === commandeHubChaineTv.chaines[i].name) {
                msg.payload = commandeHubChaineTv.chaines[i].command;
                return [msg, sauvegardeChaine];
            }
        }
    }
    //Überprüfung der Kanalnummer und Abruf der 2 Befehle
    else if (chaines.length === 2) {
    //Wir machen dasselbe
        chaines = chaines.split(""); //Dadurch wird jede Kanalnummer in ein Array in zwei Teile aufgeteilt
       //Holt die Werte aus diesem Array und vergleicht sie wie zuvor
        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; //Zeit in Millisekunden zwischen jeder Nachricht kann geändert werden
            }
        }
        for (const i in commandeHubChaineTv.chaines) {
            if (nbrChaine2 === commandeHubChaineTv.chaines[i].name) {
                commandEnvoi2.payload = commandeHubChaineTv.chaines[i].command;
            }
        }
        //Wir geben an der ersten Ausgabe des Knotens die erste Nummer und dann die zweite aus und speichern den Kanal mit der zweiten Ausgabe in Richtung mqtt
        return [[msg, commandEnvoi2], sauvegardeChaine];
    }
}


5. Lautstärke des Verstärkers

Hallo @dahut
Danke für das Tutorial, damit kann ich mein Audio-Video-System automatisieren.
Falls ich mir die Freiheit nehmen darf, es gibt ein kleines Apostroph, das einen Fehler in deiner Funktion A1 verursacht. Es steht in der ersten Zeile, direkt vor flow.get. Ich habe es entfernt und mein Code funktioniert jetzt.

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

:wink:

Ich habe korrigiert

Entschuldigung für diesen kleinen Fehler und danke
@VonOx, Danke für die Korrektur.

Hallo @dahut
Danke für das Tutorial :+1:, jetzt funktioniert alles richtig.
Werden die Punkte 4 und 5 des Tutorials später noch entwickelt? :slightly_smiling_face:

Hallo, @Psoy
ich freue mich sehr, dass alles funktioniert, denn es ist nicht wirklich einfach, ein Tutorial zu erstellen.

Die Punkte 4 und 5 sind bereits geschrieben und sogar eine Rückmeldung an Gladys, wenn man die Fernbedienung direkt verwendet. Dadurch können Szenen in Gladys mithilfe der Rückmeldung des Hubs ausgelöst werden.

Guten Abend @dahut
Da ich kein JavaScript beherrschte, gebe ich zu, dass ich etwas gekämpft habe, aber jetzt ist es gut, es funktioniert. :grinning:

Wirst du sie bald veröffentlichen?
Danke nochmal

Guten Abend @Psoy

Ich habe gerade Punkt 4, für den Kanälewechsel, eingestellt, in der Hoffnung, dass keine Fehler drin sind.

Es hat etwas länger gedauert als geplant, weil ich versucht habe, es zu vereinfachen, aber dann ist alles kaputt gegangen. Also musste ich alles korrigieren und am Ende wirklich vereinfachen, mit einer winzigen Einstellung.

Guten Abend @dahut,
Ich teste das, sobald ich kann, und gebe dir Feedback.
Vielen Dank
Gute Nacht