IoT-Automatisierung

Intelligente Beleuchtung mit MQTT steuern: Dimmer, LED-Streifen, Szenen und Zeitpläne

Steuern Sie LED-Streifen und Dimmer per MQTT mit einem ESP32, nutzen Sie JSON-Befehle mit sanften Übergängen, speichern Sie Szenen als retained Messages und führen Sie Zeitpläne über einen kleinen Python-Dienst aus.

Dimmbarer LED-Streifen unter einem Schreibtisch, gesteuert von einem ESP32 in einem Projekt für intelligente Beleuchtung mit MQTT
Probieren Sie es auf Ihrem eigenen MQTT-Broker ausHolen Sie sich im Free-Tarif einen privaten, verwalteten MQTT-Broker und starten Sie mit fertigen Codebeispielen.
Kostenlos testen Codebeispiele Keine Kreditkarte erforderlich

Mit einer MQTT-Steuerung für intelligente Beleuchtung kann jede App, jedes Dashboard und jede Automatisierung ein Licht dimmen, eine Szene abrufen oder einen Zeitplan ausführen, indem sie einfach eine Nachricht veröffentlicht. In diesem Tutorial bauen Sie einen ESP32-PWM-Dimmer für LED-Streifen mit sanften Überblendungen, entwerfen Topics, die für einen Raum ebenso funktionieren wie für ein ganzes Gebäude, speichern Szenen als retained Messages und führen Zeitpläne über einen winzigen Python-Dienst aus, der mit einem ConnectMQ-Broker verbunden ist.

Beleuchtungshardware für MQTT auswählen

Bevor Sie Firmware schreiben, legen Sie fest, welche Art von Beleuchtung Sie steuern. Jede Option passt etwas anders zu MQTT.

Hardware Anbindung an MQTT Geeignet für Worauf zu achten ist
Niedervolt-LED-Streifen mit ESP32-PWM-Treiber Eigene Firmware, wie in diesem Tutorial Schreibtische, Regale, Schränke, Akzentbeleuchtung Dimensionierung des Netzteils und Spannungsabfall bei langen Strecken
Adressierbare LEDs (WS2812B und ähnliche) Eigene Firmware oder WLED Effekte und Farbe pro Pixel Stromaufnahme, Länge der Datenleitung
Netzspannungsdimmer und Relais mit MQTT-Firmware Tasmota, Shelly oder ähnliche Geräte Vorhandene Deckenleuchten Nur zertifizierte Hardware, passender Dimmertyp für das Leuchtmittel
DALI- oder KNX-Beleuchtung Brücke vom Bus zu MQTT Büros und Gewerbegebäude Der Bus bleibt die Steuerung; MQTT schafft Transparenz

Im Wohnbereich decken PWM-Streifen und smarte Relais die meisten Anforderungen ab. In Gewerbegebäuden hängt die Beleuchtung meist bereits an DALI oder KNX, und der richtige Weg ist, diesen Bus zu MQTT zu überbrücken, statt ihn zu ersetzen. Die folgende Topic-Struktur funktioniert für alle vier Varianten, und genau deshalb lohnt es sich, sie früh zu standardisieren.

Topic-Design für Leuchten

Eine Leuchte braucht auf MQTT drei Dinge: ein Befehls-Topic, ein Zustands-Topic und ein Verfügbarkeits-Topic. Getrennt gehalten verhindern sie Rückkopplungsschleifen, und Dashboards zeigen den tatsächlichen Zustand an.

<prefix>/<room>/<light>/set          commands in (JSON)
<prefix>/<room>/<light>/state        actual state out (retained)
<prefix>/<room>/<light>/availability "online" / "offline" (retained, last will)
<prefix>/scenes/<scene>              scene definitions (retained)
<prefix>/<room>/scene/set            recall a scene by name

Befehle verwenden JSON, damit Sie sie später erweitern können, ohne ältere Clients zu brechen:

