Daten senden und empfangen mit MQTT

MQTT (Teil 3): Daten senden und empfangen

Im letzten Teil hast du den MQTT-Broker kennengelernt und erfahren, wie du ihn mit Mosquitto auf einem Raspberry Pi einrichtest. Nun wird es Zeit für etwas Kommunikation. In diesem Tutorials lernst du, wie du Daten von einem ESP8266 an den Broker sendest. Ein zweiter ESP8266 hat diese Daten abonniert und reagiert entsprechend. Konkret: Du sendest die aktuelle Lichtstärke und wenn es dunkel wird, geht woanders das Licht an.

Für diese Lektion brauchst du folgende Teile:

  • 2x ESP8266-Modul
  • 1x Lichtsensor plus 10kΩ Widerstand
  • 1x LED plus passendem Vorwiderstand
  • Breadboards und Kabel

MQTT-Bibliotheken für Arduino

Um MQTT mit dem ESP8266 zu nutzen, verwendest du die Bibliothek PubSubClient von Nick O’Leary. Sie ist speziell für die Verwendung mit der Arduino-IDE und ESP8266 optimiert.

Installation der PubSubClient-Bibliothek:

  1. Öffne die Arduino-IDE.
  2. Gehe zu Sketch > Bibliothek einbinden > Bibliotheken verwalten (oder klicke auf den entsprechenden Button im Menü links)
  3. Suche nach „PubSubClient“ und installiere die neueste Version.
PubSubClient in der Arduino IDE installieren

Daten an den MQTT-Broker senden

Lass uns einen ersten Sketch erstellen, der eine Verbindung zum MQTT-Broker herstellt und eine Nachricht published.

//Nachrichten an den MQTT-Broker senden

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = "DEIN_WLAN_SSID";
const char* password = "DEIN_WLAN_PASSWORT";
const char* mqtt_server = "IP_ADRESSE_DES_BROKERS";

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Verbinde mit ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi verbunden");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Verbinde mit MQTT...");
    if (client.connect("ESP8266Client")) {
      Serial.println("verbunden");
    } else {
      Serial.print("Fehler, rc=");
      Serial.print(client.state());
      Serial.println(" Nächster Versuch in 5 Sekunden");
      delay(5000);
    }
  }
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  client.publish("esp8266/test", "Hallo vom ESP8266!");
  delay(5000);
}

Ersetze DEIN_WLAN_SSID, DEIN_WLAN_PASSWORT und IP_ADRESSE_DES_BROKERS durch deine eigenen Werte. Falls du die IP deines Raspberry Pis (also des laufenden Brokers) nicht kennst, gib im Terminal Folgendes ein:

hostname -I

Im Terminal siehst du dann die IP-Adresse, zum Beispiel 192.168.0.143

Das Sketch stellt eine Verbindung zum WLAN und dem MQTT-Broker her. In der loop()-Funktion wird alle 5 Sekunden eine Nachricht an das Topic esp8266/test gesendet.

Lade das Sketch auf deinen ESP8266 hoch und öffne den Seriellen Monitor. Du solltest sehen, wie der ESP8266 eine Verbindung herstellt und Nachrichten sendet.

Auf dem Raspberry Pi kannst du die Nachrichten mit mosquitto_sub empfangen. Gibt hierfür den folgenden Befehl in einem neuen Terminal-Fenster (während Mosquitto aktiv ist) ein:

mosquitto_sub -t esp8266/test

So weit, so gut. Als Nächstes testest du die andere Richtung und sendest du Nachrichten vom MQTT-Broker zum ESP8266

Daten vom MQTT-Broker empfangen

In diesem Test installierst du an deinem ESP8266 eine LED, die du vom Terminal (also vom Broker) aus an- und ausschaltest. Verbinde die LED wie folgt:

LED am ESP8266

Nun lade den folgenden Sketch auf deinen ESP8266 – hinterlege jedoch zunächst wieder dein Netzwerk, Passwort und die IP-Adresse des Brokers:

//Nachrichten vom MQTT-Broker empfangen

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = "DEIN_WLAN_SSID";
const char* password = "DEIN_WLAN_PASSWORT";
const char* mqtt_server = "IP_ADRESSE_DES_BROKERS";

