ESP-NOW Nach­rich­ten übermitteln

Lese­zeit: 10 Minu­ten


Zie­le des Projekts

Mit ESP-NOW sol­len ESP32-Mikrocontroller

  • Text­nach­rich­ten sen­den, emp­fan­gen und im Seri­el­len Moni­tor anzeigen
  • Daten von Tem­pe­ra­tur­sen­so­ren mes­sen und auf einem LCD/einem OLED anzeigen

ESP-NOW

ESP-NOW ist ein draht­lo­ses Kom­mu­ni­ka­ti­ons­pro­to­koll für die Kom­mu­ni­ka­ti­on zwi­schen zwei oder meh­re­ren ESP32-Con­trol­lern, das die Über­tra­gung kur­zer Daten­pa­ke­te erlaubt. Die betei­lig­ten ESP32-Mikro­con­trol­ler kön­nen ohne Ver­wen­dung von vor­han­de­nen WiFi-Net­zen direkt mit­ein­an­der kom­mu­ni­zie­ren. ESP-NOW ähnelt zwar der klas­si­schen WLAN-Kom­mu­ni­ka­ti­on, es kommt jedoch ohne Rou­ter oder ande­re typi­sche Netz­werk­kom­po­nen­ten aus.
Vor dem Auf­bau einer Kom­mu­ni­ka­ti­on müs­sen die teil­neh­men­den Gerä­te gekop­pelt wer­den. Nach Abschluss der Kopp­lung besteht eine siche­re Ver­bin­dung zwi­schen den kom­mu­ni­zie­ren­den Gerä­ten.
Die Gerä­te iden­ti­fi­zie­ren sich unter­ein­an­der durch den Aus­tausch ihrer MAC (=Media Access Control)-Adressen.

Die Reich­wei­te ist natür­lich sehr von den bau­li­chen Gege­ben­hei­ten abhän­gig. Ich habe eine Kom­bi­na­ti­on von ESP32-C6 und ESP32-C3 sowohl als Sen­der als auch als Emp­fän­ger ver­wen­det. Alle kön­nen die Daten vom Erd­ge­schoss bis ins zwei­te Ober­ge­schoss sen­den und empfangen.

Die Hard­ware

Der Ein­fach­heit hal­ber habe ich aus­schließ­lich Gerä­te ver­wen­det, die über den I²C-Bus ange­steu­ert werden:

Natür­lich kannst du auch ande­re Sen­so­ren verwenden.

I²C-Pins der Mikrocontroller:

Board instal­lie­ren

Als Mikro­con­trol­ler kön­nen belie­bi­ge Modu­le aus der Fami­lie der ESP32-Mikro­con­trol­ler ver­wen­det werden.

MAC-Adres­se ermitteln

Den Kom­mu­ni­ka­ti­ons­part­nern müs­sen die jewei­li­gen MAC-Adres­sen bekannt sein. Jedes Netz­werk­ge­rät hat eine indi­vi­du­el­le MAC-Adres­se.
Das Pro­gramm ermit­telt die MAC-Adres­se und zeigt sie im Seri­el­len Moni­tor an. Die for­ma­tier­te MAC-Adres­se kannst du anschlie­ßend kopie­ren und direkt in den Pro­gram­men verwenden.

#include "WiFi.h"

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

  WiFi.mode(WIFI_STA);
  WiFi.begin();
  
  Serial.print("MAC-Adresse: ");

  // MAC-Adresse ermitteln
  String MACAdresse = WiFi.macAddress();
  Serial.println(MACAdresse);

  String FormatierteMACAdresse;
  Serial.print("Formatierte MAC-Adresse: ");

  int index = 0;
  
  // MAC-Adresse besteht aus 6 durch : getrennte Elemente
  for (int i = 0; i < 6; i++) 
  {
    // index: Abstand zum nächsten Wert 2 Ziffern + :
    FormatierteMACAdresse += "0x" + MACAdresse.substring(index, index + 3);
    index += 3;
  }

  FormatierteMACAdresse.replace(":", ", ");
  Serial.println("{" + FormatierteMACAdresse + "}");
}