{"state": "ON", "brightness": 180, "transition": 2.0}

In größeren Liegenschaften gliedern Sie <prefix> zusätzlich nach Standort, Gebäude und Etage, ähnlich wie ein Unified Namespace (UNS) in der Industrie ein Werk nach den ISA-95-Ebenen ordnet; so kann ein Facility-Dashboard eine ganze Etage mit einem einzigen Wildcard-Abonnement überwachen.

brightness reicht von 0 bis 255, und transition ist die Überblendzeit in Sekunden. Dieses Format entspricht dem JSON-Schema, das die Home-Assistant-MQTT-Integration für Leuchten versteht; derselbe Dimmer kann also ohne Firmwareänderung in Home Assistant erscheinen.

Hardware

  • Ein ESP32-Entwicklungsboard.
  • Ein einfarbiger LED-Streifen mit 12 V oder 24 V und ein passendes Netzteil.
  • Ein Logic-Level-N-Kanal-MOSFET (zum Beispiel IRLZ44N oder AO3400 auf einem Modul) pro Kanal oder eine fertige MOSFET-Treiberplatine.
  • Ein 220-Ohm-Gatewiderstand und ein 10-kOhm-Pull-down pro Kanal.

Verbinden Sie das MOSFET-Gate über den Widerstand mit GPIO 25, die Source mit Masse (gemeinsam mit der ESP32-Masse) und den Drain mit dem Minuspol des LED-Streifens. Der Pluspol des Streifens geht an den Pluspol des Netzteils. Versorgen Sie einen Streifen niemals über den 5-V-Pin des ESP32.

Für Netzspannungsdimmer verwenden Sie ein zertifiziertes Produkt, das bereits MQTT spricht, etwa ein Tasmota- oder Shelly-Gerät, statt selbst Hardware für Netzspannung zu bauen. Das Topic-Design aus diesem Artikel gilt trotzdem; Hinweise zum Flashen und zur Konfiguration finden Sie unter Tasmota MQTT.

Die ESP32-Dimmer-Firmware

Der Sketch nutzt die LEDC-API des ESP32-Arduino-Core 3.x (ledcAttach und ledcWrite), PubSubClient und ArduinoJson 7. Er wendet eine Gammakurve an, damit das Dimmen für das Auge linear wirkt, blendet sanft über und veröffentlicht nach jeder Änderung einen retained Zustand.

#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <math.h>

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* BROKER = "broker.connectmq.com";
const int   PORT = 1883;

#define PREFIX "connectmq/demo/light-8pz3/office-201/desk-strip"
const char* T_SET   = PREFIX "/set";
const char* T_STATE = PREFIX "/state";
const char* T_AVAIL = PREFIX "/availability";

const int LED_PIN = 25;
const int PWM_FREQ = 5000;   // Hz, oberhalb sichtbaren Flimmerns
const int PWM_BITS = 12;     // 0..4095
const int PWM_MAX = (1 << PWM_BITS) - 1;

WiFiClient net;
PubSubClient mqtt(net);

bool on = false;
int brightness = 255;            // letzte Helligkeit 1..255
float current = 0, target = 0;   // 0..255
float step = 0;
unsigned long lastStep = 0;

void writePwm(float level) {
  float norm = level / 255.0f;
  int duty = (int)(powf(norm, 2.2f) * PWM_MAX + 0.5f);   // Gammakorrektur
  ledcWrite(LED_PIN, duty);
}

void publishState() {
  JsonDocument doc;
  doc["state"] = on ? "ON" : "OFF";
  doc["brightness"] = brightness;
  char buf[96];
  size_t n = serializeJson(doc, buf);
  mqtt.publish(T_STATE, (const uint8_t*)buf, n, true);
}

void startFade(float to, float seconds) {
  target = to;
  int steps = max(1, (int)(seconds * 50));     // 50 Aktualisierungen pro Sekunde
  step = (target - current) / steps;
  if (seconds <= 0) { current = target; writePwm(current); step = 0; }
}

