Im letzten Teil zu MQTT habe ich versucht, die Grundlagen dieses Protokolls zu vermitteln. Zudem sollte anschaulich erklärt werden, wie MQTT genau funktioniert und wie Nachrichten an den MQTT-Broker gesendet werden, sodass sie auch tatsächlich empfangen werden. Abgeschlossen wurde das Ganze mit einem kleinen Beispiel, wie man einen MQTT-Broker auf einem Raspberry Pi oder via Docker installiert und anschließend einfach nutzen kann. Dieser Blog soll ein praktisches Beispiel mit verschiedenen Microcontrollern – wie dem D1 Mini, dem ESP32 und einem Arduino mit Ethernet-Shield – zeigen, um MQTT noch besser zu verstehen.
Voraussetzung zu diesem Beitrag
Damit der Beitrag nachgebaut werden kann, wird zunächst ein MQTT-Broker benötigt, wie er bereits in meinem ersten Beitrag eingerichtet wurde. Gleichzeitig wird einiges an Hardware benötigt, siehe Tabelle 1.
| Pos | Menge | Hardware |
| 1 | 1 | Arduino Uno |
| 2 | 1 | Arduino Ethernet-Shield |
| 3 | 1 | D1 Mini |
| 4 | 1 | ESP32 NodeMCU Development Board |
| 5 | 1 | BME 280 |
| 6 | 1 | I2c-LCD (20×4) |
| 7 | 1 | 10kOhm Potentiometer |
| 8 | 1 | Rote LED |
| 9 | 1 | 200Ohm Widerstand |
| 10 | 1 | Jumper Wires |
| 11 | 1-3 | Breadboards |
| 12 | 1 | Taster |
Gleichzeitig wird für den Quellcode der einzelnen Microcontroller Visual Studio Code mit PlatformIO benötigt. Ersteres ist eine kostenlose Entwicklungsumgebung von Microsoft, die unter https://code.visualstudio.com/ heruntergeladen werden kann. PlatformIO ist ein Plug-in beziehungsweise eine Erweiterung für Visual Studio Code, die nachträglich installiert werden muss. Damit PlatformIO installiert werden kann, wird außerdem Python in einer aktuellen Version benötigt – Stand Oktober 2024 ist dies Version 3.13.0 – siehe https://www.python.org/. Ausführliche Anleitungen zur Installation finden sich im Internet.
Hinweis zum Quellcode
Da ich Visual Studio Code mit PlatformIO verwende, habe ich die Möglichkeit, mit verschiedenen Projektkonfigurationen zu arbeiten. Ich nutze für meinen Quellcode meist zwei Projektkonfigurationen, siehe Abbildung 1:
*_Debug: mit einer erweiterten Ausgabe im seriellen Monitor
*_Release: der reine Quellcode ohne die vielen Ausgaben im seriellen Monitor

Sollte bei deinem Testaufbau der Quellcode oder der Microcontroller nicht arbeiten beziehungsweise möchtest du sehen, was genau passiert, dann empfehle ich dir, an dieser Stelle den Code im *_Debug zu kompilieren und auf deinen Microcontroller zu laden.
Sollte der Code funktionieren und du Speicher auf deinem Microcontroller sparen wollen, empfehle ich dir, die *_Release-Projektkonfiguration zu verwenden.
Bei allen Projekten wird mit der *_Debug-Projektkonfiguration eine serielle Kommunikation aktiviert, und viele Stellen im Code geben Hinweise darauf, was gerade passiert.
Der vollständige Quellcode für alle in diesem Beitrag verwendeten Projekte steht außerdem in einem öffentlichen GitHub-Repository zur Verfügung. Dort befinden sich die PlatformIO-Projekte für den D1 Mini, den ESP32 sowie den Arduino Uno inklusive der entsprechenden Konfigurationen. Das Repository ist unter folgendem Link erreichbar: https://github.com/BerryBase-de/MQTT-Example
Damit lassen sich die Beispiele aus diesem Artikel direkt herunterladen, anpassen und auf die jeweiligen Mikrocontroller übertragen.
Grundidee und Aufbau des Beispiels
Die Grundidee hinter dem Beispiel ist ein vereinfachtes Szenario aus der Heimautomation. Zunächst gibt es einen einfachen Sensor – hier ein D1 Mini mit BME280 –, der uns die Umweltdaten eines Raums liefert.
Als weiteren Sensor und Anzeige gibt es einen Arduino Uno mit Ethernet-Shield, mit dem ein Potentiometer ausgelesen wird und der Wertebereich als prozentualer Wert an den MQTT-Broker gesendet wird. Gleichzeitig erhält der Arduino Uno alle Daten aus unserem Beispiel, um diese auf einem 20 x 4 LCD-Display darzustellen. Hierzu wird ein LCD-Display mit angelötetem I2C-Shield verwendet.
Zuletzt kommt in diesem Aufbau ein ESP32 NodeMCU Development Board mit einer LED und einem Taster zum Einsatz. Dieser simuliert einen entfernten Taster sowie eine Leuchte – in diesem Fall eine rote LED –, die im eingeschalteten Zustand anhand des prozentualen Wertes vom Arduino gedimmt wird.
Der Clou an dem Aufbau ist, dass alle Informationen für die Anzeige und die LED nicht direkt von den Microcontrollern übernommen werden. Stattdessen werden die Nachrichten beim Abonnieren – also beim Subscribe – vom MQTT-Broker verwendet. Der Taster für die LED wird also in diesem Fall nicht direkt ausgewertet, sondern über Nachrichten vom MQTT-Broker gesteuert.
In der Praxis ist das zwar nicht üblich, soll aber zeigen, wie gut und schnell MQTT hier arbeitet und reagiert.
Abbildung 2 zeigt einmal den Aufbau mit Breadboard und allen Komponenten – außer dem Raspberry Pi.