void loop() {
  // bleibt leer, Programm läuft nur einmal
}

Funk­tio­nen ESP-NOW

Funk­ti­onBeschrei­bungPara­me­ter
esp_now_init();star­tet ESP-NOWRück­ga­be­wert bei Erfolg: ESP_OK
esp_now_add_peer();fügt einen ESP als Kom­mu­ni­ka­ti­ons­part­ner hinzustruct esp_now_peer_info &peer_info
peer_info.channel -> legt den Über­tra­gungs­ka­nal fest (0 = aktu­el­ler Kanal)
peer_info.peer_addr -> MAC-Adres­se des Kommunikationspartners
peer_info.encrypt -> Nach­richt ver­schlüs­seln (true/false)
Rück­ga­be­wert bei Erfolg: ESP_OK
esp_now_send();Nach­richt sendenPara­me­ter:
MAC-Adresse
Nachricht
Grö­ße der Nachricht
esp_now_register_send_cb(FunktionsName);defi­niert eine Funk­ti­on, die über­prüft, ob eine Nach­richt erfolg­reich gesen­det wurdeRück­ga­be­wert bei Erfolg: ESP_NOW_SEND_SUCCESS
esp_now_register_recv_cb(FunktionsName);defi­niert eine Funk­ti­on, die über­prüft, ob eine Nach­richt erfolg­reich emp­fan­gen wurde
wer­tet den Inhalt der Nach­richt aus
Para­me­ter:
MAC-Adresse
Nachricht
Grö­ße der Nachricht

Text­nach­richt sen­den und empfangen

Sen­der

In einem ers­ten Schritt soll eine kur­ze Text­nach­richt von einem ESP32 an einen ande­ren ESP32 gesen­det wer­den. Der Text ent­hält eine zufäl­lig erzeug­te Zahl.

  • Es müs­sen kei­ne zusätz­li­chen Biblio­the­ken instal­liert wer­den, es wer­den die "Bord­mit­tel" verwendet.
  • Die MAC-Adres­se des Emp­fän­gers muss dem Sen­der bekannt gemacht werden.
  • Die Varia­ble Emp­faen­ger­Info vom Typ esp_now_peer_info_t ent­hält die benö­tig­ten Infor­ma­tio­nen über den Emp­fän­ger:
    peer_address -> MAC-Adres­se
    chan­nel -> Kanal der Ver­bin­dung (0−13) Stan­dard ist 0
    Wenn der Kanal nicht kor­rekt ist, wird beim Sen­den eine Feh­ler­mel­dung aus­ge­ge­ben:
    Peer chan­nel is not equal to the home chan­nel, send fail!
    encrypt = fal­se -> kei­ne Verschlüsselung
  • Die Call­Back-Funk­ti­on esp_now_register_send_cb über­prüft, ob die Nach­richt gesen­det wurde.
  • esp_now_add_peer fügt die Adres­se des Emp­fän­gers hinzu.
  • esp_now_send sen­det die Nach­richt und über­prüft gleich­zei­tig mit esp_err_t, ob das Sen­den erfolg­reich war. Der Funk­ti­on wer­den die Adres­se des Emp­fän­gers, die Daten und die Län­ge der Daten übergeben.
#include "esp_now.h"
#include "WiFi.h"

// MAC-Adresse des Empfängers -> muss angepasst werden
uint8_t EmpfaengerAdresse[] = {0x10, 0xB4, 0x1D, 0x14, 0x72, 0x00};

// enthält die Information über den ESP mit dem kommuniziert werden soll
esp_now_peer_info_t EmpfangerInfo;

void NachrichtGesendet(const uint8_t *EmpfaengerAdresse, esp_now_send_status_t Status) 
{
  if(Status == ESP_NOW_SEND_SUCCESS) Serial.println("Nachricht gesendet");
}