void onMessage(char* topic, byte* payload, unsigned int len) {
  JsonDocument doc;
  if (deserializeJson(doc, payload, len)) return;

  float transition = doc["transition"] | 0.5f;
  if (doc["brightness"].is<int>()) {
    brightness = constrain(doc["brightness"].as<int>(), 1, 255);
    on = true;
  }
  if (doc["state"].is<const char*>()) {
    on = strcmp(doc["state"].as<const char*>(), "ON") == 0;
  }
  startFade(on ? brightness : 0, transition);
  publishState();
}

void connectMqtt() {
  while (!mqtt.connected()) {
    String id = "light-" + String((uint32_t)ESP.getEfuseMac(), HEX);
    if (mqtt.connect(id.c_str(), T_AVAIL, 1, true, "offline")) {
      mqtt.publish(T_AVAIL, "online", true);
      mqtt.subscribe(T_SET, 1);
      publishState();
    } else {
      delay(2000);
    }
  }
}

void setup() {
  ledcAttach(LED_PIN, PWM_FREQ, PWM_BITS);
  writePwm(0);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(250);
  mqtt.setServer(BROKER, PORT);
  mqtt.setCallback(onMessage);
}

void loop() {
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();

  if (step != 0 && millis() - lastStep >= 20) {
    lastStep = millis();
    current += step;
    if ((step > 0 && current >= target) || (step < 0 && current <= target)) {
      current = target;
      step = 0;
    }
    writePwm(current);
  }
}

Beachten Sie, dass die Überblendung in loop() ohne delay() läuft, sodass das Gerät auch während des Dimmens weiter auf MQTT reagiert. Der Last Will markiert die Leuchte als offline, wenn sie Strom oder WLAN verliert.

Den Dimmer testen

# alles für diese Demo beobachten
mosquitto_sub -h broker.connectmq.com -p 1883 -i light-view-8pz3 -t "connectmq/demo/light-8pz3/#" -v

# mit etwa 70 Prozent und 2 Sekunden Überblendung einschalten
mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 -q 1 \
  -t "connectmq/demo/light-8pz3/office-201/desk-strip/set" \
  -m '{"state":"ON","brightness":180,"transition":2}'

# mit langsamer Überblendung ausschalten
mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 -q 1 \
  -t "connectmq/demo/light-8pz3/office-201/desk-strip/set" \
  -m '{"state":"OFF","transition":5}'

Der öffentliche MQTT-Broker ist für Tests und Prototypen gedacht und steht allen offen, sodass ein Fremder Ihr Demo-Licht schalten könnte. Auf dem Schreibtisch ist das harmlos, aber genau deshalb muss echte Beleuchtung auf einem privaten Broker mit Zugangsdaten laufen.

Szenen als retained Messages

Eine Szene ist ein benannter Satz von Leuchtenzuständen. Wenn Sie jede Szene als retained Message auf dem Broker speichern, sehen alle Steuerungen, Dashboards und Wandpanels dieselben Definitionen, und Sie können eine Szene ändern, indem Sie eine neue Version veröffentlichen.

mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 -r \
  -t "connectmq/demo/light-8pz3/scenes/focus" \
  -m '{"office-201/desk-strip":{"state":"ON","brightness":230},"office-201/ceiling":{"state":"ON","brightness":200}}'

mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 -r \
  -t "connectmq/demo/light-8pz3/scenes/presentation" \
  -m '{"office-201/desk-strip":{"state":"ON","brightness":40},"office-201/ceiling":{"state":"OFF"}}'

Szenenabruf und Zeitpläne in Python

Ein kleiner Dienst abonniert Szenendefinitionen und Abrufanfragen, verteilt Szenenabrufe auf die einzelnen Leuchten und führt einen Tageszeitplan aus. Er nutzt paho-mqtt 2.x und ansonsten nur die Standardbibliothek.

import json
import time
import uuid
from datetime import datetime