Wie eingangs schon erwähnt, wird der Raspberry Pi aus dem vorherigen Blogartikel als MQTT-Broker verwendet. Dieser ist auch zwingend nötig, da andernfalls die generelle Kommunikation nicht funktioniert.
Solltest du im weiteren Verlauf deine Heimautomation um Umweltdaten erweitern wollen, kann der D1 Mini mit BME280 als einfacher Sensor genutzt werden.
Der D1 Mini mit BME280 als Sensor
Die Hardware
Den Anfang macht der D1 Mini mit dem BME280. Letzterer liefert Umweltdaten über:
- Temperatur
- Druck
- Feuchtigkeit
und ist im Grunde das, was man in der Regel in der Heimautomation zur Steuerung von Heizkörpern oder Thermostaten benötigt. Teilweise werden solche Sensoren für viel Geld von namhaften Herstellern verkauft, obwohl der Hardwarepreis eher gering ist. In diesem Fall sendet der D1 Mini jede Minute die aktuellen Umweltdaten an den MQTT-Broker.
Abbildung 3 zeigt die Verdrahtung des D1 Mini und des BME280. Dabei ist auf die verwendeten Pins zu achten, da diese in der Projektkonfiguration entsprechend hinterlegt sind.

Da lediglich die Spannungsversorgung sowie die I2C-Kommunikation zwischen den Bauteilen hergestellt werden muss, sollte der Aufbau schnell erledigt sein. Wichtig ist dabei, die 3,3-V-Spannungsversorgung des D1 Mini zu verwenden und NICHT die 5-V-Spannungsversorgung. Dies kann zu einer Überlastung und zum Defekt des D1 Mini führen.
Der Quellcode
Damit später die Kommunikation zwischen dem D1 Mini und dem Broker funktioniert, sind in der platformio.ini noch einige Anpassungen nötig, siehe Abbildung 4.