void setup() 
{
  Serial.begin(9600);

  // Stations-Modus
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");

  /*
    Informationen zum ESP hinzufügen (esp_now_peer_info_t)
    peer_address -> MAC-Adresse
    channel -> Kanal der Verbindung (0-13) Standard: 0
    encrypt = false -> keine Verschlüsselung
  */
  // MAC-Adresse des ESPs nach peer_addr kopieren
  memcpy(EmpfangerInfo.peer_addr, EmpfaengerAdresse, 6);
  EmpfangerInfo.channel = 0;
  EmpfangerInfo.encrypt = false;

  if (esp_now_add_peer(&EmpfangerInfo) != ESP_OK) 
  {
    Serial.println("Empfänger konnte nicht hinzugefügt werden!");
    return;
  }

  // anzeigen, ob Nachricht erfolgreich gesendet wurde
  esp_now_register_send_cb((esp_now_send_cb_t) NachrichtGesendet);   
}

void loop() 
{
  int Zahl = random(1, 1000);

  // Zahl in char-Array umwandeln
  String Zufallszahl = String(Zahl);
  Serial.println(Zufallszahl);

  char Daten[Zufallszahl.length() + 1];
  Zufallszahl.toCharArray(Daten, Zufallszahl.length() + 1);

  // Nachricht an Empfänger senden
  esp_err_t Fehler = esp_now_send(EmpfaengerAdresse, (uint8_t *) &Daten, sizeof(Daten) - 1);
  if (Fehler != ESP_OK) Serial.println("Fehler beim Senden an Empfänger ");
  else Serial.println("Nachricht gesendet!");
  delay(5000);
}

Emp­fän­ger

Auf der Sei­te des Emp­fän­gers wird im set­up-Teil eine Call­Back-Funk­ti­on Daten­Emp­fan­gen defi­niert: sie wer­tet die emp­fan­ge­nen Daten aus.

#include "esp_now.h"
#include "WiFi.h"

/*
  Funktion DatenEmpfangen 
  Parameter: 
  MACAdresse
  empfangeneDaten
  LaengeDaten
*/
void DatenEmpfangen(const uint8_t * MACAdresse, const uint8_t * empfangeneDaten, int LaengeDaten) 
{
  Serial.println("Nachricht vom Sender ...");
  Serial.print("Zufallszahl: ");
  for(int i = 0; i < LaengeDaten; i++)
  {
    Serial.print((char)empfangeneDaten[i]);
  }
  Serial.println();

  Serial.println("------------------------");
}
 
void setup() 
{
  Serial.begin(9600);
  
  // WiFi im Stations-Modus starten
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");
  
  // Funktion DatenEmpfangen mit Rückgabewert registrieren 
  esp_now_register_recv_cb(esp_now_recv_cb_t(DatenEmpfangen));
}
 
void loop() 
{
  // bleibt leer, Programm reagiert nur auf die Funktion DatenEmpfangen
}

Sen­sor­da­ten an zwei Emp­fän­ger senden

Ein ESP32 sen­det Mess­da­ten an zwei Emp­fän­ger. Ein DHT20 lie­fert die Daten, sie wer­den auf einem OLED und einem LCD angezeigt.

Sen­der

  • Die MAC-Adres­sen der Emp­fän­ger wer­den in einem ⇒Array definiert.
  • Die Mess­da­ten wer­den in einer ⇒Struk­tur abgelegt.
  • Die Varia­ble Emp­faen­ger­Info vom Typ esp_now_peer_info_t ent­hält die benö­tig­ten Infor­ma­tio­nen über den Emp­fän­ger. Sie wird in einer for-Schlei­fe den jewei­li­gen Emp­fän­gern zugewiesen.
  • Die Mess­da­ten des DHT wer­den den Ele­men­ten des Arrays zuge­ord­net:
    0 -> ers­ter Emp­fän­ger, 1 -> zwei­ter Emp­fän­ger
    Daten[0].Temperatur = dht.getTemperature();
    Daten[0].Luftfeuchtigkeit = dht.getHumidity();
    Daten[1].Temperatur = dht.getTemperature();
    Daten[1].Luftfeuchtigkeit = dht.getHumidity();
  • esp_now_send sen­det die Daten in einer for-Schlei­fe an die Empfänger.

Benö­tig­te Bibliotheken

