Serie Leinwand-Maskierung zur Bildverbesserung (Teil 1 2 3 4 5 6 7)

HTTP-Webservice mit Node.js zur Steuerung eines Schrittmotors

Für eine Leinwand-Maskierung, die sich mechanisch verschieben lässt, haben wir einen Schrittmotor mit Gewindespindel als Antrieb vorgesehen. Ein Raspberry Pi steuert den Motor mit Hilfe eines Python-Scripts. Weil das für die Einbindung in die Heimkino-Steuerung etwas unpraktisch ist, wollen wir hier noch einen kleinen Webservice drum herum stricken, der die Steuerung der Maskierung im hausinternen Netzwerk zur Verfügung stellt.

Ein Raspberry Pi 3 mit diversen belegten Pins, die mit dem Schrittmotor-Treiber verdrahtet sind.

Der Vorteil eines HTTP-Webservices ist, dass es mittlerweile sehr viele Systeme zur Hausautomation gibt, die diesen ansprechen können. Dazu gehören unter vielen anderen die beliebte Logitech Harmony und der Light-Manager Air. Zwar ist mit der hier gezeigten Umsetzung noch keine direkte Anbindung an einen Sprachassistenten möglich, aber über den Umweg eines der genannten Systeme ist das nur noch Fleißarbeit. Außerdem wollen wir unsere Maskierung ja nicht gleich der ganzen Welt öffnen.

HTTP-basierte Schnittstellen sind im Grunde nichts anderes als gewöhnliche Internetseiten – nur eben nicht mit einem hübschen Layout. Stattdessen werden pure Daten ausgetauscht und Befehle gesendet. Dazu benötigen wir nur einen kleinen Webserver – was komplizierter klingt, als es ist. Anstatt den Webservice im Internet zur Verfügung zu stellen (was sicherheitstechnisch zumindest bedenklich wäre), läuft dieser auf dem Raspberry Pi, der auch den Schrittmotor steuert, und stellt ihn im lokalen Netzwerk bereit.

In diesem Artikel stelle ich dir den kompletten Code zur Verfügung, der dafür notwendig ist und zeige dir, wo du Anpassungen vornehmen musst. Die Python-Scripts zur Steuerung des Motors sind ebenfalls enthalten und im Vergleich zu unseren einfachen Versuchen aus dem vorherigen Artikel nun weitestgehend ausgereift.

Weiterhin gehe ich darauf ein, wie du den Webservice nutzen kannst und wie er sich in deine Heimkino-Steuerung einbinden lässt.

Grundvoraussetzung ist, dass du einen Raspberry Pi als Controller für den Schrittmotor einsetzt. Mit einem Arduino funktioniert die hier vorgestellte Lösung nicht out-of-the-box. Ausgangslage ist ein NEMA-17-Schrittmotor mit 4 Kabeln, ein TB6600-Treiber und besagter Raspberry Pi. Den Aufbau und die Installation von Raspbian als Betriebssystem habe ich im vorherigen Beitrag vorgestellt. Deshalb erwähne ich das hier nur nochmal sehr knapp.

Es ist sicher möglich, die Python-Scripts samt Webservice auch auf anderen Systemen laufen zu lassen – wenn du das willst, wirst du schon wissen, was du tust.

Legen wir los.

1. Installation auf dem Raspberry Pi

Du würdest diesen Artikel vermutlich nicht lesen, wenn du nicht bereits erste Schritte mit einem Schrittmotor (ha!) gemacht hättest. Ich gehe deshalb davon aus, dass du Raspbian als Betriebssystem installiert hast und bereits Python-Scripts ausführen konntest.

Für den Anfang solltest du nochmal das System auf den neuesten Stand bringen, was etwas dauern könnte:

sudo apt-get update
sudo apt-get upgrade

1.1 Node.js installieren

Zuerst installierst du Node.js einschließlich npm (Node Package Manager) nach diesem Tutorial. Das ist leider etwas unübersichtlich, funktioniert aber sonst ganz gut.

Anmerkung: Die Node-Website verlinkt ein *.tar.xz-File – im Tutorial wird aber von einem *.tar.gz ausgegangen. Ändere einfach beim WGET die Dateiendung ab; auf dem Server liegt beides.

1.2 Den Webservice einrichten