WiFiClient espClient;
PubSubClient client(espClient);

const int ledPin = D5;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Verbinde mit ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi verbunden");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Nachricht empfangen [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  if ((char)payload[0] == '1') {
    digitalWrite(ledPin, HIGH);  // LED einschalten
  } else {
    digitalWrite(ledPin, LOW);  // LED ausschalten
  }
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Verbinde mit MQTT...");
    if (client.connect("ESP8266Client")) {
      Serial.println("verbunden");
      client.subscribe("esp8266/led");
    } else {
      Serial.print("Fehler, rc=");
      Serial.print(client.state());
      Serial.println(" Nächster Versuch in 5 Sekunden");
      delay(5000);
    }
  }
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

So funktioniert der Sketch

Interessant in diesem Sketch sind die folgenden zwei Funktionen:

  • Die callback()-Funktion wird aufgerufen, wenn eine Nachricht auf einem abonnierten Topic eintrifft. Wir überprüfen den Inhalt der Nachricht und schalten die LED entsprechend ein oder aus.
  • In der reconnect()-Funktion abonnieren wir das Topic „esp8266/led“, um Steuerbefehle für die LED zu empfangen.

Nachdem du den Sketch auf den ESP8266 geladen hast, kannst du die Funktion wieder im Terminal testen. Steuere dort die LED mit einem der folgenden Befehle. Ersetze IP_ADRESSE_DES_BROKERS hierbei mit der tatsächlichen IP-Adresse deines Raspberry Pi:

mosquitto_pub -h IP_ADRESSE_DES_BROKERS -t "esp8266/led" -m "1"  # LED einschalten
mosquitto_pub -h IP_ADRESSE_DES_BROKERS -t "esp8266/led" -m "0"  # LED ausschalten

Funktioniert? Dann wird es Zeit für den letzten Teil: Hier lässt du zwei ESP8266 miteinander sprechen.

Kommunikation zwischen zwei ESP8266

Bisher hast du das Terminal verwendet, um den MQTT-Broker zu bedienen, also Nachrichten an einen ESP8266 zu senden oder von dort zu empfangen. Aber eigentlich sollte der Broker seine Arbeit im Hintergrund erledigen und nur ein Postbote sein, von dem du nicht viel mitbekommst. Nun sollen also zwei ESP8266 miteinander kommunizieren: Am ersten ist ein Lichtsensor installiert, der die Lichtstärke misst. Fällt diese unter einen bestimmten Wert, sendet er eine entsprechende Nachricht an den Broker. Ein zweiter ESP8266 hat diese Nachrichten abonniert und schaltet bei Bedarf eine LED ein.

Die LED hast du ja bereits installiert. Am anderen ESP8266 verbindest du den Lichtsensor wie folgt:

Lichtsensor am ESP8266

Der Sketch für den Sender

Für den Sender der Nachrichten, also den ESP8266 mit dem angeschlossenen Lichtsensor benötigst du folgenden Sketch:

//Lichtstärke senden

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = "DEIN_WLAN_SSID";
const char* password = "DEIN_WLAN_PASSWORT";
const char* mqtt_server = "IP_ADRESSE_DES_BROKERS";

WiFiClient espClient;
PubSubClient client(espClient);

const int lightSensorPin = A0;
const int lightThreshold = 500;

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Verbinde mit ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi verbunden");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Verbinde mit MQTT...");
    if (client.connect("ESP8266Client_Publisher")) {
      Serial.println("verbunden");
    } else {
      Serial.print("Fehler, rc=");
      Serial.print(client.state());
      Serial.println(" Nächster Versuch in 5 Sekunden");
      delay(5000);
    }
  }
}

void loop() {
  if (client.connected()) {
    client.loop();

    int lightValue = analogRead(lightSensorPin);
    Serial.print("Lichtwert: ");
    Serial.println(lightValue);

    if (lightValue < lightThreshold) {
      client.publish("esp8266/light", "1");  // LED einschalten
      Serial.println("MQTT Message Sent: 1");
    } else {
      client.publish("esp8266/light", "0");  // LED ausschalten
      Serial.println("MQTT Message Sent: 0");
    }

    delay(5000);
  } else {
    reconnect();
  }
}

