ESP32 und Arduino

ArduinoMqttClient-Bibliothek: API, Polling, QoS und Will Messages

Ein umfassender Leitfaden zur offiziellen ArduinoMqttClient-Bibliothek: die Verbindungs-API, warum poll() so wichtig ist, Senden und Empfangen per Stream, QoS- und Retain-Flags, Will Messages und alle connectError()-Codes.

Code-Editor mit einem ArduinoMqttClient-Sketch neben einem Arduino-Board, das MQTT-Nachrichten veröffentlicht
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

ArduinoMqttClient ist die offizielle, von Arduino gepflegte MQTT-Bibliothek und läuft auf allem vom UNO R4 WiFi und Nano 33 IoT bis zu MKR-Boards und dem ESP32. Dieser Leitfaden geht die ArduinoMqttClient-API in der Reihenfolge durch, in der Sie sie verwenden: konfigurieren, verbinden, pollen, veröffentlichen, empfangen und eine Will Message setzen. Jedes Beispiel verbindet sich mit einem echten Broker, sodass Sie beim Lesen direkt testen können.

Warum ArduinoMqttClient

ArduinoMqttClient umhüllt ein beliebiges Arduino-Client-Objekt, etwa WiFiClient, WiFiSSLClient, EthernetClient oder einen Mobilfunk-Client, und setzt MQTT 3.1.1 darauf. Die markanteste Designentscheidung: Ausgehende wie eingehende Nachrichten werden als Streams verarbeitet, sodass Sie nie einen Puffer in der Größe Ihrer größten Nachricht brauchen.

Funktion ArduinoMqttClient
Protokoll MQTT 3.1.1
Publish-QoS 0, 1 und 2
Subscribe-QoS 0, 1 und 2
Retained Messages Ja
Will Message Ja, gestreamt mit beginWill() / endWill()
Payload-Verarbeitung Gestreamt (print() / read())
Ereignismodell Polling mit poll(), Callback bei Nachricht
Maintainer Arduino

Wenn Sie PubSubClient bereits kennen, ist das PubSubClient-Arduino-Tutorial ein nützlicher Vergleichspunkt; beide Bibliotheken lösen dasselbe Problem mit unterschiedlichen Kompromissen.

Die Bibliothek installieren

Öffnen Sie in der Arduino IDE Werkzeuge → Bibliotheken verwalten, suchen Sie nach "ArduinoMqttClient" und installieren Sie sie. Zusätzlich brauchen Sie die Netzwerkbibliothek Ihres Boards:

Board Netzwerkbibliothek Unverschlüsselter Client TLS-Client
UNO R4 WiFi WiFiS3 WiFiClient WiFiSSLClient
Nano 33 IoT, MKR WiFi 1010 WiFiNINA WiFiClient WiFiSSLClient
ESP32 WiFi (Core) WiFiClient WiFiClientSecure
Boards mit Ethernet-Shield Ethernet EthernetClient Nicht integriert

Den Client konfigurieren

Erstellen Sie zuerst den Netzwerk-Client und übergeben Sie ihn dann an MqttClient:

#include <WiFiNINA.h>          // oder WiFiS3.h, WiFi.h ...
#include <ArduinoMqttClient.h>

WiFiClient net;
MqttClient mqttClient(net);

Setzen Sie vor dem Aufruf von connect() die Session-Parameter:

mqttClient.setId("acm-51e09b");                       // Client ID, niemals leer
mqttClient.setUsernamePassword("YOUR_USERNAME", "YOUR_PASSWORD"); // optional
mqttClient.setKeepAliveInterval(30 * 1000L);          // Millisekunden!
mqttClient.setConnectionTimeout(10 * 1000L);          // Millisekunden
mqttClient.setCleanSession(true);

Achten Sie auf die Einheiten: Anders als bei PubSubClient werden Keep-Alive- und Timeout-Werte in Millisekunden angegeben. Wer 30 statt 30000 übergibt, erhält nach der Ganzzahldivision ein Keep Alive von null Sekunden. Damit ist Keep Alive komplett deaktiviert, tote Verbindungen bleiben vom Broker unbemerkt, und Ihre Will Message wird nie ausgelöst.