Den kompletten Code, den du für den Webservice benötigst, kannst du von GitHub herunterladen. Python-Scripts für die Motorsteuerung sind ebenfalls enthalten. Das Projekt legst du am besten im Home-Verzeichnis deines Pi-Standardbenutzers in einem Unterverzeichnis screen-masking ab. Darin sollte sich unter anderem die Datei index.js befinden.

1.3 Node-Module installieren

Stelle sicher, dass du dich im Projektverzeichnis befindest:

cd ~/screen-masking

Dann kannst du die Komponenten für das Projekt installieren:

npm install

Wie das bei Node-Projekten so üblich ist, sind darin alle Abhängigkeiten definiert. Das Projekt weiß also selbst, was es braucht.

1.4 Testlauf starten

Jetzt wäre es an der Zeit, zu testen, ob die App grundsätzlich läuft.

node index.js

Die App sollte starten und ausgeben, unter welchem Port sie erreichbar ist. Tippe die folgende URL in einen Webbrowser ein, der sich im selben Netzwerk wie der Raspberry Pi befindet (oder nutze curl, wenn dir das einfacher erscheint).

http://<raspberry-pi-ip>:<port>/force-by/500

Den Teil <raspberry-pi-ip> ersetzt du natürlich durch die IP-Adresse des Raspberry Pi und <port> durch die Portnummer, die beim Start der App angezeigt wurde.

An dieser Stelle eine kleine Warnung: Teste die Funktionalität immer nur dann, wenn der Motor nicht mit deiner Maskierung verbunden ist. Wenn der Motor über die mechanischen Grenzen der Maskierung hinaus fährt, wird sehr wahrscheinlich etwas kaputt gehen. Einmal richtig eingerichtet, kümmert sich die App darum, dass sowas nicht passiert.

1.5 App mit dem System starten

Du wirst die App wahrscheinlich automatisch mit dem System starten lassen wollen. So kannst du einfach mal den Stecker ziehen. Nach einem Neustart wird sie dann automatisch wieder gestartet. Dieses Tutorial erklärt, wie das geht.

sudo vi /etc/rc.local

Füge hier die folgende Zeile ein:

su pi -c 'cd /home/pi/screen-masking; node index.js < /dev/null &'

Nach einem Neustart (init 6) sollte die App automatisch im Hintergrund gestartet werden. Der Testlauf durch Aufruf der URL wie oben beschrieben sollte immer noch funktionieren.

1.6 Konfiguration anpassen

Die Node.js-App ist nur ein „Wrapper“ für die Python-Scripts, um diese auf einem standardisierten und breit unterstützten Weg im Netzwerk verfügbar zu machen. An der App selbst muss nichts konfiguriert werden (außer du möchtest unbedingt den äußerst sorgfältig gewählten Port ändern).

Allerdings solltest du das Verhalten des Schrittmotors konfigurieren und an deine Hardware anpassen. Das erledigst du in der Datei python/tb6600/stepper.py. Alle wichtigen Einstellungen sind als Konstanten definiert.

  • Du kannst die Pin-Nummern des Raspberry Pi für DIRPUL und ENA anpassen, falls du sie abweichend von der Beschreibung in python/tb6600/wiring-nema17-4pin.md verkabelt hast.
  • Der Winkel eines Motorschritts ist in STEP_ANGLE mit 0,9° vorkonfiguriert, was bei den meisten Motoren einem Halbschritt entspricht.
  • Die Rampe ist in RAMP_LENGTH mit 600 Schritten angegeben, um den Motor sanft anfahren und abbremsen zu lassen.
  • MIN_RPM und MAX_RPM definieren die langsamste und schnellste Geschwindigkeit des Motors in Umdrehungen pro Minute. Die Werte sollten so klein bzw. groß wie möglich sein, so dass der Motor keine Aussetzer hat oder übermäßig starke Resonanzen erzeugt.
  • MAX_STEPS ist von allen Einstellungen die wichtigste. Sie besagt, wie viele Schritte der Motor fahren darf, bevor er die Obergrenze des Fahrwegs erreicht.

Noch ein paar Informationen zu MAX_STEPS. Wie bereits erwähnt stellt das Python-Script sicher, dass der Motor nur im Bereich von 0 bis MAX_STEPS bewegt werden kann. Er kann sich nicht oberhalb oder unterhalb dieser Grenze bewegen, sondern wird vorher anhalten. Damit wird sichergestellt, dass der Motor nicht versehentlich versucht, deine Maskierung über ihre mechanischen Grenzen hinaus zu ziehen.

