MQTT mit ESP32

Lese­zeit: 7 Minu­ten

Seite als PDF

Ziel des Projekts


Ein ESP32-Mikro­con­trol­ler misst die Tem­pe­ra­tur. Die Daten wer­den an einen MQTT-Ser­ver gesen­det, ein zwei­ter ESP32 emp­fängt die Daten und zeigt sie auf einem OLED an.

Im Bei­spiel sen­det ein ESP32-Wroom die Daten, ein NodeM­CU und ein Ardui­no Nano ESP32 emp­fan­gen die Daten und zei­gen sie auf einem OLED an.

MQTT


MQTT (Mes­sa­ge Queue Tele­me­try Trans­port) ist ein Pro­to­koll für die Über­tra­gung von Daten nach dem Publisher-Sub­scri­ber-Modell. Es besteht aus dem Ser­ver (Bro­ker) und ver­schie­de­nen Kli­en­ten. Einer die­ser Kli­en­ten ver­öf­fent­licht (Publish) zu einem The­ma (Topic) eine Nach­richt und schickt sie an den Bro­ker. Ein ande­rer Kli­ent sen­det eine Anfra­ge (Sub­scri­be) zum Bro­ker und fragt nach Daten (Pay­load) zum fest­ge­leg­ten The­ma. Sind Daten vor­han­den, wer­den sie übermittelt.

Öffent­li­che Broker

Bro­kerPortBenut­zer­na­mePass­wort
test​.mos​quit​to​.org1883
public​.mqt​thq​.com1883
bro​ker​.emqx​.io1883emqxpublic

Benö­tig­te Bauteile

  • ESP32-Wroom/­NodeM­CU/Ar­dui­no Nano ESP32 als Messgerät
  • ESP32-Wroom/­NodeM­CU/Ar­dui­no Nano ESP32 für die Anzeige
  • Lei­tungs­dräh­te
  • OLED
  • DHT22

Der Schalt­plan

Das Pro­gramm

Benö­tig­te Biblio­theken

Funk­tio­nen der Biblio­thek u8g2

Schlüs­sel­wortPara­me­terAkti­on
begin();OLED star­ten
get­Dis­play­Width();Bild­schirm­brei­te feststellen
get­Dis­play­H­eight();Bild­schirm­hö­he feststellen
cle­ar­Dis­play();Bild­schirm dun­kel schalten
setdrawColor(Parameter)0 → schwarz
1 → weiß
Zei­chen­far­be festlegen
setContrast(Parameter)0 ... 255Kon­trast einstellen
setDisplayRotation(U8G2_R*);U8G2_R0 → 0 Grad
U8G2_R1 → 90 Grad
U8G2_R2 → 180 Grad
U8G2_R3 → 270 Grad
Anzei­ge drehen
flipMode(Parameter);0 → nor­ma­le Ausrichtung
1 → 180 Grad drehen
wirk­sam erst bei einer Rotation
Anzei­ge spie­geln (180 Grad)
home();Cur­sor in die lin­ke obe­re Ecke setzen
drawPixel(x-Achse, y-Ach­se)ein­zel­nen Pixel zeichnen
drawLine(StartX, StartX, End­eX, EndeY);Linie zeich­nen
drawHLine(StartX, Star­tY, Länge);hori­zon­ta­le Linie zeichnen
drawVLine(StartX, Star­tY, Länge);ver­ti­ka­le Linie zeichnen
drawFrame(StartX, Star­tY,, Brei­te, Höhe);Recht­eck zeichnen
drawRFrame(StartX, Star­tY, Brei­te, Höhe, Eckenradius);abge­run­de­tes Recht­eck zeichnen
drawBox(StartX, Star­tY, Brei­te, Höhe);aus­ge­füll­tes Recht­eck zeichnen
drawCircle(MittelpunkX, Mit­tel­punk­tY, Radi­us, Kreisausschnitt);U8G2_DRAW_UPPER_RIGHT
U8G2_DRAW_UPPER_LEFT
U8G2_DRAW_LOWER_RIGHT
U8G2_DRAW_LOWER_LEFT
U8G2_DRAW_ALL
Kreis zeich­nen
Vier­tel­kreis oben rechts
Vier­tel­kreis oben links
Vier­tel­kreis unten rechts
Vier­tel­kreis unten links
vol­ler Kreis
drawDisc(MittelpunkX, Mit­tel­punk­tY, Radius);Aus­ge­füll­ten Kreis zeichnen
drawEllipse(StartX, Star­tY, Radi­usX, RadiusY);Ellip­se zeichnen
drawXBM(StartX, Star­tY, Brei­te, Höhe, Array_Bilddatei);XBM-Bild anzei­gen
setCursor(x-Achse, y-Ach­se);Cur­sor setzen
setFont(Schriftart)Bei­spie­le für funk­tio­nie­ren­de Schriftarten:
Schrift­hö­he in Pixeln (px)
6px: u8g2_font_5x7_tr
7px: u8g2_font_torussansbold8_8r 
8px: u8g2_font_ncenB08_tr
10px: u8g2_font_t0_15b_me 
12px: u8g2_font_helvB12_tf 
13px: u8g2_font_t0_22_te
14px: u8g2_font_helvB14_tf
17px: u8g2_font_timB18_tf
18px: u8g2_font_lubB18_tr
20px: u8g2_font_courB24_tf
23px: u8g2_font_timB24_tf
25px: u8g2_font_helvR24_tf
32px: u8g2_font_logisoso32_tf
42px: u8g2_font_fub42_tf
58px: u8g2_font_logisoso58_tf
62px: u8g2_font_logisoso62_tn
Schrift­art
print("Text");
drawStr(StartX, Star­tY ,"Text");
Text schrei­ben
setFontDirection(Wert);0 → nor­mal ausgerichtet
1 → 90 ° gedreht
2 → 180 ° gedreht
3 → 270 ° gedreht
Schreib­rich­tung

