Apple Homekit - WS2812B Lichterkette per Raspberry Pi steuern

Apple Homekit - WS2812B Lichterkette per Raspberry Pi steuern

Inzwischen haben wir ja die dunkle Jahreszeit erreicht und viele von euch da draußen stehen vor allen Dingen in dieser Jahreszeit auf ein buntes Farbenmeer an Lichterketten und glitzernden Weihnachtsbäumen. 

Ich persönlich bin der Überzeugung, dass bei Deko weniger mehr ist, allerdings bin ich auch ein Mann. Das liegt wohl in der Natur des Mannes (Ooooh, hat er nicht gesagt!). Nichtsdestotrotz kann auch ich mich nicht aus dem Bann der glitzernden Weihnachtskugeln, Kerzen, Lametta und sonstigem Schnickschnack entziehen. 

Aber was wäre eine Tech Seite mit einem Haufen von DIY Projekten, wenn wir nicht selber ein paar Lichterketten programmieren würden. Vor allen Dingen dann wenn es möglich ist diese Lichterketten auch noch per Apples Smart Home zu steuern. Aus diesem Grund soll sich dieser Artikel darum drehen, wie wir per Apples HomeKit und vielleicht ein paar HomePods oder einfach unserem iPhone das Licht in den schönsten Farben ein und ausschalten können. 

Dieser Artikel soll sich somit darauf beschränken wie wir einen Raspberry Pi so programmieren, dass wir eine WS2812B Lichterkette dynamisch per Sprachbefehl steuern können.

Was werden wir tun?

In erster Linie geht es darum eine Lichterkette per Sprachbefehl steuern zu können. Für dieses Ziel benötigen wir eine Homebridge. Diese Homebridge habe ich auf einem Raspberry Pi Zero W (im Verlauf nur noch "HomeBridge" gennant) installiert. Anleitungen dazu gibt es in Hülle und Fülle. Beispielsweise kann ich diesen Artikel hier wärmstens empfehlen. 

Die installierte Homebridge Instanz wird die Sprachbefehle entgegen nehmen und wird unserem Apple HomeKit (z.b. auf dem iPhone) die entsprechenden Geräte zur Verfügung stellen. Für das Steuern selber benötigen wir innerhalb der Homebridge ein ganz bestimmtes Plugin, welches zwei Funktionen erfüllt:

  1. Den Apple Geräten die Information zur Verfügung stellen, dass es eine steuerbare Lichterkette gibt.
  2. Die Sprachbefehle aus Siri/Homekit an unsere DIY Lichterkette weiterleiten.

Der zweite Raspberry Pi (im Verlauf nur noch "DIY Homekit Lichterkette" gennant), welchen wir im Laufe dieses Artikels aufsetzen und zusammenbauen werden, wird dann das empfangen der Befehle übernehmen. Nach dem Empfang des Befehls wird die DIY Homekit Lichterkette entsprechende Aktionen tätigen, um den angeschlossensn WS2812B LED Strip zu steuern. Als dritte Funktionalität unserer aufgesetzten DIY Homekit Lichterkette wird diese noch Statusinformation über den aktuellen Status der DIY Homekit Lichterkette an die Homebridge zurück liefern, welche ihrerseits wiederum die Information an unsere Apple Geräte weiterleitet. Das klingt im ersten Moment ein wenig kompliziert, wir werden aber gleich noch einmal auf das genaue Konzept eingehen und wer sich beispielsweise bereits den Artikel zu dem Steuern von Thermostaten an über einen Raspberry Pi angeschaut hat, der wird hier viele Parallelen entdecken können.

Vorab - Was benötigen wir?

Wir benötigen folgende Dinge für unser Projekt:

In unserer kleinen Einkaufsliste sind unter Umständen mehr oder auch weniger Dinge enthalten als eigentlich benötigt. Es kommt bei dieser Einkaufsliste tatsächlich eher ganz darauf an welches Netzteil ihr kauft und ob dafür beispielsweise noch ein zusätzliches Kabel mit Kaltgerätestecker gekauft werden muss. Weiterhin kommt es ganz auf euren Anwendungszweck an welchen LED Strip ihr benötigt. Dabei kann es sich um eine richtige Lichterkette, um einen PCB-Kreis oder auf einen klassischen Strip handeln. Was genau ihr kauft ist eigentlich völlig egal. Hauptsache es handelt sich um einen WS2812B fähigen LED Controller. Ein 5050SMD reicht nicht aus, da diese nicht einzeln angesteuert werden können! Die hier gestellte Einkaufsliste mit allen Links dahinter sind in meiner Konfiguration genutzt worden und funktionieren. Alternativen gerne in die Kommentare, da dies sehr individuell sein kann.

Das Konzept

Wie versprochen werde ich jetzt noch einmal auf das grundlegende Konzept eingehen. Wie in dem nachfolgenden Bild ersichtlich ist wird es ein zu steuerndes Gerät geben. Ein weiteres Gerät welches eine einheitliche Schnittstelle für alle zusteuern Geräte bietet und zu guter Letzt mindestens ein Gerät welches steuert. In der Regel ist das Steuergerät ein HomePod, ein iPhone oder ein iPad. Die einheitliche Schnittstelle wird durch einen Homebridge Server zur Verfügung gestellt. Innerhalb dieses Homebridge Servers werden mehrere zu steuernde Geräte konfiguriert, welche im Endeffekt über das lokale Netzwerk wiederum von der Homebridge angesprochen und gesteuert werden. Dabei ist zwischen jedem Gerät und jeder Schicht eine bidirektionale Verbindung aufgebaut. In die eine Richtung wird gesteuert. In die andere Richtung werden Statusinformation übertragen.

Damit unsere DIY HomeKit Lichterkette Befehle entgegen nehmen und Statusinformation zur Verfügung stellen kann muss diese über das lokale Netzwerk angesprochen werden können. In der Regel bietet sich hierfür ein HTTP Server an. Ich habe mich an dieser Stelle für einen Apache Server entschieden, da ich mit diesem bereits sehr gute Erfahrung gemacht habe und mich damit auskenne. Selbstverständlich könnt ihr hier auch einen NGINX Server oder einen ähnlichen Server auf eurem Raspberry Pi installieren. Die Konfiguration dieser Servers werde ich hier in diesem Artikel aber nicht abdecken können. 