Bevor du das Script an deiner Maskierung ausprobierst, musst du genau ermitteln, wie viele Schritte dein Motor machen muss, um die Maskierung über ihren vollen mechanischen Fahrweg zu ziehen. Wenn der Motor eine Gewindespindel antreibt, wird der Schlitten sehr wahrscheinlich die selbe Strecke zurücklegen müssen wie die Maskierung. In meinem Fall sind das 20 cm. Abhängig von der Steigung des Gewindes könnten dafür zum Beispiel 10.000 Schritte notwendig sein. Du solltest vorab mit dem Motor gewisse Schrittzahlen abgefahren sein und dabei mit einem Lineal ausgemessen haben, welche Strecke dabei zurückgelegt wurde. So kommst du am Ende darauf, wie viele Schritte für die Strecke notwendig sind. Diesen Wert trägst du für MAX_STEPS ein.

Bedenke dabei auch: Um die selbe Strecke zurückzulegen sind doppelt so viele Halbschritte (0,9°) notwendig, wie ganze Schritte (1,8°) erforderlich wären. MAX_STEPS hängt also auch mit STEP_ANGLE zusammen und mit der Schrittgröße, die du mit den kleinen Schaltern am TB6600-Treiber festgelegt hast.

2. API des Webservice

Du kannst im Grunde die Python-Scripts direkt ausführen, wie du es bereits gewohnt bist. Die meisten davon sind nur Abkürzungen und greifen am Ende immer auf Funktionen zu, die in stepper.py definiert sind. Der Weg, den wir hier einschlagen wollen, ist aber der, die App zu nutzen.

Wie bereits mit dem Test weiter oben erfolgt, rufst du verschiedene URLs mit Parametern auf, um die einzelnen Funktionen anzusteuern. Nachfolgend sind alle Möglichkeiten aufgelistet. Verwende HTTP GET um Werte abzufragen und PUT um Aktionen auszuführen. Rückgabewerte werden im JSON-Format ausgegeben.

GET /position
Gibt die aktuelle Position des Motors in Anzahl Schritten zurück. Der Wert liegt zwischen 0 und MAX_STEPS.

GET /power
Gibt den Zustand eines Relais-Moduls zurück, sofern du eines verwendest, um die Stromzufuhr zum Treiber zu kontrollieren. Mögliche Werte sind 1 oder 0. Mehr dazu später.

PUT /move-to/1000
Bewegt den Motor absolut an die angegebene Schrittposition. Nimmt Werte im Bereich von 0 bis MAX_STEPS entgegen. Die Bewegung erfolgt möglichst schnell und verwendet die Rampe.

Nach jeder Bewegung bekommst du die neue Position in Schritten zurück. Du könntest diesen Wert zum Beispiel verwenden, um das Bildseitenverhältnis der Leinwand anzuzeigen.

PUT /move-by/250
Bewegt den Motor relativ um die angegebene Schrittzahl. Nimmt eine beliebige positive oder negative Ganzzahl entgegen. Beispiel: Der Motor steht aktuell an Position 4350, du rufst /move-by/-350 auf, die neue Position nach der Bewegung ist 4000. Die Bewegung erfolgt möglichst schnell und verwendet die Rampe.

Du kannst dem Motor so zwar befehlen, über die Ober- und Untergrenze hinaus zu fahren, aber er wird rechtzeitig anhalten und auch nur die tatsächlich erreichte Position zurückgeben.

PUT /force-by/250
Bewegt den Motor relativ um die angegebene Schrittzahl. Nimmt eine beliebige positive oder negative Ganzzahl entgegen. Die Bewegung erfolgt so langsam wie möglich und verwendet die Rampe nicht. Die Unter- und Obergrenze der Bewegung wird ignoriert! Verwende das nur mit großer Vorsicht. Bei entsprechenden Aufrufen wird sich der Motor aus den mechanischen Grenzen der Maskierung hinaus bewegen. Die Funktion ist dafür gedacht, die Position korrigieren zu können. Alternativ könntest du einfach am Motor drehen.

PUT /calibrate
Setzt die intern gespeicherte Position auf 0 zurück. Rufe das auf, nachdem du die Maskierung an die untere Grenze gesetzt hast.