Funk­tio­nen der Biblio­thek ArduinoMqtt

Schlüs­sel­wortPara­me­terAkti­on
con­nect()Name des Bro­kers, Port des BrokersBro­ker verbinden
poll();Bro­ker abfragen
begin­Mes­sa­ge();
print();
endMessage();
Min­des­tens Inhalt der Nachricht
optional:
Län­ge der Nachricht, 
auf dem Bro­ker behal­ten (true/false)
Qua­li­tät der Über­mitt­lung der Nachricht
0 = Nach­richt wird ein­mal versendet
eine Über­prü­fung des Emp­fangs durch den Bro­ker fin­det nicht statt
1 = die Nach­richt wird solan­ge ver­sen­det, bis der Bro­ker den Emp­fang bestä­tigt hat
2 = die Nach­richt wird ein­mal gesendet 
es wird sicher gestellt, dass die Nach­richt beim Bro­ker ange­kom­men ist

Dupli­kat sen­den (true/false)
Nach­richt sen­den starten
und mit print() übermitteln
begin­Will();
print();
endWill();
The­ma
Län­ge der Nachricht, 
auf dem Bro­ker behal­ten (true)
Qua­li­tät der Nach­richt (0 .. 2
ver­sucht eine getrenn­te Ver­bin­dung neu aufzubauen
muss vor dem eigent­li­chen Ver­bin­dungs­auf­bau gestar­tet werden
onMes­sa­ge();Funk­ti­on für die Aus­wer­tung der emp­fan­gen Daten
Daten aus­wer­ten
sub­scri­be()Min­des­tens das Thema
optional:
Qua­li­tät der Über­mitt­lung der Nachricht
Kon­trast einstellen

Der Sen­der

#include "ArduinoMqttClient.h"

// ESP8266: NodeMCU, Wemos D1 Mini
// #include "ESP8266WiFi.h"

// ESP32
#include "WiFi.h"
#include "DHT.h"

// Pin des DHT-Sensors
int SENSOR_DHT = 4;

// DHT11
// #define SensorTyp DHT11

// DHT22
#define SensorTyp DHT22

// dht-Sensor einen Namen und Typ zuweisen
DHT dht(SENSOR_DHT, SensorTyp);

char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

WiFiClient wifiClient;

// wifiClient MqttClient zuordnen
MqttClient mqttClient(wifiClient);

const char broker[] = "test.mosquitto.org";
int port = 1883;

/* 
  öffentliche Broker
  const char broker[] = "public.mqtthq.com";
  int port = 1883;

  const char broker[] = "test.mosquitto.org";
  int port = 1883;

  const char broker[] = "broker.emqx.io";
  const char *mqtt_username = "emqx";
  const char *mqtt_password = "public";
  int port = 1883;
*/

// Thema für Senden/Empfangen
const char Messdaten[] = "Messdaten";

// Thema für die "will"-Nachricht für den Versuch die Verbindung 
// neu aufzubauen
const char getrennteVerbindung[] = "getrennteVerbindung";

// Intervall zwischen den Messungen
const long Interval = 5000;
unsigned long vorherigeZeit = 0;

void setup() 
{
  Serial.begin(9600);
  while (!Serial);
  delay(1000);

  WiFi.begin(Router, Passwort);

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

  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  /*
    will-Nachricht:
    wird an den Broker gesendet und versucht eine getrennte Verbindung neu aufzubauen
    Parameter:
    Thema, Länge des gesendeten Strings, Behalten der Anforderung, Qualität der Verbindung
    muss vor dem Aufbau der Verbindung zum Broker festgelegt werden
  */
  String willDaten = "getrennt";
  bool Behalten = true;
  int willQualitaetService= 2;

  // will-Nachricht senden
  mqttClient.beginWill(getrennteVerbindung, willDaten.length(), Behalten, willQualitaetService);
  mqttClient.print(getrennteVerbindung);
  mqttClient.endWill();

  Serial.println("Versuche mit dem Broker " + String(broker) + " zu verbinden ... ");

  delay(1000);

  // Verbindungsversuch
  if (!mqttClient.connect(broker, port)) 
  {
    Serial.print("Verbindung zum Broker gescheitert");

    // Programm anhalten
    while (1);
  }
  Serial.println();

  Serial.println("Mit dem Broker " + String(broker) + " verbunden!");
  Serial.println();

  // dht-Sensor starten
  dht.begin();
}

void loop() 
{
  // Broker abfragen
  mqttClient.poll();

  unsigned long aktuelleZeit = millis();

  // Intervall zwischen den Sendezeiten
  if (aktuelleZeit - vorherigeZeit >= Interval) 
  {
    // letzte Sendezeit sichern
    vorherigeZeit = aktuelleZeit;

    // gemessene Temperatur dht in String umwandeln
    String Temperatur = String(dht.readTemperature(), 1);

    // . durch , ersetzen
    Temperatur.replace(".", ",");

    // gemessene Luftfeuchtigkeit in String umwandeln
    String Luftfeuchtigkeit = String(dht.readHumidity(), 1);

    // . durch , ersetzen
    Luftfeuchtigkeit.replace(".", ",");

    // String Senden zusammenbauen / als Trennzeichen
    String Senden = Temperatur + "/" + Luftfeuchtigkeit;
    Serial.println("Nachricht gesendet:");

    // Anzeige im Seriellen Monitor: String Senden am / trennen
    int Suche = Senden.indexOf("/");

    // String bis zum /
    Temperatur = Senden.substring(0, Suche);

    // String vom ersten Zeichen hinter / bis zum Ende
    Luftfeuchtigkeit = Senden.substring(Suche + 1, Senden.length());

    // Daten im Seriellen Monitor anzeigen
    Serial.println(Temperatur + "°C");
    Serial.println(Luftfeuchtigkeit + "%");
    Serial.println("---------------------");

    // Messdaten senden
    bool Behalten = false;
    int ServiceQualitaet = 2;
    bool Duplikat = false;
    mqttClient.beginMessage(Messdaten, Senden.length(), Behalten, ServiceQualitaet, Duplikat);
    mqttClient.print(Senden);
    mqttClient.endMessage();
  }
}

Der Emp­fän­ger

#include "ArduinoMqttClient.h"

// ESP32
// #include "WiFi.h"

// ESP8266: NodeMCU, Wemos D1 Mini
#include "ESP8266WiFi.h"

#include "U8g2lib.h"

/*
  Typbezeichnung mit Bildschirmgröße in Pixeln
  1 = page buffer mode, F = full screen buffer mode 
  Hardware I2C/Hardware SPI
  Name des OLEDs
  Rotation R0 (keine)
*/
U8G2_SSD1306_128X64_NONAME_1_HW_I2C oled(U8G2_R0, U8X8_PIN_NONE);

// Router SSID/Passwort
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

const char broker[] = "test.mosquitto.org";
int port = 1883;

/* 
  öffentliche Broker
  const char broker[] = "public.mqtthq.com";
  int port = 1883;

  const char broker[] = "test.mosquitto.org";
  int port = 1883;

  const char broker[] = "broker.emqx.io";
  const char *mqtt_username = "emqx";
  const char *mqtt_password = "public";
  int port = 1883;
*/

// Thema  für Senden/Empfangen
const char Messdaten[] = "Messdaten";

/*
  Qualität der Verbindung (0 .. 2)
  0 = Nachricht wird einmal versendet
      eine Überprüfung des Empfangs durch den Broker findet nicht statt
  1 = die Nachricht wird solange versendet, bis der Broker den Empfang bestätigt hat
  2 = die Nachricht wird einmal gesendet, es wird sicher gestellt, dass sie
      beim Broker angekommen ist
*/
int subscribeQoS = 2;

void setup() 
{
  Serial.begin(9600);
  while (!Serial);
  delay(1000);

  WiFi.begin(Router, Passwort);

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  Serial.print("Versuche mit dem Broker " + String(broker) + " zu verbinden ... ");

  // Verbindung zum Broker aufbauen
  if (!mqttClient.connect(broker, port)) 
  {
    Serial.print("Verbindung zum Broker gescheitert");

    // Programm anhalten
    while (1);
  }
  Serial.println();

  Serial.println("Mit dem Broker " + String(broker) + " verbunden!");
  Serial.println();

  // den Rückruf für den Nachrichtenempfang festlegen
  mqttClient.onMessage(empfangeneNachricht);

  // in das Thema Messdaten "einschreiben"
  mqttClient.subscribe(Messdaten, subscribeQoS);

  // OLED starten
  oled.begin();

  // Kontrast maximal 255
  oled.setContrast(200);
  oled.setFont(u8g2_font_helvR24_tf);

  // Zeichenfarbe weiß
  oled.setDrawColor(1);

  // horizontale Schrift
  oled.setFontDirection(0);
}

void loop() 
{
  // Broker abfragen
  mqttClient.poll();
}

void empfangeneNachricht(int NachrichtGroesse) 
{
  Serial.println("Nachricht empfangen: ");

  // Thema der Nachricht empfangen und anzeigen
  String Nachricht = mqttClient.messageTopic();
  Serial.println(Nachricht + " ");

  // Nachricht als String lesen
  String EmpfangeneNachricht = mqttClient.readString();

  // String Anzeige am / trennen
  int Suche = EmpfangeneNachricht.indexOf("/");
  String Temperatur = EmpfangeneNachricht.substring(0, Suche);
  String Luftfeuchtigkeit = EmpfangeneNachricht.substring(Suche + 1, EmpfangeneNachricht.length());

  // Anzeige im Seriellen Monitor
  Serial.println(Temperatur + "°C");
  Serial.println(Luftfeuchtigkeit + "%");
  Serial.println("---------------------");
  Serial.println();

  // Anzeige OLED
  oled.clearDisplay();
  oled.firstPage();

  do 
  {
    oled.setCursor(2, 30);
    oled.print(Temperatur);

    // Grad-Zeichen
    oled.print((char)176);
    oled.print("C");
    oled.setCursor(2, 60);
    oled.print(Luftfeuchtigkeit + "%");

  } 
  while (oled.nextPage());
}

MQTT mit Raspber­ry Pi

Die Ver­bin­dung zu den öffent­li­chen Bro­kern ist nicht ver­schlüs­selt und die Erreich­bar­keit ist nicht garan­tiert. Als Lösung bie­tet sich an mit einem Raspber­ry Pi einen eige­nen Bro­ker zu betreiben.

Raspber­ry Pi als Bro­ker


letz­te Aktua­li­sie­rung: 20. Aug 2024 @ 11:12