Verbinden und connectError() auswerten

connect(host, port) liefert bei Erfolg 1 und bei einem Fehler 0. Schlägt der Aufruf fehl, verrät connectError() den Grund:

connectError() Konstante Bedeutung und Lösung
-2 MQTT_CONNECTION_REFUSED Socket konnte nicht geöffnet werden: Problem mit WLAN, DNS, Port oder TLS
-1 MQTT_CONNECTION_TIMEOUT Kein CONNACK rechtzeitig: falscher Port-Typ oder schlechte Verbindung
0 MQTT_SUCCESS Verbunden
1 MQTT_UNACCEPTABLE_PROTOCOL_VERSION Broker hat MQTT 3.1.1 abgelehnt (selten)
2 MQTT_IDENTIFIER_REJECTED Leere oder unzulässige Client ID
3 MQTT_SERVER_UNAVAILABLE Broker nimmt derzeit keine Verbindungen an
4 MQTT_BAD_USER_NAME_OR_PASSWORD Zugangsdaten falsch
5 MQTT_NOT_AUTHORIZED Client nicht zugelassen, z. B. passt die Client ID nicht zu den Zugangsdaten

Eine vollständige, wiederverwendbare Verbindungsfunktion:

bool connectMqtt(const char* host, int port) {
  Serial.print("Connecting to ");
  Serial.print(host);
  Serial.print(':');
  Serial.println(port);

  if (!mqttClient.connect(host, port)) {
    Serial.print("MQTT connect failed, connectError = ");
    Serial.println(mqttClient.connectError());
    return false;
  }
  Serial.println("MQTT connected");
  return true;
}

Zum Testen verwenden Sie broker.connectmq.com auf Port 1883, den öffentlichen MQTT-Broker. Er akzeptiert anonyme Verbindungen mit jeder eindeutigen, nicht leeren Client ID und ist für Tests und Prototypen gedacht, nicht für Produktionsdaten. Halten Sie Ihre Topics unter einem eindeutigen Präfix wie connectmq/demo/<your-id>/ und veröffentlichen Sie nichts Vertrauliches.

Warum poll() so wichtig ist

poll() ist der Herzschlag von ArduinoMqttClient. Jeder Aufruf:

  1. Liest eingehende Bytes vom Netzwerk-Client und parst vollständige Pakete.
  2. Ruft Ihren onMessage-Callback auf (oder stellt die Nachricht für parseMessage() bereit).
  3. Beantwortet die QoS-1- und QoS-2-Handshakes eingehender Nachrichten.
  4. Sendet ein PINGREQ, wenn das Keep-Alive-Intervall kurz vor dem Ablauf steht.

Wird poll() länger als das Keep-Alive-Intervall nicht aufgerufen, schließt der Broker die Verbindung. Vermeiden Sie delay()-Aufrufe, die länger als ein Bruchteil Ihres Keep Alive sind, und ersetzen Sie sie durch millis()-basiertes Timing:

unsigned long lastSend = 0;

void loop() {
  mqttClient.poll();
  if (millis() - lastSend >= 10000) {
    lastSend = millis();
    // hier veröffentlichen
  }
}

Nachrichten veröffentlichen

Das Veröffentlichen ist ein Stream in drei Schritten:

// Einfache QoS-0-Nachricht
mqttClient.beginMessage("connectmq/demo/acm-51e09b/temperature");
mqttClient.print(22.7);
mqttClient.endMessage();

// Retained, QoS 1
mqttClient.beginMessage("connectmq/demo/acm-51e09b/status", true, 1);
mqttClient.print("online");
mqttClient.endMessage();

Die vollständige Signatur lautet beginMessage(topic, retain = false, qos = 0, dup = false). Es gibt außerdem eine Überladung, die die Payload-Größe vorab entgegennimmt: beginMessage(topic, size, retain, qos, dup). Kennen Sie die exakte Größe, nutzen Sie sie: Die Bibliothek kann die Daten dann direkt ins Netzwerk schreiben, statt erst die ganze Nachricht zu puffern. Das ist bei großen Payloads auf Boards mit wenig RAM entscheidend.