PUT /power/1
Legt den Schaltzustand eines optional an Pin 11 angeschlossenen Relais-Moduls fest. Nimmt die Werte 1 oder 0 entgegen. Das Relais wird vor jeder Motorbewegung automatisch aktiviert, falls nicht bereits geschehen. Einschalten musst du es also eigentlich gar nicht. Wenn du kein Relais-Modul verwendest, ist der Strom sowieso immer an, bis du den Stecker ziehst.

3. Einbindung in bestehende Steuersysteme

An dieser Stelle sollte es dir also möglich sein, den Schrittmotor über HTTP-Aufrufe zu steuern. Somit kannst du die Steuerung der Maskierung in jedes beliebige System zur Hausautomation einbauen, die das unterstützt.

3.1 Light-Manager Air

Beispielhaft zeige ich hier mal, wie das mit dem Light-Manager Air funktioniert.

In AirStudio legst du in der Aktorenverwaltung einen neuen Aktor vom Typ IR–Funk–LAN an, wählst LAN aus und klickst bei Taste 1 auf Konfigurieren. Hier wählst du PUT aus und gibst die URL ohne vorangestelltes http:// ein. Daten werden nicht benötigt.

Die Taste kannst du noch wie das damit eingestellte Bildformat benennen. Für Taste 2 könntest du beispielsweise den gegenläufigen Befehl senden. Oder du verwendest /move-by/200 und nutzt die beiden Tasten, um die Maskierung schrittweise hoch und runter zu bewegen.

3.2 Einbinden in CinemaVision-Actions

Du kannst die Steuerung der Maskierung als Teil einer CinemaVision-Action aufrufen.

http://<IP-Adresse>:<Port>/move-to/3500
PUT: { }

So kannst du beispielsweise zum Ende des Werbeblocks automatisch die Maskierung von 16:9 auf 21:9 reinfahren lassen.

Nun konnte ich diese App natürlich nicht in jedem denkbaren Szenario testen. Deshalb bin ich auf deine Mithilfe angewiesen, eventuelle Fehler zu finden und zu beheben. Das betrifft sowohl das Script selbst als auch die Anleitung in diesem Artikel. Wie gut konntest du das nachvollziehen? Ist etwas nicht schlüssig oder fehlen wichtige Informationen? Schreibe bitte einen Kommentar, wenn du etwas in der Art findest.

Gleiches gilt, wenn du ein weiteres Beispiel hast, wie du den Webservice nutzt. In welches System bindest du die Aufrufe ein? Weitere Beispiele sind hier gern gesehen.

Über Bert Kößler

Leidenschaftlicher Filmvorführer, Popcorn-Koch, Kartenabreißer, Platzanweiser, Programmchef, Projektionist, Reinigungsfachkraft und Kabelmann in einer Person. Neigt zu ausgeprägtem Fanatismus, wenn es um die Steuerung und Automatisierung des Heimkinos geht. Konnte sich zwischen zwei Filmen dazu motivieren, Heimkino Praxis als Ventil für gelegentliche Schreibanfälle zu gründen.

