In diesem Beitrag zeige ich dir, wie du mit dem Arduino Plug and Make Kit eine vielseitige DIY-IoT-Lösung umsetzen kannst. Am Beispiel einer Shelly DUO Lampe lernst du, smarte Geräte über externe Komponenten wie Taster, Sensoren oder Potentiometer zu steuern. Dabei erfährst du, wie du REST-Schnittstellen mit dem Arduino nutzen kannst – eine Methode, die sich leicht auf zahlreiche andere Projekte und Geräte übertragen lässt.
Zum Arduino Plug and Make Kit habe ich dir bereits einige Beiträge veröffentlicht und auch gezeigt, wie einfach es ist, mit diesem Kit in die Welt der Mikrocontrollerprogrammierung einzutauchen.
- Arduino Plug and Make Kit: Richtungsanzeige mit Modulino Movement
- Arduino Plug and Make Kit: Abstandskontrolle mit Alarmfunktion
- Einsteigerprojekt: Pixel Chaser mit dem Arduino Plug and Make Kit
- Arduino Plug and Make Kit: Was ist drin und wie benutzt man es?
Für diesen Beitrag verwende ich die Shelly DUO Lampe, die in zwei Varianten erhältlich ist: eine einfache Version mit Funktionen zur Helligkeits- und Farbintensitätssteuerung, wie ich sie verwende, und eine RGB-Version, bei der auch die Farbe individuell eingestellt werden kann.
Inhaltsverzeichnis
- Ziel dieses IoT-Projektes
- Was wird für dieses IoT Projekt benötigt?
- Aufbau der Schaltung
- Regeln der Shelly DUO Lampe über den Arduino
Ziel dieses IoT-Projektes
Das Ziel dieses Projektes ist es aufzuzeigen, wie man ein smartes Gerät wie die Shelly DUO Lampe vom Arduino aus steuern kann. Dabei verwende ich den Arduino UNO R4 WiFi welcher über einen ESP32-S3 Chip verfügt, welcher diesem Mikrocontroller die Bluetooth und auch WiFi Features hinzufügt.
Alternativ kannst du dieses auch über die Arduino Cloud lösen, dann kannst du diese über ein Dashboard steuern, dazu kommt aber ein separater Beitrag.
Was wird für dieses IoT Projekt benötigt?
Wenn du dieses IoT-Projekt nachbauen möchtest, dann benötigst du:
- einen Arduino Plug and Make Kit*
- ein USB-Typ-C Datenkabel*
- eine Shelly DUO* Lampe
- ein E26 Sockel**
- eine 2Adrige Zuleitung**
Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!
** Der E26 Sockel sowie die Zuleitung, bekommst du im örtlichen Baumarkt sehr günstig und daher kann ich dir hier keinen günstigen Link zum kauf anbieten.
Aufbau der Schaltung
Die Schaltung am Arduino ist recht einfach, ich verwende hier wie erwähnt das Arduino Plug and Make Kit. Dieses Kit enthält alles, was du auf der Seite des Arduino benötigst. Die Shelly DUO Lampe benötigt hier lediglich einen E26 Sockel, welche wir einzeln im Baumarkt erhalten und über eine 2Adrige Zuleitung mit Strom versorgt wird.
Durch die Qwiic Schnittstelle am Arduino UNO R4 WiFi ist der Aufbau sehr einfach. Die Aktoren in der Schaltung werden hintereinander mit den entsprechenden Kabeln angeschlossen und via I2C programmiert.
Regeln der Shelly DUO Lampe über den Arduino
Starten wir nun und regeln zunächst die Shelly DUO Lampe über den Arduino (später werde ich dir zeigen wie dieses über die Arduino Cloud abläuft). Die smarten Geräte von Shelly bieten hierzu eine kleine REST Schnittstelle, welche wir bedienen können. Das Coole daran, wir benötigen hier keine Authentifizierung, solange wir im selben Netzwerk sind und keine gesetzt sind. (Über die Shelly-Cloud können wir auch von außen darauf zugreifen, dieses ist jedoch nicht Bestandteil von diesem Beitrag.)
Auf der Seite UNO R4 WiFi Network Examples finden wir eine sehr ausführliche Dokumentation wie man am Arduino UNO R4 WiFi eine Http Anfrage absendet, jedoch war dieses für die Verbindung zum Shelly nicht möglich. Ich habe nach einigem experimentieren mit der Bibliothek vom GitHub Repositiory arduino-libraries/ArduinoHttpClient erfolgreich geschafft die Lampe zu steuern.
Das fertige Programm zum regeln einer Shelly DUO Lampe via Arduino UNO R4 WiFi findest du nachfolgend als ZIP-Datei zum download.
Schritt 1 – REST Schnittstelle der Shelly DUO Lampe ansprechen
Bevor wir vom Arduino die HTTP Anfragen absenden können, müssen wir diese erst einmal ermitteln.
In der offiziellen API-Dokumentation der Shelly DUO Lampe (https://shelly-api-docs.shelly.cloud/gen1/#shelly-duo) finden sich die URLs, mit denen die Lampe direkt über den Browser gesteuert werden kann.
- den Status der Lampe auslesen > http://<IP-Adresse>/status
- eine Eigenschaft setzen > http://<IP-Adresse>/light/0?
- turn – on / off
- brightness – setzen der Helligkeit von 0 bis 100
- temp – setzen der Temperatur der Lampe von 2700 Kelvin bis 6500 Kelvin
Beispiele
Auslesen des Status der Shelly DUO Lampe
Die Adresse zum Auslesen des Status der Shelly DUO Lampe ist http://192.168.178.195/status, die Ausgabe ist im JSON-Format. In der Ausgabe können wir diverse Schlüssel / Werte paare ablesen, wo wir die derzeitige Konfiguration und den Zustand auslesen können.
Im Grund interessiert uns hier lediglich der Abschnit „lights“, dort finden wir, ob diese aktiviert ist (ison) welche Helligkeit (brightness) sowie Farbtemperatur (temp) gesetzt ist.
"lights": [{
"ison": true,
"source": "http",
"has_timer": false,
"timer_started": 0,
"timer_duration": 0,
"timer_remaining": 0,
"brightness": 80,
"white": 0,
"temp": 2700,
"transition": 0
}],
Aktivieren / Deaktivieren der Lampe
Die Lampe lässt sich durch eine Adresse aus dem Browser aktivieren und deaktivieren, dazu nutzen wir die Adresse http://192.168.178.195/light/0 und hängen den Parameter turn mit dem Wert off für AUS bzw. on für AN.
Als Antwort erhalten wir ebenso ein JSON mit dem neuen Zustand der Lampe.
Setzen mehrerer Werte über einen HTTP Request
Wie das aktivieren / deaktivieren können wir die Farbtemperatur (Parameter temp) und die Helligkeit (Parameter brightness) ebenso über die Adresse setzen. Dazu verketten wir in der Adresse die Parameter mit einem & Symbol.
Ein Problem beim Absenden von mehreren Werten mit einer HTTP Anfrage ist, dass im Fehlerfall ein Text analysiert werden muss. Das macht das ganze bei der Programmierung etwas aufwändiger, daher sende ich im späteren Programm die Eigenschaften einzeln ab und werte die Antwort aus.
Schritt 2 – Aufbau einer WiFi Verbindung am Arduino UNO R4 WiFi
Damit wir eine HTTP Anfrage an die Shelly Lampe senden können, müssen wir uns im selben WiFi Netzwerk befinden. Dazu bauen wir diese erst einmal auf.
#include "WiFiS3.h" #define WIFI_SSID "abc" #define WIFI_PWD "123" int status = WL_IDLE_STATUS; void setup() { Serial.begin(115200); Serial.print("Aufbau der Verbindung zu: "); Serial.println(WIFI_SSID); while (status != WL_CONNECTED) { status = WiFi.begin(WIFI_SSID, WIFI_PWD); Serial.print("."); delay(500); } Serial.println(); Serial.print("Verbindung erfolgreich zu "); Serial.print(WIFI_SSID); Serial.println(" aufgebaut!"); Serial.print("IP-Adresse: "); Serial.println(WiFi.localIP()); } void loop(){}
Schritt 3 – Absenden einer HTTP Anfrage an die Shelly DUO Lampe vom Arduino
Für das Absenden einer HTTP Anfrage vom Arduino UNO R4 WiFi verwende ich die Bibliothek ArduinoHttpClient welche wir über den Bibliotheksverwalter installieren können.
Dazu öffnen wir den Bibliotheksverwalter (1) und suchen zunächst nach „ArduinoHttp“ aus den Suchergebnissen wählen wir die Schaltfläche INSTALLIEREN (3) am Eintrag „ArduinoHttpClient von Arduino“.
Abfragen des Status der Shelly DUO Lampe
Starten wir zunächst mit einer einfachen Anfrage an die Shelly Lampe, um den Status abzufragen. Dazu rufen wir via HTTP GET die Adresse <IP-Adresse>/status auf.
#include <ArduinoHttpClient.h> #include "WiFiS3.h" #define WIFI_SSID "abc" #define WIFI_PWD "123" char serverAddress[] = "192.168.178.195"; WiFiClient wifi; HttpClient client = HttpClient(wifi, serverAddress, 80); int status = WL_IDLE_STATUS; void setup() { Serial.begin(115200); Serial.print("Aufbau der Verbindung zu: "); Serial.println(WIFI_SSID); while (status != WL_CONNECTED) { status = WiFi.begin(WIFI_SSID, WIFI_PWD); Serial.print("."); delay(500); } Serial.println(); Serial.print("Verbindung erfolgreich zu "); Serial.print(WIFI_SSID); Serial.println(" aufgebaut!"); Serial.print("IP-Adresse: "); Serial.println(WiFi.localIP()); readShellyDuoStatus(); } void readShellyDuoStatus() { if (WiFi.status() == WL_CONNECTED) { client.get("/status"); printHttpResponse(); } } int printHttpResponse() { int statusCode = client.responseStatusCode(); Serial.print("HttpStatus Code: "); Serial.println(statusCode); if (statusCode == 200) { String response = client.responseBody(); Serial.print("Antwort: "); Serial.println(response); } client.stop(); return statusCode; } void loop() {}
Die Ausgabe des Status im JSON-Format erfolgt beim obigen Code auf der seriellen Schnittstelle. Von diesem können wir nachfolgende Status / Wert ablesen:
Setzen einer Eigenschaft an der Shelly DUO Lampe
Die Shelly DUO Lampe benötigt einige Sekunden, bis der neue Wert umgesetzt wird. Daher ist das Regeln der Helligkeit / Farbtemperatur über den Rotary Encoder etwas stockend.
Für das Setzen einer Eigenschaft wie Helligkeit und Farbtemperatur rufen wir die Adresse http://<IP-Adresse>/light/0 mit dem jeweiligen Parameter auf. Dabei musst du auf den jeweiligen Gültigkeitsbereich der Werte achten.
min. Wert | max. Wert | |
---|---|---|
Helligkeit | 0 | 100 |
Temperatur | 2700 | 6500 |
Weiß | 0 | 100 |
Der Weißwert leitet sich von der Temperatur ab und beide Werte heben sich ggf. auf, daher empfehle ich dir nur einen von diesen zu verwenden!
Beispiel – setzen der Helligkeit
Die Adresse zum setzen der Helligkeit wäre beispielsweise http://192.168.178.195/light/0?brightness=50.
#include <ArduinoHttpClient.h> #include "WiFiS3.h" #define WIFI_SSID "abc" #define WIFI_PWD "123" char serverAddress[] = "192.168.178.195"; WiFiClient wifi; HttpClient client = HttpClient(wifi, serverAddress, 80); int status = WL_IDLE_STATUS; void setup() { Serial.begin(115200); Serial.print("Aufbau der Verbindung zu: "); Serial.println(WIFI_SSID); while (status != WL_CONNECTED) { status = WiFi.begin(WIFI_SSID, WIFI_PWD); Serial.print("."); delay(500); } Serial.println(); Serial.print("Verbindung erfolgreich zu "); Serial.print(WIFI_SSID); Serial.println(" aufgebaut!"); Serial.print("IP-Adresse: "); Serial.println(WiFi.localIP()); readShellyDuoStatus(); sendHttpRequest("/light/0?brightness=", String(50, DEC)); } void readShellyDuoStatus() { sendHttpRequest("/status", ""); } bool sendHttpRequest(String url, String param) { int connectStatus = client.connect(serverAddress, 80); Serial.println(connectStatus); client.get(url + param); return printHttpResponse() == 200; } int printHttpResponse() { int statusCode = client.responseStatusCode(); Serial.print("HttpStatus Code: "); Serial.println(statusCode); if (statusCode == 200) { String response = client.responseBody(); Serial.print("Antwort: "); Serial.println(response); } client.stop(); return statusCode; } void loop() {}
Die Antwort von diesem REST-Call ist wieder ein JSON (in der Grafik mit Gelb markiert) aus welchem wir den Status der Lampe (ison) und die Helligkeit (brightness) ablesen können.
Im nächsten Schritt möchte ich dir zeigen wie du diese Antwort parsed und auswertest.
Schritt 4 – Parsen des JSON-Response von der Shelly DUO Lampe am Arduino
Die Antwort von der Shelly Lampe im JSON-Format können wir mit wenigen Zeilen Code mit der ArduinoJson Bibliothek parsen. Diese Bibliothek ist unter https://arduinojson.org/ sehr gut beschrieben und dokumentiert.
Wenn man den Status abruft ist der JSON-Response sehr komplex und enthält alle Daten zu der Lampe:
{"wifi_sta":{"connected":true,"ssid":"FRITZBox7590GI24","ip":"192.168.178.195","rssi":-83},"cloud":{"enabled":true,"connected":true},"mqtt":{"connected":false},"time":"13:14","unixtime":1735733673,"serial":56,"has_update":false,"mac":"08F9E07058FD","cfg_changed_cnt":0,"actions_stats":{"skipped":0},"lights":[{"ison":true,"source":"http","has_timer":false,"timer_started":0,"timer_duration":0,"timer_remaining":0,"brightness":50,"white":100,"temp":6500,"transition":0}],"meters":[{"power":0.00,"is_valid":true,"timestamp":1735737273,"counters":[0.000, 0.000, 0.000],"total":0}],"update":{"status":"idle","has_update":false,"new_version":"20230913-111821/v1.14.0-gcb84623","old_version":"20230913-111821/v1.14.0-gcb84623","beta_version":"20231107-162700/v1.14.1-rc1-g0617c15"},"ram_total":52128,"ram_free":40396,"fs_size":233681,"fs_free":163150,"uptime":2142}
Die Antwort beim setzen einer Eigenschaft jedoch entfält lediglich die Werte für die Helligkeit, Farbtemperatur sowie den Weißwert und ob diese Lampe eingeschaltet ist oder eben nicht.
{"ison":true,"source":"http","has_timer":false,"timer_started":0,"timer_duration":0,"timer_remaining":0,"brightness":50,"white":100,"temp":6500,"transition":0}
Beispiel – parsen einer Antwort beim setzen einer Eigenschaft
Über einen Online jsonformatter wie https://jsonformatter.curiousconcept.com/# kann man diese Antwort formatieren lassen und so besser die Schlüssel/Werte Paare ablesen.
Wenn man sich die Antwort bzw. eher die Werte genauer anschaut, dann erkennt man schon wie möglichen Datentypen:
- ison – bool,
- source – String,
- brightness – int
{
"ison":true,
"source":"http",
"has_timer":false,
"timer_started":0,
"timer_duration":0,
"timer_remaining":0,
"brightness":50,
"white":100,
"temp":6500,
"transition":0
}
Die Funktion zum parsen der Antwort ist in meinem Fall wiefolgt aufgebaut:
- Schritt 1 – deserialisieren des JSON-Response in eine JsonDocument,
- Schritt 2 – prüfen ob der Vorgang erfolgreich war,
- Schritt 2.1 – bei einem Fehler, ausgeben der Fehlermeldung und verlassen der Funktion
- Schritt 3 – bei erfolg wird der Schlüssel „ison“ ausgelesen und in eine boolsche Variable geschrieben
- Schritt 4 – aktivieren / deaktivieren einer LED je nach Status der Variable ison
void parseResponse(String response) { JsonDocument doc; DeserializationError error = deserializeJson(doc, response.c_str()); if (error) { Serial.print(F("Fehler beim parsen der Antwort!")); Serial.println(error.f_str()); return; } bool ison = doc["ison"]; digitalWrite(led, ison); }
Hier das komplette Projekt zum aktivieren / deaktivieren einer Shelly DUO Lampe und aktivieren einer LED über den Status des Feldes „ison“ aus der Antwort.
#include <ArduinoHttpClient.h> #include "WiFiS3.h" #include "ArduinoJson.h" #define WIFI_SSID "abc" #define WIFI_PWD "123" #define led 13 char serverAddress[] = "192.168.178.195"; WiFiClient wifi; HttpClient client = HttpClient(wifi, serverAddress, 80); int status = WL_IDLE_STATUS; void setup() { Serial.begin(115200); pinMode(led, OUTPUT); Serial.print("Aufbau der Verbindung zu: "); Serial.println(WIFI_SSID); while (status != WL_CONNECTED) { status = WiFi.begin(WIFI_SSID, WIFI_PWD); Serial.print("."); delay(500); } Serial.println(); Serial.print("Verbindung erfolgreich zu "); Serial.print(WIFI_SSID); Serial.println(" aufgebaut!"); Serial.print("IP-Adresse: "); Serial.println(WiFi.localIP()); readShellyDuoStatus(); sendHttpRequest("/light/0?turn=", "on"); delay(2500); sendHttpRequest("/light/0?turn=", "off"); } void readShellyDuoStatus() { sendHttpRequest("/status", ""); } bool sendHttpRequest(String url, String param) { if (WiFi.status() == WL_CONNECTED) { int connectStatus = client.connect(serverAddress, 80); if (connectStatus > 0) { client.get(url + param); return printHttpResponse() == 200; } else { Serial.println("Keine Verbindung zum Client möglich! [" + url + param + "]"); } } Serial.println("Keine WiFi Verbindung!"); return false; } int printHttpResponse() { int statusCode = client.responseStatusCode(); Serial.print("HttpStatus Code: "); Serial.println(statusCode); if (statusCode == 200) { String response = client.responseBody(); Serial.print("Antwort: "); Serial.println(response); parseResponse(response); } client.stop(); return statusCode; } void parseResponse(String response) { JsonDocument doc; DeserializationError error = deserializeJson(doc, response.c_str()); if (error) { Serial.print(F("Fehler beim parsen der Antwort!")); Serial.println(error.f_str()); return; } bool ison = doc["ison"]; digitalWrite(led, ison); } void loop() {}