Im Wesentlichen muss zunächst das WiFi korrekt eingetragen werden (Zeile 23 und 24) und die IP-Adresse des MQTT-Brokers – also des Raspberry Pi – angepasst werden (Zeile 26).
Hinzu kommt, dass jeder MQTT-Client einen eindeutigen Namen benötigt, der jedoch keine Leerzeichen oder Sonderzeichen enthalten darf (Zeile 25).
Solltest du beim MQTT-Broker bereits eine Benutzer-/Passwort-Authentifizierung eingerichtet haben, muss dies mit dem Flag in Zeile 28 sowie den Anmeldedaten in Zeile 29 und 30 aktiviert werden. Der Quellcode arbeitet bei der Anmeldung zum MQTT-Broker ein wenig anders, was jedoch im Hintergrund geschieht.
Zeile 31 bis 33 sind die Topics, unter denen später die Sensordaten bereitgestellt werden sollen. Möchtest du ein anderes Topic für einen oder mehrere Werte verwenden, kannst du dies dort anpassen. Wichtig ist, dass hier ein absoluter Pfad angegeben wird und nicht mit Wildcards gearbeitet wird.
Sind die Einstellungen vorgenommen und die Projektkonfiguration ausgewählt, beginnt PlatformIO mit dem Herunterladen der Bibliotheken, dem Kompilieren und dem Übertragen des Codes auf den D1 Mini. In der Regel sollte das nicht länger als zwei bis drei Minuten dauern. PlatformIO sollte dies normalerweise ohne Probleme erledigen. In einigen Fällen musste ich bei der Anzeige für den Verbindungsaufbau den D1 Mini über den Reset-Button neu starten, damit dieser in den Boot-Mode wechselt.
Was genau macht nun der Quellcode im Einzelnen?
Zunächst wird – sofern *_Debug als Projektkonfiguration gewählt wurde – die serielle Kommunikation aufgebaut, damit die Debug-Ausgaben im seriellen Monitor funktionieren.
Direkt im Anschluss wird der BME280 initialisiert, das WiFi verbunden und die MQTT-Kommunikation hergestellt. In der loop()-Funktion wird anschließend wie folgt gearbeitet:
- Zunächst prüfen, ob WiFi vorhanden ist und gegebenenfalls neu verbinden
- Prüfung der MQTT-Verbindung und gegebenenfalls neu verbinden
- Prüfen, ob neue Sensordaten an MQTT gesendet werden müssen (alle 60 Sekunden)
- Wenn der Timer nicht abgelaufen ist, wird das Senden übersprungen
- Ist der Timer abgelaufen, werden die Sensordaten gesendet
Da beim D1 Mini der Watchdog automatisch aktiv ist, gibt es an einigen Stellen Funktionsaufrufe, damit der Watchdog den D1 Mini nicht fälschlicherweise neu startet. Das betrifft insbesondere den WiFi-Verbindungsaufbau und die Verbindung zu MQTT.
ESP32 NodeMCU mit LED und Taster
Die Hardware
Als nächstes sollte der ESP32 NodeMCU mit Taster, LED und Widerstand aufgebaut werden, siehe Abbildung 5.

Auch hier sollte es keine großen Probleme geben, da alle Komponenten schnell auf das Breadboard gesteckt werden können. Wichtig bei der LED ist, dass die Spannungsversorgung vom GPIO 5 an der Anode (langes Beinchen der LED) anliegt. Andernfalls wird die LED nicht leuchten. Der 220-Ohm-Widerstand wird an die Kathode (kurzes Beinchen) und GND des ESP32 angeschlossen.
Für den Taster wird der Modus Pullup-Input verwendet, da es sonst zu keinem eindeutigen Signal beim Betätigen des Tasters kommt. Daher wird GPIO 21 über den Taster mit GND verbunden. Dadurch erhält der Quellcode ein eindeutiges Signal zum Schalten der LED.
Der Quellcode
Die Konfiguration beim ESP32 ist fast identisch mit der des D1 Mini, siehe Abbildung 6.

Im unteren Bereich – Zeile 22 bis 32 – werden WiFi und MQTT eingerichtet. Dabei gelten die gleichen Regeln wie beim D1 Mini. Interessant wird es jedoch bei Zeile 32, da hier auf ein Topic vom Arduino gelauscht wird. Dieses Topic muss identisch mit dem Topic beim Arduino sein, da ansonsten die LED nicht gedimmt werden kann.
In Zeile 19 und 20 sind die LED und auch der Button konfiguriert. Solltest du eine andere GPIO-Belegung verwenden, musst du hier die entsprechenden GPIOs eintragen. Prüfe jedoch vorher, ob die GPIOs als Pullup-Input beziehungsweise als Ausgang verwendet werden können, da der ESP32 NodeMCU sonst unerwartet reagieren könnte.
Sind alle Einstellungen vorgenommen und die gewünschte Projektkonfiguration ausgewählt, kann PlatformIO wieder die nötigen Bibliotheken herunterladen, den Code kompilieren und auf den ESP32 laden.
Für Windows-Nutzer gilt hierbei, dass beim Versuch der Verbindung mit dem ESP32 dieser in den Boot-Mode versetzt werden muss. Dazu werden die Reset- und Boot-Taste des ESP32 gedrückt und anschließend die Reset-Taste wieder losgelassen. Die Boot-Taste muss weiter gedrückt bleiben. Sobald der Upload von PlatformIO gestartet wurde, kann auch die Boot-Taste losgelassen werden.
Unter Linux muss hingegen nichts getan werden, da PlatformIO den ESP32 selbstständig in den Boot-Mode versetzen kann.
Der Ablauf des Programms soll ebenfalls kurz erläutert werden. Zunächst wird – sofern *_Debug die aktive Projektkonfiguration ist – die serielle Kommunikation gestartet. Danach erfolgt der Verbindungsaufbau mit WiFi und MQTT. Anders als beim D1 Mini wird zusätzlich eine callback-Funktion gesetzt, die immer dann aufgerufen wird, wenn eine abonnierte Nachricht vom MQTT-Broker an den Client gesendet wird. Das Abonnieren – korrekt heißt es subscribe – erfolgt beim Verbinden zu MQTT in der reconnectMQTT()-Funktion.
Die main()-Funktion arbeitet anfangs ähnlich wie beim D1 Mini. Zunächst wird in jedem Zyklus die Verbindung zu WiFi und MQTT geprüft und gegebenenfalls neu aufgebaut. Wird der Taster gedrückt, wird der neue Status an den MQTT-Broker gesendet. Achtung: An dieser Stelle wird der invertierte Status gesendet – High, wenn nicht gedrückt, und Low, wenn gedrückt. Dadurch leuchtet später die LED und wird ausgeschaltet, sobald der Button gedrückt wird.
Da der Button im Code die LED nicht direkt ansteuert, sondern der Status über MQTT übertragen wird, wird die callback()-Funktion interessant.
Erhält der ESP32 eine Nachricht von einem bekannten Topic – hier der Status des Buttons und der prozentuale Wert des Potentiometers vom Arduino –, wird der neue Wert übernommen und die LED entsprechend angesteuert. Ein unbekanntes Topic, das fälschlicherweise an den ESP32 gesendet wurde, wird ignoriert.
Arduino Uno mit Ethernet-Shield, I2C-Display und Potentiometer
Die Hardware
Bei dieser Hardwareverkabelung solltest du zunächst das Ethernet-Shield auf den Arduino Uno stecken und anschließend das I2C-LCD sowie das Potentiometer verkabeln, siehe Abbildung 7.