#include "Adafruit_BME280.h"
#include "esp_now.h"
#include "WiFi.h"

#define MeeresHoehe (1013.25)

// Name des BME280
Adafruit_BME280 bme;

// MAC-Adressen der Empfänger
uint8_t EmpfangerAdresse[2][6] = 
{
  { 0xEC, 0xDA, 0x3B, 0xBD, 0x2F, 0x14 },
  { 0x10, 0xB4, 0x1D, 0x14, 0x72, 0x00 }
};

// Datenstruktur
// muss mit allen Empfängern übereinstimmen
struct Daten_Struktur 
{
  float Temperatur;
  float Luftfeuchtigkeit; 
};

// Daten: Array mit 2 Elementen
Daten_Struktur Daten[2];

// enthält die Information über die ESPs mit denen kommuniziert werden soll
esp_now_peer_info_t EmpfangerInfo[2];

void setup() 
{
  Serial.begin(9600);

  // BME280 starten, bei Misserfolg Meldung anzeigen
  if (!bme.begin(0x77)) 
  {
    Serial.println("BME280 nicht verbunden");
    Serial.println("Verkabelung und/oder HEX-Adresse prüfen!");
    Serial.println("Start mit möglichen HEX-Adressen:");
    Serial.println("bme.begin(0x76);");
    Serial.println("bme.begin(0x77);");
    Serial.println("Programm wird beendet!");
    while (1);
  } 
  else Serial.println("BME280 erfolgreich gestartet!");

  // Stations-Modus
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");

  /*
    Informationen zu den ESPs hinzufügen (esp_now_peer_info_t)
    peer_address -> MAC-Adresse
    channel -> Kanal der Verbindung (0-13) Standard: 0
    encrypt = false -> keine Verschlüsselung
    Durchlauf für alle mit MAC-Adresse definierten ESPs
  */
  for (int i = 0; i < 2; i++) 
  {
    // MAC-Adresse des jeweiligen ESPs nach peer_addr kopieren
    memcpy(EmpfangerInfo[i].peer_addr, EmpfangerAdresse[i], 6);
    EmpfangerInfo[i].channel = 0;
    EmpfangerInfo[i].encrypt = false;

    // konnte die MAC-Adresse zugeordnet werden
    if (esp_now_add_peer(&EmpfangerInfo[i]) != ESP_OK) 
    {
      Serial.println("Empfänger konnte nicht hinzugefügt werden!");
      return;
    }
  } 
}

void loop() 
{
  // Daten des bme280 den Elementen des Arrays zuordnen
  Daten[0].Temperatur = bme.readTemperature();
  Daten[0].Luftfeuchtigkeit = bme.readHumidity();
  Daten[1].Temperatur = bme.readTemperature();
  Daten[1].Luftfeuchtigkeit = bme.readHumidity();

  // Nachricht an 2 Empfänger senden
  for(int i = 0; i < 2; i++)
  {
    // Daten senden und Fehlercode abfragen
    esp_err_t Fehler = esp_now_send(EmpfangerAdresse[i], (uint8_t *) &Daten[i], sizeof(Daten[i]));
    if (Fehler != ESP_OK) 
    {
      Serial.print("Fehler beim Senden an Empfänger ");
      Serial.println(i);
    }
  }
  delay(5000);
}

Emp­fän­ger mit LCD

  • Die Defi­ni­ti­on der struct Daten_Struktur muss beim Sen­der und den Emp­fän­gern übereinstimmen.
  • Die Regis­trie­rung der Funk­ti­on Daten­Emp­fan­gen über die Call­Back-Funk­ti­on esp_now_register_recv_cb sorgt für die Dar­stel­lung der Daten..
#include "esp_now.h"
#include "WiFi.h"

#include "LCDIC2.h"

// 4-zeiliges LCD
LCDIC2 lcd(0x27, 20, 4);

// muss mit der Struktur beim Sender übereinstimmen
struct Daten_Struktur 
{
    float Temperatur;
    float Luftfeuchtigkeit; 
};

// Name für die definierte struct
Daten_Struktur Daten;