endMessage() liefert bei Erfolg 1. Bei QoS 1 und 2 verarbeitet die Bibliothek die Bestätigungspakete während der folgenden poll()-Aufrufe.

Da print() Zahlen, Strings und Floats akzeptiert, können Sie JSON ohne temporären Puffer aufbauen:

mqttClient.beginMessage(topicTelemetry);
mqttClient.print("{\"t\":");
mqttClient.print(temperature, 2);
mqttClient.print(",\"h\":");
mqttClient.print(humidity, 1);
mqttClient.print("}");
mqttClient.endMessage();

Nachrichten empfangen

Abonnieren Sie nach einem erfolgreichen Connect und bei Verwendung einer Clean Session erneut nach jedem Reconnect:

mqttClient.onMessage(onMqttMessage);
mqttClient.subscribe("connectmq/demo/acm-51e09b/cmd/#", 1);

Der Callback erhält nur die Nachrichtengröße. Sie lesen das Topic aus und streamen die Payload:

void onMqttMessage(int messageSize) {
  String topic = mqttClient.messageTopic();
  Serial.print("Topic: ");
  Serial.print(topic);
  Serial.print(", QoS ");
  Serial.print(mqttClient.messageQoS());
  Serial.print(", retained ");
  Serial.println(mqttClient.messageRetain());

  char payload[128];
  int n = 0;
  while (mqttClient.available() && n < (int)sizeof(payload) - 1) {
    payload[n++] = (char)mqttClient.read();
  }
  payload[n] = '\0';
  Serial.println(payload);
}

Nicht gelesene Bytes werden verworfen, sobald die nächste Nachricht eintrifft. Damit sind übergroße Nachrichten unproblematisch: Sie hören einfach an Ihrer Puffergrenze auf zu lesen.

Alternativ zum Callback können Sie in loop() int size = mqttClient.parseMessage(); aufrufen und Nachrichten direkt verarbeiten, wenn size größer als null ist. Verwenden Sie den einen oder den anderen Stil, nicht beide.

Will Messages

Eine Will Message (Last Will and Testament) wird vom Broker veröffentlicht, wenn sich Ihr Gerät ohne Abmeldung trennt, zum Beispiel nach einem Stromausfall oder WLAN-Verlust. Konfigurieren Sie sie vor connect():

const char willTopic[] = "connectmq/demo/acm-51e09b/status";

mqttClient.beginWill(willTopic, true, 1);   // retained, QoS 1
mqttClient.print("offline");
mqttClient.endWill();

if (connectMqtt("broker.connectmq.com", 1883)) {
  mqttClient.beginMessage(willTopic, true, 1);
  mqttClient.print("online");
  mqttClient.endMessage();
}

Wer direkt nach dem Verbinden ein retained online auf demselben Topic veröffentlicht, liefert jedem Dashboard eine zuverlässige Anwesenheitsanzeige: online, solange das Gerät verbunden ist, und offline, sobald der Broker erkennt, dass es weg ist. Das geschieht nach etwa anderthalb Keep-Alive-Intervallen.

Ein vollständiges, reconnect-sicheres Muster

Setzen Sie die Bausteine mit dieser Checkliste zusammen:

  1. WLAN verbinden und auf eine gültige IP-Adresse warten.
  2. ID, Zugangsdaten, Keep Alive und Will setzen.
  3. Verbinden; bei einem Fehler connectError() ausgeben und nach einer Pause erneut versuchen, die mit jedem Fehlschlag länger wird.
  4. Bei Erfolg onMessage registrieren, abonnieren und online retained veröffentlichen.
  5. In loop() das WLAN prüfen, mqttClient.connected() prüfen, poll() aufrufen und über einen millis()-Timer veröffentlichen.

Board-spezifische Versionen dieses Musters finden Sie im Arduino-UNO-R4-WiFi-MQTT-Tutorial und im Leitfaden zu Nano 33 IoT und MQTT mit WiFiNINA. Für ein umfassenderes Projekt zeigt das ESP32-IoT-Tutorial, wie die Geräteseite mit Dashboards und Alarmen zusammenspielt.