Da ich beim LCD bewusst auf den I2C-Adapter setze, wird die Verdrahtung erheblich vereinfacht. Statt 16 Drahtbrücken sind lediglich vier Anschlüsse nötig, da der Adapter direkt an das Display gelötet wird. Interessant an dieser Stelle ist, dass dieser I2C-Adapter bei den meisten LCDs dieser Baureihe funktioniert und nachträglich angelötet werden kann.
Beim Potentiometer wird ein analoger Anschluss des Arduino verwendet. Dabei ist darauf zu achten, dass die 5-V-Spannungsversorgung statt der 3,3 V verwendet wird. Anders als die ESP-Microcontroller arbeitet der Arduino mit 5 V Spannung. Das macht es bei komplexeren Aufbauten manchmal schwierig, die richtige Spannung für den jeweiligen Microcontroller zu wählen.
Da neuere Revisionen des Arduino Uno und des Ethernet-Shields einen separaten SDA- und SCL-Anschluss besitzen – dieser befindet sich neben der Ethernet-Buchse –, muss nicht umständlich im Pinout nach den passenden Anschlüssen gesucht werden.
Der Quellcode
Bei der Konfiguration des Arduino-Projekts wird ein Teil in der platformio.ini vorgenommen, siehe Abbildung 8.

Zeile 21 bis 30 enthält die Konfiguration von MQTT. Gerade bei Zeile 27 bis 30 ist auf die anderen Microcontroller-Projekte zu achten. Wurden dort ein oder mehrere Topics geändert, muss dies an dieser Stelle entsprechend angepasst werden. Zeile 30 enthält das Topic, über das der prozentuale Wert des Potentiometers an den MQTT-Broker gesendet wird, der später die LED am ESP32 entsprechend dimmt.
Zeile 32 bis 35 enthält die Konfiguration des I2C-LCD und des analogen Eingangs am Arduino. Sollte sich die Adresse des I2C-Adapters oder der verwendete analoge Pin unterscheiden, muss dies hier angepasst werden.
In der main.h gibt es außerdem zwei Variablen, die direkt das Ethernet-Shield betreffen. Normalerweise befindet sich auf der Unterseite des Ethernet-Shields oder auf der Platine eine aufgedruckte MAC-Adresse. Diese MAC-Adresse musst du der Variable mac[] (Zeile 58) übergeben, siehe Abbildung 9.