/*
  Funktion DatenEmpfangen 
  Parameter: 
  MACAdresse
  empfangeneDaten
  LaengeDaten
*/
void DatenEmpfangen(const uint8_t * MACAdresse, const uint8_t * empfangeneDaten, int LaengeDaten) 
{
  // struct Daten nach empfangeneDaten kopieren
  memcpy(&Daten, empfangeneDaten, sizeof(Daten));

  Serial.print("Temperatur: ");
  String Temperatur = String(Daten.Temperatur);
  Temperatur.replace(".", ",");
  Serial.println(Temperatur +"°C");

  String Luftfeuchtigkeit = String(Daten.Luftfeuchtigkeit);
  Luftfeuchtigkeit.replace(".", ",");
  Serial.print("Luftfeuchtigkeit: ");
  Serial.println(Luftfeuchtigkeit + "%");
  Serial.println("------------------------");

  lcd.setCursor(0, 0);
  lcd.print("Temperatur: ");
  lcd.setCursor(0, 1);
  lcd.print(Temperatur);
  lcd.print("\337C");

  lcd.setCursor(0, 2);
  lcd.print("Luftfeuchtigkeit: ");
  lcd.setCursor(0, 3);
  lcd.print(Luftfeuchtigkeit);
  lcd.print("%");
}
 
void setup() 
{
  // LCD starten
  lcd.begin();

  // Cursor "verstecken"
  lcd.setCursor(false);

  Serial.begin(9600);
  
  // WiFi im Stations-Modus starten
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");
  
  // Funktion DatenEmpfangen mit Rückgabewert registrieren 
  esp_now_register_recv_cb((esp_now_recv_cb_t) DatenEmpfangen);
}
 
void loop() 
{
  // bleibt leer, Programm reagiert nur auf die Funktion DatenEmpfangen
}

Emp­fän­ger mit OLED

#include "esp_now.h"
#include "WiFi.h"

#include "U8g2lib.h"

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

// muss mit der Struktur beim Sender übereinstimmen
struct Daten_Struktur 
{
    float Temperatur;  
    float Luftfeuchtigkeit; 
};

// Name für die definierte struct
Daten_Struktur Daten;

/*
  Funktion DatenEmpfangen 
  Parameter: 
  MACAdresse
  empfangeneDaten
  LaengeDaten
*/
void DatenEmpfangen(const uint8_t *MACAdresse, const uint8_t *empfangeneDaten, int LaengeDaten) 
{
  // struct Daten nach empfangeneDaten kopieren
  memcpy(&Daten, empfangeneDaten, sizeof(Daten));

  Serial.print("Temperatur: ");
  String Temperatur = String(Daten.Temperatur);
  Temperatur.replace(".", ",");
  Serial.println(Temperatur +"°C");

  String Luftfeuchtigkeit = String(Daten.Luftfeuchtigkeit);
  Luftfeuchtigkeit.replace(".", ",");
  Serial.print("Luftfeuchtigkeit: ");
  Serial.println(Luftfeuchtigkeit + "%");
  Serial.println("------------------------");

  oled.setCursor(1, 15);
  oled.print("Temperatur: ");

  oled.setCursor(1, 30);
  oled.print(Temperatur);
  oled.print((char)176);
  oled.print("C");
  oled.setCursor(1, 45);
  oled.print("Luftfeuchtigkeit: ");
  oled.setCursor(1, 60);
  oled.print(Luftfeuchtigkeit);
  oled.print("%");
  oled.sendBuffer();
  oled.clearBuffer();
}
 
void setup() 
{
  oled.begin();

  // Schriftart
  oled.setFont(u8g2_font_helvB12_tf);

  Serial.begin(9600);
  
  // WiFi im Stations-Modus starten
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");
  
  // Funktion DatenEmpfangen mit Rückgabewert registrieren 
  esp_now_register_recv_cb((esp_now_recv_cb_t) DatenEmpfangen);
}
 
void loop() 
{
  // bleibt leer, Programm reagiert nur auf die Funktion DatenEmpfangen
}