Häufige Fehler mit ArduinoMqttClient

  • beginWill() nach connect() aufrufen. Der Will ist Teil des CONNECT-Pakets und muss daher vorher konfiguriert werden.
  • Nur in setup() abonnieren. Nach einem Reconnect mit Clean Session hat der Broker Ihre Subscriptions vergessen. Abonnieren Sie stattdessen in Ihrer Connect-Funktion.
  • Eine Client ID auf mehreren Boards verwenden. Der Broker trennt jedes Mal die ältere Session, wenn sich ein anderes Board verbindet, und erzeugt so eine endlose Reconnect-Schleife.
  • Aus onMessage heraus veröffentlichen. Das funktioniert, aber lesen Sie zuerst die eingehende Payload zu Ende; sonst gehen die ungelesenen Bytes verloren.
  • endMessage() vergessen. Ohne diesen Aufruf wird nichts gesendet, und der nächste beginMessage()-Aufruf schlägt fehl.

Produktivbetrieb: TLS und Zugangsdaten

Für echte Einsätze wechseln Sie zu einem TLS-Client und Port 8883 und authentifizieren sich mit eigenen Zugangsdaten. Ein verwalteter MQTT-Broker wie ConnectMQ stellt für jeden im Portal angelegten Broker Benutzername, Passwort und Client ID aus; die Client ID ist an diese Zugangsdaten gebunden, setzen Sie sie also exakt mit setId(). Das Zertifikat von ConnectMQ stammt von Let's Encrypt, dem die WLAN-Module aktueller Arduino-Boards ab Werk vertrauen. Ersetzen Sie dabei das Demo-Präfix durch eine dauerhafte Topic-Struktur; in Industrie-4.0-Umgebungen folgt sie meist der ISA-95-Hierarchie eines Unified Namespace (UNS), etwa acme/werk-dresden/verpackung/linie-3/status. Lesen Sie vor der Auslieferung die Best Practices für MQTT-Sicherheit.

Starten Sie mit ConnectMQ

ConnectMQ ist ein Cloud-MQTT-Broker mit MQTT 3.1.1 und 5.0, TLS und WebSockets sowie einem Portal mit MQTT-Client im Browser, Live-Topic-Explorer und Schwellenwert-Alarmen. So sehen Sie am einfachsten, was Ihr ArduinoMqttClient-Sketch tatsächlich sendet. Erstellen Sie einen kostenlosen Serverless Broker unter app.connectmq.com, ohne Kreditkarte.

Häufig gestellte Fragen

Ist ArduinoMqttClient besser als PubSubClient?

Keine der beiden ist grundsätzlich besser. ArduinoMqttClient unterstützt Publishing mit QoS 1 und 2 und streamt Payloads, während PubSubClient kleiner ist und eine riesige Auswahl an Beispielen bietet. Wählen Sie ArduinoMqttClient für offizielle Arduino-Boards und wenn Sie QoS brauchen.

Unterstützt ArduinoMqttClient MQTT 5?

Nein, die Bibliothek implementiert MQTT 3.1.1. Moderne Broker bedienen 3.1.1- und 5.0-Clients parallel, sodass Ihr Gerät trotzdem Topics mit MQTT-5-Anwendungen teilen kann.

Warum bricht meine ArduinoMqttClient-Verbindung jede Minute ab?

Meist wird poll() nicht oft genug aufgerufen, das Keep Alive wurde in Sekunden statt in Millisekunden angegeben, oder ein anderer Client verwendet dieselbe Client ID.

Wie groß darf eine Nachricht maximal sein?

Die Bibliothek streamt Payloads, die Grenze setzt also vor allem Ihr Broker. Der öffentliche MQTT-Broker unter broker.connectmq.com akzeptiert bis zu 64 KB pro Nachricht; der kostenlose Serverless-Plan erlaubt 256 KB.

Verwandte Artikel

ESP32 NTP MQTT Zeitstempel: genaue Uhrzeit in jeder Nachricht

Synchronisieren Sie die ESP32-Uhr per NTP, formatieren Sie Zeitstempel in ISO 8601 und Epoch-Millisekunden und hängen Sie sie an MQTT-Payloads, damit Messwerte ihren echten Erfassungszeitpunkt behalten, auch wenn sie verspätet veröffentlicht werden.

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.