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:
- Öffne die Arduino-IDE.
- Gehe zu Sketch > Bibliothek einbinden > Bibliotheken verwalten (oder klicke auf den entsprechenden Button im Menü links)
- Suche nach „PubSubClient“ und installiere die neueste Version.
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:
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:
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.