Sen­sor­da­ten von zwei Sen­dern an Emp­fän­ger übermitteln

Zwei Sen­der wer­den jeweils mit einem BME280 bestückt, sie lie­fern die gemes­se­nen Daten an einen Empfänger.

Benö­tig­te Bibliothek

Sen­der 0

  • Die struct Daten_Struktur beinhal­tet die ID des Sen­ders als int und Tem­pe­ra­tur, Luft­feuch­tig­keit und Luft­druck als float.
  • Im loop-Teil wer­den die ID des Sen­ders und die Mess­wer­te der Daten­struk­tur (Nach­richt) zugeordnet.
#include "esp_now.h"
#include "WiFi.h"
#include "Adafruit_BME280.h"

#define MeeresHoehe (1013.25)

// Name des BME280
Adafruit_BME280 bme;

// MAC-Adresse des Empfängers -> muss angepasst werden
uint8_t EmpfaengerAdresse[] = { 0xEC, 0xDA, 0x3B, 0xBD, 0x2F, 0x14 };

// enthält die Information über den ESP mit dem kommuniziert werden soll
esp_now_peer_info_t EmpfangerInfo;

// ID -> Kennung des Controllers
// Temperatur/Luftfeuchtigkeit/Luftdruck -> Daten des jeweiligen Sensors
struct Daten_Struktur 
{
  int ID;
  float Temperatur;
  float Luftfeuchtigkeit;
  float Luftdruck;
};

Daten_Struktur Nachricht;

void NachrichtGesendet(const uint8_t *EmpfaengerAdresse, esp_now_send_status_t Status) 
{
  if(Status == ESP_NOW_SEND_SUCCESS) Serial.println("Nachricht gesendet");
}

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

  // BME280 starten, bei Misserfolg Meldung anzeigen
  if (!bme.begin(0x77)) 
  {
    Serial.println("BME280 nicht verbunden");
    Serial.println("Verkabelung und/oder HEX-Adresse prüfen!");
    Serial.println("Start mit möglichen HEX-Adressen:");
    Serial.println("bme.begin(0x76);");
    Serial.println("bme.begin(0x77);");
    Serial.println("Programm wird beendet!");
    while (1);
  } 
  else Serial.println("BME280 erfolgreich gestartet!");

  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  }

  // anzeigen, ob Nachricht erfolgreich gesendet wurde (cb = callback)
  esp_now_register_send_cb((esp_now_send_cb_t)NachrichtGesendet);

  /*
    Informationen zum ESP hinzufügen (esp_now_peer_info_t)
    peer_address -> MAC-Adresse
    channel -> Kanal der Verbindung (0-13) Standard: 0
    encrypt = false -> keine Verschlüsselung
  */
  // MAC-Adresse des ESPs nach peer_addr kopieren
  memcpy(EmpfangerInfo.peer_addr, EmpfaengerAdresse, 6);
  EmpfangerInfo.channel = 0;
  EmpfangerInfo.encrypt = false;

  // Empfänger hinzufügen
  if (esp_now_add_peer(&EmpfangerInfo) != ESP_OK) 
  {
    Serial.println("Empfänger konnte nicht hinzugefügt werden!");
    return;
  }
}

void loop() 
{
  // ID des Controllers
  Nachricht.ID = 0;

  // Daten lesen
  Nachricht.Temperatur = bme.readTemperature();
  Nachricht.Luftfeuchtigkeit = bme.readHumidity();
  Nachricht.Luftdruck = bme.readPressure() / 100.0;

  // Nachricht an Empfänger senden
  esp_err_t Fehler = esp_now_send(EmpfaengerAdresse, (uint8_t *)&Nachricht, sizeof(Nachricht));

  if (Fehler == ESP_OK) 
  {
    Serial.println("Nachricht erfolgreich gesendet!");
  } 
  else 
  {
    Serial.println("Fehler beim Senden der Nachricht!");
  }
  delay(5000);
}

Sen­der 1

#include "esp_now.h"
#include "WiFi.h"
#include "Adafruit_BME280.h"

#define MeeresHoehe (1013.25)

