Bastian Raschke
Nils Tegetmeyer

Sicherheitskritisch

A blog about IT security and electronics

IoT-Stimmungslicht mit ESP8266 steuerbar über Internet via iOS-App

Written by Bastian Raschke.
Published 2016-08-31 in the category Smart Home.

This article is available in more than one language.
Available translations: en

In meinem letzten Artikel habe ich bereits ein cooles RGB-Stimmungslicht mit einem Raspberry Pi und einer Web-App realisiert. Allerdings hat es mich im täglichen Gebrauch gestört, dass immer ein komplettes Linux auf dem Pi läuft, dabei unnötig 5 Watt verbraucht und das System auch nicht ohne schlechtes Gewissen schnell mal aus der Steckdose gezogen werden kann, ohne korrektes Herunterfahren. Und natürlich hat das Booten auch ca. 30-40 Sekunden gedauert. Alles in allem nicht so mega praxistauglich. Aber dann habe ich den ESP8266 kennengelernt.

ESP8266 - perfekt für IoT

Der ESP8266 war für mich anfänglich nur ein Bauteil, mit dem ich einen Arduino an WLAN anbinden kann. Nach meinen weiteren Nachforschungen und Tests habe ich dann erfahren, dass dieses kleine beliebte Bauteil, dass es bei Ebay für 3-8€ zu kaufen gibt, völlig autonom ohne einen Arduino läuft. Und das Beeindruckende dabei ist, dass der ESP8266 trotz des geringen Preisen viel mehr Leistung als ein kompletter Arduino hat! Satte 1 Megabyte (!) Flash-Speicherplatz stehen für das eigene Programm zur Verfügung (statt nur 32 Kilobyte). Der ESP8266 taktet weiterhin mit 80 MHz und nicht mir 16MHz oder weniger. Und eben das WLAN-Feature gibt es einfach mal dazu. Und bei dem erwähnten Preis ein wahres IoT-Wunder.

Die Krönung des Glücks ist die Tatsache, dass es die Community geschafft hat, den ESP8266 direkt mit der Arduino IDE programmierbar zu machen. Die Einstiegshürden sind also sehr niedrig. Den ESP8266 gibt es in x Ausführungen - ich habe mich für eine Platine entschieden, die einen Seriellwandler und die Spannungsversorgung bereits an Bord hat, sodass die Platine direkt per Micro-USB versorgt und programmiert werden kann. Die "NodeMCU" genannte Platine gibt es mit mehreren USB-Seriell-Wandlern, ich habe mich für die etwas teurere CP2102-Variante entschieden, da ich mit diesem Chip bisher immer gute Erfahrung hatte.

ESP8266 als NodeMCU mit CP2102
ESP8266 als NodeMCU mit CP2102 für ca. 7€

Vernetzt mit MQTT

Nun hatte ich die perfekte Plattform für ein vernetztes VibeLight 2.0. Nun fehlte mir noch ein geeignetes, schmalspuriges Kommunikationsprotokoll. Ich wollte, dass die ESP8266s mit einem Push-Verfahren sofort über eine Änderung informiert werden (um das Licht zu schalten). Anfänglich bin ich zwischen HTTP als Polling-Lösung und Websockets mit nativerem Echtzeit-Push beschwankt. Beides war aber nicht das Gelbe vom Ei. Glücklicherweise habe ich dann von dem MQTT-Protokoll erfahren, dass für IoT-Anwendungen entwickelt wurde und extrem leichtgewichtig ist (also fast keinen Overhead produziert).

Das Protokoll ist derart leichtgewichtig, dass eine Änderung innerhalb von unter einer Sekunde abgewickelt ist - und trotz dass der Broker im öffentlichen Internet steht. Was mich besonders beeindruckt hat, dass dies selbst bei mobilem Internet mit langsamen EDGE (2G) im gleichen Zeitrahmen möglich ist! Bei MQTT können sich N Geräte auf beliebige Channels subscriben oder darauf publishen. Ein zentraler Server (Broker) verwaltet alle Operationen. Der Broker wickelt auch weiterhin die Benutzerauthentifizierung ab. Ich nutze die freie MQTT-Server-Implementierung Mosquitto, die leistungsfähig und detailliert konfigurierbar ist. Für Arduino bzw. den ESP8266 gibt es einige MQTT-Bibliotheken, wobei ich mich für die PubSubClient-Bibliothek von Nick O'Leary entschieden habe.