import paho.mqtt.client as mqtt

BROKER, PORT = "broker.connectmq.com", 1883
PREFIX = "connectmq/demo/light-8pz3"

scenes = {}
SCHEDULE = [            # (HH:MM, Wochentage 0=Mo..6=So, Szene)
    ("08:00", range(0, 5), "focus"),
    ("12:30", range(0, 5), "presentation"),
    ("19:00", range(0, 7), "off"),
]
scenes["off"] = {"office-201/desk-strip": {"state": "OFF", "transition": 10}}


def recall(client, name):
    scene = scenes.get(name)
    if not scene:
        print("Unknown scene", name)
        return
    for light, cmd in scene.items():
        cmd = {"transition": 1.5, **cmd}
        client.publish(f"{PREFIX}/{light}/set", json.dumps(cmd), qos=1)
    print("Recalled", name)


def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(f"{PREFIX}/scenes/+", qos=1)
    client.subscribe(f"{PREFIX}/+/scene/set", qos=1)


def on_message(client, userdata, msg):
    parts = msg.topic.split("/")
    if parts[-2] == "scenes":
        if msg.payload:
            scenes[parts[-1]] = json.loads(msg.payload)
    elif parts[-2] == "scene" and parts[-1] == "set":
        recall(client, msg.payload.decode().strip())


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"light-sched-{uuid.uuid4().hex[:6]}")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, PORT, 60)
client.loop_start()

last_run = None
while True:
    now = datetime.now()
    key = now.strftime("%Y-%m-%d %H:%M")
    if key != last_run:
        for hhmm, days, scene in SCHEDULE:
            if now.strftime("%H:%M") == hhmm and now.weekday() in days:
                recall(client, scene)
        last_run = key
    time.sleep(5)

Eine Szene rufen Sie manuell so ab:

mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 \
  -t "connectmq/demo/light-8pz3/office-201/scene/set" -m "focus"

Wenn Sie für Zeitpläne und sonnenstandsabhängige Auslöser einen visuellen Editor bevorzugen, funktionieren dieselben Topics auch aus Node-RED oder aus Home-Assistant-Automatisierungen.

Erweiterung auf Tunable White und RGB

Dieselbe Firmwarestruktur lässt sich auf mehrkanalige Streifen skalieren. Ein Tunable-White-Streifen hat einen warmen und einen kalten Kanal, ein RGB- oder RGBW-Streifen drei oder vier. Binden Sie pro Farbpin einen LEDC-Kanal an und erweitern Sie den JSON-Befehl um optionale Felder, zum Beispiel "color_temp": 300 in Mired für Tunable White oder "color": {"r": 255, "g": 140, "b": 0} für RGB. Behalten Sie brightness als eigenes Feld und skalieren Sie jeden Kanal damit, sodass sich Helligkeit und Farbe unabhängig voneinander ändern lassen und eine Szene beides in einer Nachricht setzen kann.

Zwei praktische Punkte ersparen später Ärger. Mischen Sie Tunable White so, dass die Summe beider Kanäle bei gegebener Helligkeit konstant bleibt, sonst wird das Licht in der Mitte des Bereichs merklich heller. Und veröffentlichen Sie nach jedem Befehl den vollständigen resultierenden Zustand einschließlich Farbe auf dem Zustands-Topic, denn Dashboards und Home Assistant benötigen ihn, um die Position der Farbauswahl korrekt darzustellen.

Checkliste für den Produktivbetrieb

  1. Wechseln Sie auf einen privaten Broker auf Port 8883 mit TLS und geben Sie jedem Dimmer eigene Zugangsdaten.
  2. Lassen Sie Wandschalter lokal funktionieren; MQTT soll Steuerung ergänzen und nicht der einzige Weg sein, ein Licht einzuschalten.
  3. Kombinieren Sie die Beleuchtung mit Präsenzsensoren im Büro, damit leere Räume automatisch abschalten.
  4. Lassen Sie in Gebäuden mit KNX oder DALI den vorhandenen Bus schalten und überbrücken Sie ihn zu MQTT, wie in unserer KNX-MQTT-Integration.
  5. Verwenden Sie QoS 1 für Befehle und senden Sie immer absolute Werte, niemals "toggle", damit eine doppelte Zustellung keinen Schaden anrichtet.