// Name des BME280
Adafruit_BME280 bme;

// MAC-Adresse des Empfängers -> muss angepasst werden
uint8_t EmpfaengerAdresse[] = { 0xEC, 0xDA, 0x3B, 0xBD, 0x2F, 0x14 };

// enthält die Information über den ESP mit dem kommuniziert werden soll
esp_now_peer_info_t EmpfangerInfo;

// ID -> Kennung des Controllers
// Temperatur/Luftfeuchtigkeit/Luftdruck -> Daten des jeweiligen Sensors
struct Daten_Struktur 
{
  int ID;
  float Temperatur;
  float Luftfeuchtigkeit;
  float Luftdruck;
};

Daten_Struktur Nachricht;

void NachrichtGesendet(const uint8_t *EmpfaengerAdresse, esp_now_send_status_t Status) 
{
  if(Status == ESP_NOW_SEND_SUCCESS) Serial.println("Nachricht gesendet");
}

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

  // BME280 starten, bei Misserfolg Meldung anzeigen
  if (!bme.begin(0x76)) 
  {
    Serial.println("BME280 nicht verbunden");
    Serial.println("Verkabelung und/oder HEX-Adresse prüfen!");
    Serial.println("Start mit möglichen HEX-Adressen:");
    Serial.println("bme.begin(0x76);");
    Serial.println("bme.begin(0x77);");
    Serial.println("Programm wird beendet!");
    while (1);
  } 
  else Serial.println("BME280 erfolgreich gestartet!");

  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  }

  // anzeigen, ob Nachricht erfolgreich gesendet wurde (cb = callback)
  esp_now_register_send_cb((esp_now_send_cb_t)NachrichtGesendet);

  /*
    Informationen zum ESP hinzufügen (esp_now_peer_info_t)
    peer_address -> MAC-Adresse
    channel -> Kanal der Verbindung (0-13) Standard: 0
    encrypt = false -> keine Verschlüsselung
  */
  // MAC-Adresse des ESPs nach peer_addr kopieren
  memcpy(EmpfangerInfo.peer_addr, EmpfaengerAdresse, 6);
  EmpfangerInfo.channel = 0;
  EmpfangerInfo.encrypt = false;

  // Empfänger hinzufügen
  if (esp_now_add_peer(&EmpfangerInfo) != ESP_OK) 
  {
    Serial.println("Empfänger konnte nicht hinzugefügt werden!");
    return;
  }
}

void loop() 
{
  // ID des Controllers
  Nachricht.ID = 1;

  // Daten lesen
  Nachricht.Temperatur = bme.readTemperature();
  Nachricht.Luftfeuchtigkeit = bme.readHumidity();
  Nachricht.Luftdruck = bme.readPressure() / 100.0;

  // Nachricht an Empfänger senden
  esp_err_t Fehler = esp_now_send(EmpfaengerAdresse, (uint8_t *)&Nachricht, sizeof(Nachricht));

  if (Fehler == ESP_OK) 
  {
    Serial.println("Nachricht erfolgreich gesendet!");
  } 
  else 
  {
    Serial.println("Fehler beim Senden der Nachricht!");
  }
  delay(5000);
}

Emp­fän­ger

  • Der Daten­struk­tur wer­den drei Bezeich­nun­gen zuge­ord­net (Sen­der, Sender1, Sender2).
  • Das Array Anzahl­Con­trol­ler ent­hält als Ele­men­te die bei­den Sender.
  • die emp­fan­ge­nen Daten müs­sen den jewei­li­gen Sen­dern zuge­ord­net wer­den:
    AnzahlSender[Sender.ID].Temperatur = Sender.Temperatur;
    AnzahlSender[Sender.ID].Luftfeuchtigkeit = Sender.Luftfeuchtigkeit;
    AnzahlSender[Sender.ID].Luftdruck = Sender.Luftdruck;
  • Anschlie­ßend wird die ID des Sen­ders abge­fragt und die Mess­da­ten im Seri­el­len Moni­tor und auf dem LCD dargestellt.
#include "esp_now.h"
#include "WiFi.h"