22 Gedanken zu „HTTP-Webservice mit Node.js zur Steuerung eines Schrittmotors

  1. Hallo Bert!
    Vielen Dank für die Fortsetzung der Reihe.
    Gedanklich wäre eine Lösung ideal, welche das Seitenverhältnis der Quelle ausliest (zur Vereinfachung vom Webserver über Kodi) Und die Maskierung automatisch entsprechend anpasst. Hast du hierfür vielleicht eine Anregung wie das ganze umgesetzt werden könnte?

    Grüße Dennis

    1. Hi Dennis,

      das wäre zu ungenau, weil Videos in 16:9 inklusive schwarzen Balken vorliegen können. Ermittlung anhand der Pixel wäre zu aufwendig und ungenau. Und alkes wäre auf Kodi eingeschränkt.

      Ich würde eher dazu neigen, z. B. themoviedb.org anzuzapfen. Müsste man mal sehen, ob die diese Daten vorliegen haben.

      Tendenziell empfinde ich es aber als ausreichend einfach, verschiedene Buttons für die wichtigsten Formate zu haben. Die 2% Filme mit Sonderformaten korrigiert man dann manuell.

      1. pi@raspberrypi:~ $ cd node-v11.15.0-linux-armv6l
        pi@raspberrypi:~/node-v11.15.0-linux-armv6l $ sudo cp -R * /usr/local/
        pi@raspberrypi:~/node-v11.15.0-linux-armv6l $ node -v
        v11.15.0
        pi@raspberrypi:~/node-v11.15.0-linux-armv6l $ npm -v
        6.7.0
        pi@raspberrypi:~/node-v11.15.0-linux-armv6l $ cd
        pi@raspberrypi:~ $ sudo apt-get install git
        Reading package lists... Done
        Building dependency tree
        Reading state information... Done
        git is already the newest version (1:2.20.1-2+deb10u1).
        0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
        pi@raspberrypi:~ $ git clone https://github.com/Heimkino-Praxis/screen-masking.git
        Cloning into 'screen-masking'...
        remote: Enumerating objects: 28, done.
        remote: Counting objects: 100% (28/28), done.
        remote: Compressing objects: 100% (20/20), done.
        remote: Total 28 (delta 6), reused 24 (delta 6), pack-reused 0
        Unpacking objects: 100% (28/28), done.
        pi@raspberrypi:~ $ ls
        Desktop    Music                              Public
        Documents  node-v11.15.0-linux-armv6l         screen-masking
        Downloads  node-v11.15.0-linux-armv6l.tar.gz  Templates
        MagPi      Pictures                           Videos
        pi@raspberrypi:~ $ cd screen-masking
        pi@raspberrypi:~/screen-masking $ npm install
        npm WARN screen-masking@0.0.1 No repository field.
        
        added 51 packages from 38 contributors and audited 51 packages in 38.129s
        found 0 vulnerabilities
        
        pi@raspberrypi:~/screen-masking $ node index.js
        Screen masking app is listening on port 1337
        pi@raspberrypi:~ $ cd screen-masking
        pi@raspberrypi:~/screen-masking $ npm install
        npm WARN screen-masking@0.0.1 No repository field.
        
        added 51 packages from 38 contributors and audited 51 packages in 38.129s
        found 0 vulnerabilities
        
        pi@raspberrypi:~/screen-masking $ node index.js
        Screen masking app is listening on port 1337

        Habs mal mit nem Full Image gemacht. Selber Fehler:

        Cannot GET /force-by/500
        1. Liest sich so weit normal. Das npm install kannst du dir sparen, das Teil ist viel zu einfach gestrickt. Die Warnung beim npm install hat nichts weiter zu bedeuten.

          Ich verstehe immer noch nicht so richtig, wie du zu dem Fehler kommst. Ab der Zeile Screen masking app is listening on port 1337 sollte das Teil laufen, bis du es mit Ctrl+C beendest. Wie versuchst du es denn währenddessen aufzurufen?

  2. Im Browser wird der Tab als Error betitelt. Und auf der Seite steht Cannot GET / (Befehl) Und am Motor tut sich nix.

    Habs jetzt auf mehreren RaspberryPis installiert , in ner X86 VM getestet immer der selbe Fehler.

    Bin irgendwie Ratlos. Das Python Script funktioniert einwandfrei.

        1. Okay, hab das mal geprüft. Zunächst mal ist die URL okay. Die vorherige Info bzgl. „npm install müsse nicht ausgeführt werden“ war falsch – ist aber mal egal, weil die Warnung nichts zu bedeuten hatte und alles gut verlaufen ist.

          Das Problem liegt darin, dass du einen HTTP-PUT ausführen musst. Der Aufruf im Browser wird aber immer ein GET sein. Deshalb binde die URL einfach mal in das System zur Steuerung ein, das du am Ende verwenden willst, und stelle sicher, dass ein PUT ausgeführt wird. Dann müsste das laufen.

          Alternativ solltest du in einem zweiten Konsolenfenster ungefähr das hier ausführen können müssen:

          curl -X PUT http://192.168.2.102:1337/force-by/500

          Ich überlege mir derweil, wo ich den Tipp mit den Browser überall gegeben habe und wie man den Test einfacher machen kann.

          1. Hi,
            mega tolle Beschreibung. Habe den Schrittmotor mit deiner Anleitung innerhalb kürzester Zeit zum Laufen gebracht. Hänge nun allerdings auch am Thema Webinterface mit Node. Deine Pythonskripte sind aktuell unverändert und getestet. Sie funktionieren einwandfrei. Möchte ich sie nun aber mittels Curl aufrufen bekomme ich in der Konsole folgenden Fehler:

            pi@raspberrypi:~/screen-masking $ node index.js
            Screen masking app is listening on port 1337

            PythonShellError: ModuleNotFoundError: No module named ‚RPi‘
            at PythonShell.parseError (/home/pi/screen-masking/node_modules/python-shell/index.js:246:21)
            at terminateIfNeeded (/home/pi/screen-masking/node_modules/python-shell/index.js:129:32)
            at ChildProcess. (/home/pi/screen-masking/node_modules/python-shell/index.js:121:13)
            at ChildProcess.emit (events.js:310:20)
            at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
            —– Python Traceback —–
            File „python/tb6600/force-by.py“, line 1, in
            import stepper
            File „/home/pi/screen-masking/python/tb6600/stepper.py“, line 1, in
            import RPi.GPIO as GPIO {
            traceback: ‚Traceback (most recent call last):\n‘ +
            ‚ File „python/tb6600/force-by.py“, line 1, in \n‘ +
            ‚ import stepper\n‘ +
            ‚ File „/home/pi/screen-masking/python/tb6600/stepper.py“, line 1, in \n‘ +
            ‚ import RPi.GPIO as GPIO\n‘ +
            „ModuleNotFoundError: No module named ‚RPi’\n“,
            executable: ‚python3‘,
            options: null,
            script: ‚python/tb6600/force-by.py‘,
            args: [ ‚500‘ ],
            exitCode: 1
            }

            Im Stepper-Skript wird gleich in der ersten Zeile das
            import RPi.GPIO as GPIO
            bemängelt.
            Könntest du mir da bitte weiter helfen? Danke schon mal.
            Grüße
            Stefan

          2. Hallo Stefan,

            klingt so, als wäre das Python-Modul nicht richtig installiert. Hast du npm install ausgeführt und wurden da irgendwelche Fehler ausgegeben? Gibt es das Verzeichnis node_modules und darin python-shell?

  3. Nein, es wurden keine Fehler ausgegeben, lediglich:
    pi@raspberrypi:~/screen-masking $ npm install
    npm WARN screen-masking@0.0.1 No repository field.
    audited 51 packages in 4.783s
    found 0 vulnerabilities
    Ja, den Ordner Python-Shell gibt es.

    1. Komisch. Funktionieren die Python-Scripts, die sich im Paket befinden? Oder hast du nur die aus dem Artikel getestet? Dieses No module named ‚RPi‘ kommt mir komisch vor. Das ist irgendwas von Python, nicht von Node. Läuft da ein ganz normales Raspbian mit unveränderter Python-Standardinstallation?

      1. Ja, die Skripte aus dem Paket sind getestet und funktionieren. Es klappt lediglich der Aufurf über Node nicht. Ja, es läuft ein normales Raspbian mit Python-Standardinstallation.

        1. Okay, das ist blöd. Vielleicht hilft das weiter, aber vermutlich wird dir das nur sagen, dass das Paket bereits installiert ist.

          Es ist halt komisch, dass es mit dem direkten Aufruf funktioniert, nur über Node nicht. Das lässt vermuten, dass irgendwas mit dem aktuellen „Arbeitsverzeichnis“ nicht richtig ist und dadurch die Pfade durcheinander kommen. Da hilft nur viel ausprobieren und googeln, fürchte ich. 🙁

          1. Vielen Dank für die Antwort. Der Link hat nun tatsächlich weiter geholfen. Nun funktioniert es. Ich habe das Python-Modul neu installiert, wie beschrieben.

  4. Echt klasse deine Beiträge, finde es super das es so Leute wie dich gibt und ihr know how mit anderen teilen.
    Gibt es denn eine Möglichkeit das System über harmony hub zu Steuern? Werde einen raspberry zero w verwenden.

    1. Hallo Jürgen,

      die hier gezeigte Lösung kannst du mit jedem System steuern, das in der Lage ist, HTTP-Requests abzuschicken. Ob das mit dem Harmony Hub geht, weiß ich gerade nicht mit Sicherheit auswendig. Müsste aber eigentlich. Das Teil kann ja auch Philips Hue ansteuern, und das ist technisch gesehen nichts anderes.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Hinweise zur Verarbeitung Deiner Angaben und Widerspruchsrechte: Datenschutzerklärung