Stolperfalle Symptom Lösung
Keine Gammakorrektur Die meisten sichtbaren Änderungen passieren am unteren Ende des Bereichs Eine Potenzkurve wie im Sketch anwenden
Überblendung mit delay() Leuchte ignoriert Befehle während des Überblendens Überblendung schrittweise in loop() ausführen
Zustand nicht retained Dashboards zeigen nach dem Wiederverbinden "unbekannt" Zustand mit gesetztem Retain-Flag veröffentlichen
Befehle auf dem Zustands-Topic Leuchten schwingen oder erzeugen Echos Topics set und state trennen
Niedrige PWM-Frequenz Sichtbares Flimmern auf Kamerabildern 1 kHz oder mehr verwenden

Ein verwalteter MQTT-Broker hält die Lichtsteuerung verfügbar, ohne dass ein Server im Gebäude nötig ist, und der Leitfaden zur IoT-Automatisierung zeigt, wie sich die Beleuchtung mit anderen Gebäudesystemen verbindet.

Betreiben Sie Ihre Beleuchtung mit ConnectMQ

Erstellen Sie unter app.connectmq.com einen kostenlosen Serverless-Broker, ohne Kreditkarte. Flashen Sie Ihre Dimmer mit den ausgegebenen Zugangsdaten und nutzen Sie dann den MQTT-Client im Browser im ConnectMQ-Portal, um Testbefehle zu senden und Szenen abzurufen, während Sie jeden Raum in Betrieb nehmen.

Häufig gestellte Fragen

Warum JSON-Befehle statt einfacher ON- und OFF-Werte verwenden?

Mit JSON trägt eine einzige Nachricht Zustand, Helligkeit und Übergangszeit, und Sie können später Felder wie die Farbtemperatur ergänzen, ohne bestehende Clients zu brechen.

Sollten Zustands-Topics von Leuchten retained sein?

Ja. Ein retained Zustand ermöglicht es jedem Dashboard und jeder App, den korrekten Zustand sofort beim Abonnieren anzuzeigen, ohne auf die nächste Änderung zu warten.

Kann ich Leuchten mit Netzspannung über einen ESP32 steuern?

Verwenden Sie ein zertifiziertes Dimmer- oder Relaismodul für Netzspannung mit MQTT-Unterstützung, etwa ein Tasmota- oder Shelly-Gerät. Eigene Hardware für Netzspannung zu bauen ist riskant und oft nicht normkonform.

Was passiert mit geplanten Szenen, wenn der Scheduler ausfällt?

Die Leuchten behalten ihren aktuellen Zustand und bleiben über Schalter und direkte MQTT-Befehle steuerbar. Betreiben Sie den Scheduler als Dienst mit automatischem Neustart, damit verpasste Ereignisse selten bleiben.

Verwandte Artikel

Zigbee2MQTT einrichten: Vom Koordinator bis zum Dashboard

Installieren Sie Zigbee2MQTT mit Docker, konfigurieren Sie Koordinator und MQTT-Verbindung, lernen Sie Geräte an und benennen Sie sie um, steuern Sie sie per MQTT und zeigen Sie ihre Zustände auf einem Dashboard an, zuerst getestet auf einem kostenlosen öffentlichen MQTT-Broker.

8 Min. Lesezeit

Alle Artikel →

Ihr privater MQTT-Broker ist nur wenige Klicks entfernt

Konto anlegen, Broker-Zugangsdaten erhalten und das erste Gerät verbinden — ohne Server, die installiert, gepatcht oder skaliert werden müssen.