Die darauffolgende IP-Adresse muss eine freie IP-Adresse in deinem Netzwerk sein und sich im selben Netz wie der MQTT-Broker befinden.
Sind alle Anpassungen vorgenommen und die gewünschte Projektkonfiguration ausgewählt, können ein letztes Mal alle nötigen Bibliotheken heruntergeladen, der Code kompiliert und auf den Microcontroller übertragen werden.
Im Prinzip verhält sich der Code ähnlich wie der Code des ESP32. Der Unterschied besteht darin, dass der Arduino alle in diesem Praxisbeispiel vorhandenen Topics abonniert und diese Werte auf den vier Zeilen des Displays ausgibt. Beim Potentiometer wird der Wert – der in der Regel zwischen 0 und 1023 liegt – in einen prozentualen Wert umgewandelt und an den MQTT-Broker gesendet.
Der Ablauf des Programms beginnt – sofern *_Debug als Projektkonfiguration ausgewählt wurde – mit der Initialisierung der seriellen Kommunikation. Danach wird die Ethernetverbindung mit dem Ethernet-Shield aufgebaut und anschließend MQTT initialisiert. In der setup()-Funktion wird – wie auch schon beim ESP32 – die callback-Funktion für eingehende MQTT-Nachrichten gesetzt.
Die main()-Funktion folgt dann dem gewohnten Ablauf. Es wird die Verbindung zu MQTT geprüft, gegebenenfalls neu aufgebaut und der aktuelle Wert des analogen Eingangs mit dem letzten Wert verglichen. Kommt eine neue Nachricht via MQTT, wird der Inhalt des Displays komplett gelöscht und alle Daten neu ausgegeben. Somit ist – zumindest bei diesem kleinen Projekt – direkt ersichtlich, welche aktuellen Werte die MQTT-Clients verschickt haben.
Das Beispiel im Betrieb
Wie bereits erwähnt, ist das Praxisbeispiel nicht groß und umfasst nur wenige Clients. Es zeigt jedoch sehr deutlich, dass alle gängigen Microcontroller mit der passenden MQTT-Bibliothek diesen Standard beherrschen, siehe Abbildung 10.

Egal ob der Arduino Uno über Ethernet Daten sendet und empfängt oder die ESP-Controller via WiFi kommunizieren – die MQTT-Daten werden zuverlässig ausgetauscht. Die einzelnen Topics werden auf dem LCD angezeigt und in den eingestellten Zeitintervallen aktualisiert. Die LED reagiert auf den Taster und den eingestellten Potentiometerwert und wird entsprechend gedimmt.
Zusammenfassung
Das Beispiel repräsentiert bereits gut, was mit MQTT im Bereich Heimautomation oder -steuerung möglich ist. Nicht umsonst wird dieser Standard bei vielen IoT-Geräten im Bereich Heimautomation weiterhin angeboten. Die Frage ist dabei immer, wie die entsprechende Nachricht vom MQTT-Client aufgebaut ist.
Gerade bei beispielsweise Shelly-Geräten der neueren Generation werden nicht mehr nur einfache Werte verschickt, sondern Daten im sogenannten JSON-Format. Auch diese Art der Übertragung wäre mit leichten Anpassungen im Quellcode der einzelnen Microcontroller durchaus möglich. Der Arduino ist jedoch durch seinen Speicher stark begrenzt, weshalb er bei komplexerem Code oder zu vielen Bibliotheken schnell an seine Grenzen stößt.
MQTT hat insbesondere durch IoT und Heimautomation noch einmal deutlich an Aufmerksamkeit gewonnen – nicht zuletzt aufgrund der einfachen Einrichtung eines MQTT-Brokers und der unkomplizierten Möglichkeit, Daten bereitzustellen.
Nicht unerwähnt lassen möchte ich an dieser Stelle das Tool MQTT Explorer, das es für alle gängigen Betriebssysteme gibt. Es handelt sich um ein Programm, das als MQTT-Client fungiert und alle Daten vom MQTT-Broker beziehen, manipulieren oder auch neue Topics erstellen kann. Die Fülle an Informationen und Auswertungen, die dieses Tool mitbringt, ist in meinem Netzwerk immer wieder hilfreich, um Problemen oder Informationen von MQTT-Clients auf die Spur zu kommen. Ein Blick auf dieses Tool lohnt sich definitiv.
Abschließend zu dieser kleinen Blogreihe kann ich nur sagen: Sich mit MQTT zu beschäftigen ergibt durchaus Sinn. Hat man das Prinzip erst einmal verstanden, sind der eigenen Kreativität und den Einsatzmöglichkeiten fast keine Grenzen mehr gesetzt.
Wer das gezeigte Beispiel selbst nachbauen möchte, findet den vollständigen Quellcode im offiziellen GitHub-Repository zu diesem Artikel: https://github.com/BerryBase-de/MQTT-Example
Mit diesen Projekten lässt sich der im Artikel beschriebene Aufbau direkt umsetzen und bei Bedarf für eigene Heimautomationsprojekte erweitern.






