Eine weitere Vorraussetzung war es für mich als sicherheitsbewussten Entwickler natürlich, dass die Verbindung zwischen dem Broker und den Geräten verschlüsselt erfolgt. Doch auch hierfür dank der Community bereits eine Lösung, sodass Verbindungen seitens des ESP8266 mit TLS 1.1 abgesichert werden können. Dabei musste ich die oben erwähnte PubSubClient-Bibliothek minimal verändern, sodass der Fingerprint des TLS-Zertifikats auch verifiziert wird - ansonsten wären MITM-Angriffe problemlos möglich.

Beliebig viele vernetzte Lichtaktoren

Dadurch dass sich N Clients auf dem gleichen Channel subcriben können, ist es möglich, nahezu unbegrenzt viele Lichtaktoren in seiner Wohnung aufzustellen. Wenn man auf einen Channel published (z.B. welche Lichtszene man wünscht), erhalten sofort an alle Clients, die auf dem Channel subcribed sind, die Nachricht, ihre Lichtszene zu ändern. Ich habe die Firmware in der Art geschrieben, dass sowohl Lichtstreifen für indirekte Beleuchtung als auch z.B. Lampen mit weniger LEDs möglichst gleich cool aussehen. Es gibt verschiedene Lichtszenen (z.B. Farbverlauf, halbierte Farben): die Lichtszene definiert lediglich in welchem Muster die LEDs geschaltet werden, die eigentlichen Farben sind jedesmal frei setzbar ohne eine Firmwareänderung.

Aufbau der Hardware

Ich habe zwei Lichtaktoren gebaut: Meine bestehende Lichtleiste wurde umgerüstet und zusätzlich habe ich noch eine Ikea Fado-Lampe umgerüstet mit dem VibeLight 2.0-System. So sehen die Komponenten aus:

Umgerüstete Lichtleiste mit VibeLight 2.0 Umgebaute Ikea Fado-Lampe mit VibeLight 2.0
Umgerüstete Lichtleiste und umgebaute Ikea Fado-Lampe mit VibeLight 2.0

Die geöffnete Hardware der Ikea Fado-Lampe:

Innenleben der umgebauten Ikea Fado-Lampe - Vorderseite Innenleben der umgebauten Ikea Fado-Lampe - Rückseite
Innenleben der umgebaute Ikea Fado-Lampe

Das Innenleben der Lichtleiste:

Innenleben der umgerüsteten Lichtleiste Absteckbare Lichtleiste
Innenleben der umgerüsteten Lichtleiste und absteckbare Lichtleiste

Beide Lichter verwenden nahezu die identische Platine, wobei ich bei der Lichtleiste ja bereits aus Version 1 ein 1000µF-Kondensator verbaut war, weswegen dieser auf der Platine nicht angelötet wurde. Hier seht ihr hingegen die vollausgestattete Platine mit dem Kondensator:

Vollausgebaute Platine von VibeLight 2.0
Die Platine von VibeLight 2.0 im Vollausbau

Einrichtung von Mosquitto

Zunächst installiert ihr Mosquitto:

~# apt-get install mosquitto

TLS-Zertifikate erzeugen

Zunächst erzeugt ihr einen Schlüssel und Zertifikat für eure Zertifizierungsstelle (CA). Dies ist leider nötig:

~# echo "01" > "/etc/mosquitto/ca_serial.txt"
~# openssl ecparam -genkey -name prime256v1 -noout -out "/etc/mosquitto/ca.key" -outform PEM
~# openssl req -new -x509 -days 3650 -subj "/CN=VibeLight 2.0 CA" -key "/etc/mosquitto/ca.key" -out "/etc/mosquitto/ca.crt" -outform PEM

Nun erzeugt ihr den Schlüssel und das Zertifikat für eure eigentliche Server-Domain:

~# openssl ecparam -genkey -name prime256v1 -noout -out "/etc/mosquitto/mqtt.sicherheitskritisch.key" -outform PEM
~# openssl req -new -subj "/CN=mqtt.sicherheitskritisch.de" -key "/etc/mosquitto/mqtt.sicherheitskritisch.key" -out "/etc/mosquitto/mqtt.sicherheitskritisch.csr"
~# openssl x509 -req -days 3650 -CA "/etc/mosquitto/ca.crt" -CAkey "/etc/mosquitto/ca.key" -CAserial "/etc/mosquitto/ca_serial.txt" -in "/etc/mosquitto/mqtt.sicherheitskritisch.csr" -out "/etc/mosquitto/mqtt.sicherheitskritisch.crt"