Aus Sicherheitsgründen hat unser Apache Server allerdings keinerlei Zugriffsrechte dazu einen GPIO Pin zu steuern. Diese GPIO Pins benötigen wir allerdings um unseren LED Strip ansteuern zu können. Aus diesem Grund wird es ein zusätzliches Skript auf der DIY Lichterkette geben, welches Informationen von unserem Apache Server per JSON-Datei erhält und die entsprechende Steuerung der WS2812B Lichterkette übernimmt. Noch einmal eine Schicht mehr :(, aber was solls. Hauptsache es blinkt am Ende zuverlässig wie eine Bordelltür.

Raspberry Pi - Apple HomeKit - WS2812B LED Strip - Konzept 

Schaltplan

Wir haben wie immer viel um den heißen Brei herum geredet und bisher noch nichts geschafft. Aus diesem Grund gibt es hier noch einmal zwei verschiedene Schaltpläne. Der erste Schaltplan dient zur Illustration von einem angeschlossenen LED Streifen. Das zweite Schaubild demonstriert eine Verkabelung bei mehreren LED Strips. Diese Differenzierung müssen wir machen, da ein zu langer Strip die ersten LED's des ersten Strips "überfordern" könnte. Ich will gar nicht so stark darauf eingehen. Hier ist das Bild:

Raspberry Pi - Apple HomeKit - WS2812B LED Strip - Schaltplan


Einrichtung

Jetzt wo wir alles mit einander verbunden haben können wir mit der Programmierung beginnen. Hierzu benötigen wir einen bereits eingerichteten Raspberry Pi in der Wunschkonfiguration. Der Pi sollte bereits im Netzwerk eingebunden und am Besten per SSH erreichbar sein. Es ist nicht nötig und vor allem nicht ratsam den Pi über das Internet erreichbar zu machen. Also: 

  1. Raspberry Pi OS auf die SD Karte
  2. Mit W-Lan oder Ethernet verbinden
  3. SSH aktivieren
  4. Raspberry Pi wie oben beschrieben verdrahten

Nun können wir fürs Erste folgende Befehle der Reihenfolge nach ausführen:

sudo apt update
sudo apt upgrade
sudo apt install apache2 php7.3 libapache2-mod-php7.3 
sudo apt install git scons swig gcc make build-essential python-dev zip
sudo service apache2 start


Nun erstellt ihr bitte eine Datei mittels dieses Befehls und tragt dort den nachfolgenden Inhalt ein:

sudo nano /etc/modprobe.d/snd-blacklist.conf

blacklist snd_bcm2835

Für einige Geräte scheint es auch noch nötig zu sein folgende Einträge in der Datei “/boot/config.txt” zu ändern/erstellen:

sudo nano /boot/config.txt

hdmi_force_hotplug=1
hdmi_force_edid_audio=1

Die Vorbereitungen sind getroffen. Nun benötigen wir das Programm zum Schalten der LEDs. Führt folgende Befehle aus und es sollte sich nach einigen Sekunden der LED Streifen mit lauter Farben melden:

git clone https://github.com/jgarff/rpi_ws281x
cd rpi_ws281x/
sudo scons
sudo ./test

Wenn nicht alle LED's leuchten sollten, dann ist das kein Problem. Wir ändern das bald.
Wir werden gleich ein eigenes Python Skript erstellen. Vorher ist noch ein wenig Zuarbeit nötig:

cd python
sudo python setup.py build
sudo python setup.py install
cd ~
sudo nano led-client.py

In dieser neuen Datei fügen wir folgendes ein:

#!/usr/bin/env python3
# Staticfloat.de - 2020

import time
from neopixel import *
import argparse
import json

# LED strip configuration:
LED_COUNT = 60 # Anzahl der LED's.
LED_PIN = 18 # GPIO pin
LED_FREQ_HZ = 800000 # LED Frequenz
LED_DMA = 10 # DMA channel
LED_BRIGHTNESS = 255 # 0 = aus; 255 = volle Helligkeit
LED_INVERT = False 
LED_CHANNEL = 0 
JSON_PATH = "/var/www/html/led-server-homekit/befehl.json"

def colorWipe(strip, color, wait_ms=50):
	for i in range(strip.numPixels()):
		strip.setPixelColor(i, color)
	strip.show()
	time.sleep(wait_ms/1000.0)

# Main program logic follows:
if __name__ == '__main__':
	strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
	strip.begin()
	
	try:
		while True:
			try: 
				f = open(JSON_PATH, "r")
				json_string = ''.join(f.read().split('\n'))
				commands = json.loads(json_string)
				
				if commands['power'] == 1:
					colorWipe(strip, Color(commands['color_g'], commands['color_r'], commands['color_b']), 20);
					strip.setBrightness(commands['brightness']);
					strip.show()
				else:
					colorWipe(strip, Color(0,0,0), 10)
			except: 
				print("JSON ERROR") 
			
	except KeyboardInterrupt:
		colorWipe(strip, Color(0,0,0), 10)

Eigentlich haben wir es mit diesem bisschen Programmierung schon fast geschafft. Unser Skript kann nun den LED Streifen ansteuern und je nachdem was in der entsprechenden Datei (befehl.json) an Befehlen enthalten ist werden diese auch ausgeführt.
Was heißt denn jetzt "fast geschafft"? - Nun ja, was uns jetzt noch zur Komplettierung des gesamten Projektes fehlt ist die Schnittstelle zu unserer Homebridge und dessen Konfiguration. Wie bereits mehrfach erklärt muss die HomeBridge die Möglichkeit haben Befehle an den die DIY HomeKit Lichterkette zu senden und auch dessen Status abzufragen. Außerdem müssen wir unser kleines Script bei jedem Start des Raspberry Pi mit starten. Die können wir bewerkstelligen, indem wir ...

sudo nano /etc/rc.local

... eingeben und diesen Befehl in die Datei einfügen (VOR das "exit 0") ...

sudo PYTHONPATH=".:build/lib.linux-armv7l-2.7" python /home/pi/led-client.py

Einen Server haben wir uns bereits installiert gehabt. Hat niemand gemerkt? Ich bin aber auch sneaky :P
Was wir benötigen ist nun "nur" noch das entsprechende Skript für die Statusabfrage und den Befehlsempfang und selbstverständlich noch zusätzliche Schreibrechte in die "befehl.json"-Datei.
Wir geben also ein:

cd /var/www/html/
sudo wget https://staticfloat.de/content/led-server-homekit.zip
sudo unzip led-server-homekit.zip
cd led-server-homekit/
sudo chmod 777 led-server-homekit/

Homebridge einrichten

So, jetzt aber! - Wir haben die Einrichtung und Programmierung der DIY Homebridge Lichterkette hoffentlich erfolgreich abgeschlossen. Machen wir uns also ans Werk unsere Homebridge zu konfigurieren. Im Übrigen ist dies der letzte Schritt auf unserem Weg zur Erleuchtung :D

Für die Konfiguration müssen wir uns auf die Homebridge aufschalten. Am Besten geht dies über die Administrationskonsole im Browser. Bei mir hat die Homebridge eine statische lokale IP-Adresse bekommen und kann z.b. über folgende "URL" aufgerufen werden: 

http://192.168.178.35:8080/login

Das mag bei euch anders sein! Schaut im Zweifelsfalle einmal in den Router und schaut euch die verbundenen Geräte an. Unter einer Fritzbox geht dies zum Beispiel über Heimnetz -> Netzwerk -> Eintrag mit einem entsprechenden Namen. 
Fritzbox - Homebridge - Verbundene Geräte

Hat man sich in die Homebridge eingeloggt, so müssen wir als Erstes ein Plugin installieren, welches uns die Kommunikation mit einem über HTTP steuerbaren LED Streifen erlaubt.
Klickt auf Plugins -> geht in das Suchfeld "Homebridge Better Http Rgb" ein -> Installieren. Bei mir ist das Plugin bereits installiert, deshalb wird es bereits in der installierten Liste angezeigt.

Dieser Vorgang kann etwas dauern, aber wenn das Plugin erst einmal installiert ist geht es mit der Konfiguration weiter.
Hierzu klicken wir auf Konfiguration -> fügt unten stehende Konfiguration ein -> Speichern -> Homebridge neustarten

Hier eine Beispielkonfiguration, welche jedoch um die IP Adresse der eigenen DIY Homebridge Lichterkette erweitert werden muss:

........
    "accessories": [
    ...... hier stehen andere Konfigurationen ......
        {
            "accessory": "HTTP-RGB",
            "name": "Licht",
            "service": "Light",
            "switch": {
                "status": "http://[IP der DIY Homebridge Lichterkette]/led-server-homebridge?action=status",
                "powerOn": "http://[IP der DIY Homebridge Lichterkette]/led-server-homebridge?action=on",
                "powerOff": "http://[IP der DIY Homebridge Lichterkette]/led-server-homebridge?action=off"
            },
            "brightness": {
                "status": "http://[IP der DIY Homebridge Lichterkette]/led-server-homebridge?action=brightness",
                "url": "http://[IP der DIY Homebridge Lichterkette]/led-server-homebridge?action=brightness&value=%s"
            },
            "color": {
                "status": "http://[IP der DIY Homebridge Lichterkette]/led-server-homebridge?action=color",
                "url": "http://[IP der DIY Homebridge Lichterkette]/led-server-homebridge?action=color&value=%s",
                "brightness": false
            }
        }
.....

Und das wars dann tatsächlich auch schon. Ich wünsche viel Spaß beim Schalten und Walten eures neuen Lichts. Wem hier kein Licht aufging, der kann gerne einen Kommentar hinterlassen. Ich wünsche frohe Weihnachten.

Update 15.01.2021:

Vielen Dank für den hilfreichen Kommentar von Tim. Leider habe ich innerhalb des originalen Artikels schlampig gearbeitet und mir sind einige Fehler unterlaufen. Diese wurden durch Tim freundlicherweise korrigiert. Zusätzlich habe ich das Python Skript mit in die Zip (https://staticfloat.de/content/led-server-homekit.zip) gepackt, so dass Einrückungsfehler (ein großes Problem bei Python) beim Kopieren kein Problem mehr sind. 

Marvin

Ich bin ein Mensch, der sich neben der Programmierung noch für tausend andere Dinge interessiert, die mal mehr und mal weniger verrückt sind. Vor allem aber bin ich Feuer und Flamme mit der Programmierung von eigenen kleinen Apps und Programmen, die mein Leben bereichern.

Hat dir dieser Artikel gefallen?

Kommentar hinzufügen

*Pflichtfeld

  1. Tim

    Ich war lange auf der Suche nach einer Lösung um meine WS2812b über Homekit zu steuern. Super Anleitung, Vielen Dank!

    Die folgende Änderungen musste ich noch vornehmen, damit es bei mir funktioniert:

    1. in der befehl.json sind am Ende zu viele Zeichen (,") vor der geschweiften Klammer -> müssen entfernt werden, sonst wirft die led-client.py einen Fehler

    2. der JSON_PATH in led-client.py muss auf "/var/www/html/led-server-homekit/befehl.json" geändert werden

    3. in der index.php muss Zeile 19 ($data->special = ""; ) gelöscht werden, da sonst der Eintrag special="" in der befehl.json vermerkt wird und die led-client.py einen Fehler wirft bzw. abstürzt

    4. Es kann passieren, dass die led-client.py genau in dem Moment versucht die befehl.json auszulesen, wenn der Web-Server diese gerade ändert. In diesem Fall stürzt die led-client.py ab und muss neugestartet werden. Um diesen Fall abzufangen, bietet sich der Einbau einer exception an:

    [...]
    try:
    while True:
    try:
    f = open(JSON_PATH, "r")
    json_string = ''.join(f.read().split('\n'))
    commands = json.loads(json_string)

    if commands['power'] == 1:
    colorWipe(strip, Color(commands['color_g'], commands['color_r'$
    strip.setBrightness(commands['brightness']);
    strip.show()
    else:
    colorWipe(strip, Color(0,0,0), 10)
    except:
    print("JSON ERROR")

    except KeyboardInterrupt:
    colorWipe(strip, Color(0,0,0), 10)

  2. Marvin

    Hallo Tim,

    vielen Dank für deine Hilfe und Mühe die Fixes in einen Kommentar zu verpacken. Ich habe in der Tat meinen ursprünglichen Code etwas gekürzt, damit nur die "Grundfunktionalitäten" mit in den Artikel wandern. Ursprünglich wurde durch das Skript noch eine zusätzliche "specialFunction" ausgeführt, welche im Schlafzimmer einen Lichtwecker per Siri realisiert. Scheinbar ist mir beim Ausschneiden der Funktion ein Fehler unterlaufen.
    Das Exceptionhandling ist eine grandiose Erweiterung! Vielen Dank! Ich hatte leider die letzten Wochen keine Zeit diesen Fehler zu beheben.

    Ich werde deine Anmerkungen versuchen noch heute Abend in den SourceCode einfließen zu lassen und neu hochzuladen, damit alle anderen nicht mehr in diese Fehler laufen.
    Ich sitze aktuell auch daran noch eine weitere Variante zu erstellen, die mit einem ESP32 statt einem Raspberry Pi Zero läuft.

    Gruß
    Marvin