Oben im Sketch hast du (neben den obligatorischen WLAN- und Broker-Daten) die Möglichkeit, in der Konstanten lightThreshold den Schwellenwert für den Lichtsensor einzustellen. Nach dem Upload siehst du den aktuellen Wert im Seriellen Monitor. Nutze diese Informationen, um einen passenden Schwellenwert für deine Anwendung zu definieren.

Der Sender misst alle 5 Sekunden den Lichtwert und sendet dann die passende Nachricht per MQTT.

Der Sketch für den Empfänger

Nun soll dein zweiter ESP8266 mit der angeschlossenen LED auf diese Nachrichten reagieren. Lade hierfür den folgenden Sketch hoch:

//Lichtstärke empfangen

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = "DEIN_WLAN_SSID";
const char* password = "DEIN_WLAN_PASSWORT";
const char* mqtt_server = "IP_ADRESSE_DES_BROKERS";

WiFiClient espClient;
PubSubClient client(espClient);

const int ledPin = D5;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Verbinde mit ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi verbunden");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Nachricht empfangen [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  if ((char)payload[0] == '1') {
    digitalWrite(ledPin, HIGH);  // LED einschalten
  } else {
    digitalWrite(ledPin, LOW);  // LED ausschalten
  }
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Verbinde mit MQTT...");
    if (client.connect("ESP8266Client_Receiver")) {
      Serial.println("verbunden");
      client.subscribe("esp8266/light");
    } else {
      Serial.print("Fehler, rc=");
      Serial.print(client.state());
      Serial.println(" Nächster Versuch in 5 Sekunden");
      delay(5000);
    }
  }
}

void loop() {
  if (client.connected()) {
    client.loop();
  } else {
    reconnect();
  }
}

Dieser Sketch unterscheidet sich nur leicht von jenem, mit dem du die LED per Terminal gesteuert hast. Eine Sache ist jedoch wichtig, wenn du zwei ESP8266 miteinander über den MQTT-Broker kommunizieren lässt: Sie müssen unterschiedliche Namen haben.

Den Namen, mit dem sich dein ESP8266 beim Broker anmeldet, definierst du in der folgenden Funktion (recht weit unten im Sketch):

client.connect("ESP8266Client_Receiver")

Und das war es schon, mehr benötigst du für eine einfache Kommunikation zweier ESP8266 nicht. Teste nun alle drei Geräte (Broker, Sender und Empfänger) und schaue, ob die LED angeht, wenn das Licht ausgeht.

Bausätze für dein nächstes Projekt

Alles, was du für dein nächstes Projekt brauchst – Bausätze inklusive Anleitung als E-Book und der benötigten Hardware.

ESP8266 Projekt

Wetterstation & Vorhersage

Miss die aktuelle Temperatur und Luftfeuchtigkeit und zeige dazu die Wettervorhersage auf einem OLED-Display an.

Bausatz anschauen

Arduino Projekt

Pflanzenwächter

Braucht deine Pflanze Wasser? Dieses Arduino Projekt gibt dir Bescheid, wenn es so weit ist.

Bausatz anschauen

ESP8266 Projekt

Webserver

Lerne, wie du mit deinem Webserver Messdaten ausgibst, Geräte steuerst und dir mit HTML und CSS ein Interface erstellst.

Bausatz anschauen

Arduino Projekt

Wetterstation

Baue deine eigene Wetterstation, die dir Temperatur und Luftfeuchtigkeit anzeigt.

Bausatz anschauen

Auch interessant

Mehr Projekte für Arduino, ESP32, Raspi & Co
Werde Mitglied bei Pollux Labs und finde dein nächstes Projekt. Zum Beispiel:
Über 100 Maker sind bereits Mitglied bei Pollux Labs
  • ESP32 Internetradio
  • Arduino Wetterstation
  • ESP8266 & Raspi Webserver
  • Automatische Bewässerung
  • ... und viele mehr!