Wichtig: Der Wert mqtt.sicherheitskritisch.de in den Befehlen ist natürlich beispielhaft für meinen Server gedacht und muss jeweils an eure Gegebenheiten angepasst werden.

Nun wollen wir für einen späteren Schritt noch den SHA1-Fingerprint eueres Zertifikates ausgeben:

~$ openssl x509 -in /etc/mosquitto/mqtt.sicherheitskritisch.crt -outform DER | sha1sum | cut -c 1-42 | fold -w 2 | paste -s -d ' '

Der Befehl sollte etwas in der folgenden Art ausgeben:

57 36 77 fe e4 3e a9 ae c2 3c 33 dc 60 82 56 18 18 4d 60 50

Konfiguration anpassen

Nun wird direkt die Konfiguration /etc/mosquitto/mosquitto.conf wie folgt geändert:

bind_address mqtt.sicherheitskritisch.de
port 8883

pid_file /var/run/mosquitto.pid
log_dest file /var/log/mosquitto/mosquitto.log

persistence true
persistence_location /var/lib/mosquitto/


cafile /etc/mosquitto/ca.crt
certfile /etc/mosquitto/mqtt.sicherheitskritisch.crt
keyfile /etc/mosquitto/mqtt.sicherheitskritisch.key

## The cipher "AES256-SHA" is the highest cipher that the ESP8266 supports
ciphers ECDHE-RSA-AES256-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:AES256-SHA

## The ESP8266 supports only TLS 1.1 or below
tls_version tlsv1.1


allow_anonymous false
password_file /etc/mosquitto/passwd


## Include other configurations /etc/mosquitto/conf.d/*.conf
include_dir /etc/mosquitto/conf.d

Bei der Angabe bind_address müsst ihr natürlich die IP-Adresse oder Domain eures Servers angeben. Weiterhin muss bei certfile und keyfile der Pfad zu eurem TLS-Zertifikat bzw. Schlüssel angepasst werden.

Dann werden 2 spätere Benutzerzugänge angelegt:

~# mosquitto_passwd -U /etc/mosquitto/passwd bastian
~# mosquitto_passwd -U /etc/mosquitto/passwd device_abcdefghijklm

Der erste Benutzer bastian wird später in der App verwendet, der Benutzer device_abcdefghijklm wird euer erster Lichtaktor sein. Vergebt jeweils unterschiedliche Passwörter für die Benutzer.

Abschließend kann Mosquitto neugestartet werden:

~# systemctl restart mosquitto

Flashen der Firmware

Die Firmware wird per Arduino IDE auf den ESP8266 geflasht. Wie ihr die Arduino IDE für die ESP8266-Hardware nutzbar macht, ist im Internet an vielen Stellen zu lesen, weswegen ich dies hier nicht erneut erläutern werde. Für den NodeMCU habe ich in der Arduino-IDE die folgende Flash-Konfiguration genutzt:

Wert
Platine: NodeMCU 1.0 (ESP-12E Module)
CPU Frequency: 80 Mhz
Flash Size: 4M (1M SPIFFS)
Upload Speed: 115200

Aber bevor ihr die Firmware flasht, müsst ihr noch einige Werte in der Firmware an eure Gegebenheiten anpassen:

#define WIFI_SSID                   "YOUR_WIFI_SSID"
#define WIFI_PASSWORD               "YOUR_WIFI_PASSWORD"

#define MQTT_CLIENTID               "Vibelight Device 1.0 xxxxxxxxxxxxx"
#define MQTT_SERVER                 "mqtt.sicherheitskritisch.de"
#define MQTT_SERVER_TLS_FINGERPRINT "57 36 77 fe e4 3e a9 ae c2 3c 33 dc 60 82 56 18 18 4d 60 50"
#define MQTT_PORT                   8883
#define MQTT_USERNAME               "device_abcdefghijklm"
#define MQTT_PASSWORD               "YOUR_MQTT_PASSWORD"

...

#define NEOPIXELS_COUNT             60