#include "LCDIC2.h"

// 4-zeiliges LCD
LCDIC2 lcd(0x27, 20, 4);

struct Daten_Struktur 
{
  int ID;
  float Temperatur;
  float Luftfeuchtigkeit;
  float Luftdruck;
};

Daten_Struktur Sender;
Daten_Struktur Sender1;
Daten_Struktur Sender2;

Daten_Struktur AnzahlSender[2] = { Sender1, Sender2 };

void DatenEmpfangen(const uint8_t *MACAdresse, const uint8_t *EmpfangeneDaten, int LaengeDaten) 
{
  // Messdaten in das Array Sender kopieren
  memcpy(&Sender, EmpfangeneDaten, sizeof(Sender));
  
  // die empfangenen Daten anhand der ID (Sender.ID)
  // den Sendern zuordnen
  AnzahlSender[Sender.ID].Temperatur = Sender.Temperatur;
  AnzahlSender[Sender.ID].Luftfeuchtigkeit = Sender.Luftfeuchtigkeit;
  AnzahlSender[Sender.ID].Luftdruck = Sender.Luftdruck;

  // in String umwandeln umd . durch , ersetzen zu können
  String AnzeigeTemperatur = String(AnzahlSender[Sender.ID].Temperatur);
  String AnzeigeLuftfeuchtigkeit = String(AnzahlSender[Sender.ID].Luftfeuchtigkeit);

  // float zu int konvertieren -> Nachkommastellen entfernen
  // String AnzeigeLuftdruck = String(int(AnzahlSender[Sender.ID].Luftdruck));

  // oder mit Nachkommastellen
  String AnzeigeLuftdruck = String(AnzahlSender[Sender.ID].Luftdruck);

  // Sensoren anhand der Sender-Nummer identifizieren 
  // und Daten anzeigen
  if (Sender.ID == 0) 
  {
    // . durch , ersetzen
    AnzeigeTemperatur.replace(".", ",");
    AnzeigeLuftdruck.replace(".", ",");
    AnzeigeLuftfeuchtigkeit.replace(".", ",");

    Serial.print("Esszimmer: ");
    Serial.println(AnzeigeTemperatur + "°C");
    Serial.println(AnzeigeLuftfeuchtigkeit + "% ");
    Serial.println(AnzeigeLuftdruck + " hPA"); 
    
    lcd.setCursor(0, 0);
    lcd.print("Esszimmer: ");
    lcd.print(AnzeigeTemperatur);
    lcd.print("\337C ");
    lcd.setCursor(0, 1);
    lcd.print(AnzeigeLuftfeuchtigkeit +"% ");
    lcd.print(AnzeigeLuftdruck + " hPA"); 
  }

  if (Sender.ID == 1) 
  {
    AnzeigeTemperatur.replace(".", ",");
    AnzeigeLuftdruck.replace(".", ",");
    AnzeigeLuftfeuchtigkeit.replace(".", ",");

    Serial.print("Wohnzimmer: ");
    AnzeigeTemperatur.replace(".", ",");
    Serial.println(AnzeigeTemperatur + "°C");
    Serial.println(AnzeigeLuftfeuchtigkeit + "%");
    Serial.println(AnzeigeLuftdruck + " hPA"); 
   
    lcd.setCursor(0, 2);
    lcd.print("Wohnzimmer: ");
    lcd.print(AnzeigeTemperatur);
    lcd.print("\337C ");
    lcd.setCursor(0, 3);
    lcd.print(AnzeigeLuftfeuchtigkeit + "% ");
    lcd.print(AnzeigeLuftdruck + " hPA"); 
  }

  Serial.println("-----------------");
}

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

  // LCD starten
  lcd.begin();

  // Cursor "verstecken"
  lcd.setCursor(false);

  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");

  esp_now_register_recv_cb((esp_now_recv_cb_t)DatenEmpfangen);
}

void loop() 
{
  // bleibt leer, das Programm reagiert nur auf die Funktion DatenEmpfangen
}

Quel­len


Letz­te Aktua­li­sie­rung: Okt. 15, 2025 @ 7:01