Zunächst müsst ihr bei WIFI_SSID und WIFI_PASSWORD eure korrekten WLAN-Zugangsdaten eintragen, damit der ESP8266 mit dem Internet kommunizieren kann. Bei MQTT_CLIENTID solltet ihr die x-Platzhalter gegen eine beliebige alphanumerische Zeichenkette austauschen. Bei MQTT_SERVER müsst ihr die öffentlich erreichbare Adresse eures MQTT-Brokers angeben. Mit der Angabe MQTT_SERVER_TLS_FINGERPRINT erfolgt der mit Leerzeichen getrennte SHA1-Fingerprint des TLS-Zertifikates eures Servers (diesen haben wir uns bei der Zertifikatserstellung bereits ausgeben lassen). Und natürlich müsst ihr bei MQTT_USERNAME und MQTT_PASSWORD die korrekten MQTT-Benutzerdaten eingeben, damit sich eurer Gerät dem Server gegenüber authentisieren kann.

Wichtig: Für jedes Gerät muss ein unterschiedlicher MQTT-Benutzer sowie eine eigene Client-ID genutzt werden, wenn beide Geräte parallel funktionieren sollen! Ansonsten funktioniert die Anmeldung auf beiden Geräten nicht!

Und abschließend tragt ihr bei NEOPIXELS_COUNT die Anzahl der verwendeten LEDs eures Lichtaktors ein.

Erster Funktionstest

Wenn das Flashen abgeschlossen ist, dann könnt ihr euren Lichtaktor nun testen. Ich empfehle das Aktivieren des seriellen Monitors um eventuell auftretende Fehler (z.B. falsche Benutzerdaten) nachvollziehen zu können. Ich empfehle euch auf euren Rechner das Paket mosquitto-clients zu installieren, damit ihr das Kommandozeilenprogramm mosquitto_pub zum testen nutzen könnt:

~$ mosquitto_pub -h mqtt.sicherheitskritisch.de -p 8883 \
    -u "YOUR_MQTT_USERNAME" \
    -P "YOUR_MQTT_PASSWORD" \
    --tls-version tlsv1.1 \
    --cafile /path/to/ca.crt \
    -t '/vibelight/api/1.0/' \
    -m '2A92CCECE2C2C'

Mit diesem Befehl sendet ihr an alle angeschlossenen VibeLight-Geräte den Befehl, Lichtscene 2 (halbierte Farben) mit den beiden Farben 0xA92CCE und 0xCE2C2C anzuzeigen (Parameter -m mit 2A92CCECE2C2C).

Wichtig: Wie immer müsst ihr natürlich die Adresse eures Brokers anpassen und bei --cafile müsst ihr dieselbe Datei /etc/mosquitto/ca.crt nutzen, die bei dem "TLS-Zertifikate erzeugen"-Schritt erstellt wurde.

iOS-App installieren

Zunächst müsst ihr "Cocoapods" installiert haben (die Installation sollte auf der Herstellerseite beschrieben sein). Mit eurem Xcode (ich habe mit Version 7.3.1 gearbeitet) öffnet ihr das Projekt VibeLight.xcworkspace. Vermutlich müsst ihr dann noch euer Entwicklerzertifikat für das Projekt konfigurieren. Und dann solltet ihr die App auf euer iOS-Gerät überspielen und starten können.

Notwendige Anpassungen

Einige Werte in der App sind zurzeit noch hardkodiert:

  1. Die IP-Adresse/Domain des MQTT-Brokers in der Datei MQTTConnection.swift
  2. Das Root-Zertifikat der CA (aktuell die Datei VibeLight/Resources/KlosterTrust_Root_CA.crt) und referenziert ebenfalls in der Datei MQTTConnection.swift. Hier müsst ihr dieselbe Datei /etc/mosquitto/ca.crt nutzen, die bei dem "TLS-Zertifikate erzeugen"-Schritt erstellt wurde.

Beide Werte müsst ihr natürlich anpassen an eure Gegebenheiten.

Die Constraints in dem SettingsViewController nicht korrekt gesetzt, sodass die Eingabefelder nicht in der Mitte ausgerichtet sind. Da ich aber gerade kein MacBook zur Verfügung habe, lässt sich das nicht ändern ;-)

Folgend seht ihr ein paar Screens der App:

Startbildschirm Hauptbildschirm

Viel Spaß mit dem Projekt :-)

Quellcode auf Github

Der Quellcode kann via Github bezogen werden:

VibeLight 2.0 auf Github


Tags: LED, WS2812B, ESP8266, DIY, Internet of Things, IOT, MQTT

Proudly generated with Pelican - without PHP, Perl, MySQL & Co. Jump to top