Communication bidirectionnelle ESP-NOW entre les cartes ESP32

Communication bidirectionnelle ESP-NOW entre les cartes ESP32

Dans ce guide, nous allons vous montrer comment établir une communication bidirectionnelle entre deux cartes ESP32 à l’aide du protocole de communication ESP-NOW. À titre d’exemple, deux cartes ESP32 échangeront des lectures de capteur (avec une portée en champ libre allant jusqu’à 220 mètres ~ 722 pieds).

Communication bidirectionnelle ESP-NOW entre les cartes ESP32

Regardez la vidéo de présentation

Pour une introduction au protocole ESP-NOW, vous pouvez regarder la vidéo suivante :

YouTube video

Si vous voulez en savoir plus sur ESP-NOW, vous pouvez lire ce guide : Premiers pas avec ESP-NOW (ESP32 avec Arduino IDE).

Présentation d’ESP-NOW

ESP-MAINTENANT est un protocole de communication sans connexion développé par Espressif qui se caractérise par une transmission par paquets courts. Ce protocole permet à plusieurs appareils de se parler sans utiliser le Wi-Fi.

ESP-MAINTENANT - Logo ESP32

Il s’agit d’un protocole de communication rapide qui peut être utilisé pour échanger de petits messages (jusqu’à 250 octets) entre les cartes ESP32. ESP-NOW est très polyvalent et vous pouvez avoir une communication unidirectionnelle ou bidirectionnelle dans différents arrangements.

Dans ce tutoriel, nous allons vous montrer comment établir une communication bidirectionnelle entre deux cartes ESP32.

Protocole de communication bidirectionnelle ESP-NOW ESP32

Noter: Lisez notre guide de démarrage ESP-NOW pour une introduction complète au protocole ESP-NOW avec ESP32.

Aperçu du projet

Le diagramme suivant montre une vue d’ensemble de haut niveau du projet que nous allons construire.

Communication bidirectionnelle ESP-NOW - Envoyer des lectures de capteur entre les cartes
  • Dans ce projet, nous aurons deux cartes ESP32. Chaque carte est connectée à un écran OLED et à un capteur BME280 ;
  • Chaque carte obtient des lectures de température, d’humidité et de pression de leurs capteurs correspondants ;
  • Chaque carte envoie ses lectures à l’autre carte via ESP-NOW ;
  • Lorsqu’une carte reçoit les lectures, elle les affiche sur l’écran OLED ;
  • Après avoir envoyé les lectures, la carte affiche sur l’OLED si le message a été délivré avec succès ;
  • Chaque carte doit connaître l’adresse MAC de l’autre carte pour envoyer le message.

Dans cet exemple, nous utilisons une communication bidirectionnelle entre deux cartes, mais vous pouvez ajouter plus de cartes à cette configuration et faire en sorte que toutes les cartes communiquent entre elles.

Conditions préalables

Avant de poursuivre ce projet, assurez-vous de vérifier les prérequis suivants.

Complément ESP32 Arduino IDE

Nous allons programmer l’ESP32 à l’aide de l’IDE Arduino. Par conséquent, avant de poursuivre ce didacticiel, vous devez avoir installé le module complémentaire ESP32 dans votre IDE Arduino. Suivez le guide suivant :

Installer des bibliothèques

Installez les bibliothèques suivantes dans votre IDE Arduino. Ces bibliothèques peuvent être installées via le gestionnaire de bibliothèque Arduino. Aller à Esquisser > Inclure la bibliothèque> Gérer les bibliothèques et recherchez le nom de la bibliothèque.

Pièces requises

Pour ce tutoriel, vous avez besoin des pièces suivantes :

Vous pouvez utiliser les liens précédents ou accéder directement à MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

1644623288 94 Communication bidirectionnelle ESP NOW entre les cartes ESP32

Obtenir l’adresse MAC des cartes

Pour envoyer des messages entre chaque carte, nous avons besoin de connaître leur adresse MAC. Chaque carte a une adresse MAC unique (découvrez comment obtenir et modifier l’adresse MAC ESP32).

Téléchargez le code suivant sur chacune de vos cartes pour obtenir leur adresse MAC.

// Complete Instructions to Get and Change ESP MAC Address: https://Raspberryme.com/get-change-esp32-esp8266-mac-address-arduino/

#include "WiFi.h"
 
void setup(){
  Serial.begin(115200);
  WiFi.mode(WIFI_MODE_STA);
  Serial.println(WiFi.macAddress());
}
 
void loop(){

}

Afficher le code brut

Après avoir téléchargé le code, appuyez sur le bouton RST/EN et l’adresse MAC devrait s’afficher sur le moniteur série.

Adresse MAC de la carte ESP32 avec moniteur série Arduino IDE

Notez l’adresse MAC de chaque carte pour les identifier clairement.

Étiquette d'adresse MAC de la carte ESP32

Diagramme schématique

Câblez un écran OLED et un capteur BME280 sur chaque carte ESP32. Suivez le diagramme schématique suivant.

Schéma de câblage ESP32 vers capteur BME280 et écran OLED

Vous pouvez utiliser le tableau suivant comme référence lors du câblage du capteur BME280.

BME280 ESP32
NIV 3.3V
Terre Terre
SCL GPIO 22
SDA GPIO 21

Vous pouvez également suivre le tableau suivant pour câbler l’écran OLED à l’ESP32.

Écran OLED ESP32
Terre Terre
VCC NIV
SCL GPIO 22
SDA GPIO 21

En savoir plus sur l’interfaçage de plusieurs périphériques I2C avec l’ESP32.

ESP32 Communication bidirectionnelle Code ESP-NOW

Téléchargez le code suivant sur chacun de vos tableaux. Avant de télécharger le code, vous devez entrer l’adresse MAC de l’autre carte (la carte à laquelle vous envoyez des données).

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/esp-now-two-way-communication-esp32/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <esp_now.h>
#include <WiFi.h>

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Adafruit_BME280 bme;

// REPLACE WITH THE MAC Address of your receiver 
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

// Define variables to store BME280 readings to be sent
float temperature;
float humidity;
float pressure;

// Define variables to store incoming readings
float incomingTemp;
float incomingHum;
float incomingPres;

// Variable to store if sending data was successful
String success;

//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {
    float temp;
    float hum;
    float pres;
} struct_message;

// Create a struct_message called BME280Readings to hold sensor readings
struct_message BME280Readings;

// Create a struct_message to hold incoming sensor readings
struct_message incomingReadings;

// Callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
  if (status ==0){
    success = "Delivery Success :)";
  }
  else{
    success = "Delivery Fail :(";
  }
}

// Callback when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
  Serial.print("Bytes received: ");
  Serial.println(len);
  incomingTemp = incomingReadings.temp;
  incomingHum = incomingReadings.hum;
  incomingPres = incomingReadings.pres;
}
 
void setup() {
  // Init Serial Monitor
  Serial.begin(115200);

  // Init BME280 sensor
  bool status = bme.begin(0x76);  
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  // Init OLED display
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
 
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  // Register for a callback function that will be called when data is received
  esp_now_register_recv_cb(OnDataRecv);
}
 
void loop() {
  getReadings();
 
  // Set values to send
  BME280Readings.temp = temperature;
  BME280Readings.hum = humidity;
  BME280Readings.pres = pressure;

  // Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &BME280Readings, sizeof(BME280Readings));
   
  if (result == ESP_OK) {
    Serial.println("Sent with success");
  }
  else {
    Serial.println("Error sending the data");
  }
  updateDisplay();
  delay(10000);
}
void getReadings(){
  temperature = bme.readTemperature();
  humidity = bme.readHumidity();
  pressure = (bme.readPressure() / 100.0F);
}

void updateDisplay(){
  // Display Readings on OLED Display
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println("INCOMING READINGS");
  display.setCursor(0, 15);
  display.print("Temperature: ");
  display.print(incomingTemp);
  display.cp437(true);
  display.write(248);
  display.print("C");
  display.setCursor(0, 25);
  display.print("Humidity: ");
  display.print(incomingHum);
  display.print("%");
  display.setCursor(0, 35);
  display.print("Pressure: ");
  display.print(incomingPres);
  display.print("hPa");
  display.setCursor(0, 56);
  display.print(success);
  display.display();
  
  // Display Readings in Serial Monitor
  Serial.println("INCOMING READINGS");
  Serial.print("Temperature: ");
  Serial.print(incomingReadings.temp);
  Serial.println(" ºC");
  Serial.print("Humidity: ");
  Serial.print(incomingReadings.hum);
  Serial.println(" %");
  Serial.print("Pressure: ");
  Serial.print(incomingReadings.pres);
  Serial.println(" hPa");
  Serial.println();
}

Afficher le code brut

Comment fonctionne le code

Nous avons expliqué en détail comment interagir avec l’écran OLED et avec le capteur BME280 dans les didacticiels précédents. Ici, nous allons simplement jeter un coup d’œil aux parties pertinentes en ce qui concerne ESP-NOW.

Le code est bien commenté afin que vous compreniez ce que fait chaque ligne de code.

Pour utiliser ESP-NOW, vous devez inclure les bibliothèques suivantes.

#include <esp_now.h>
#include <WiFi.h>

Dans la ligne suivante, insérez l’adresse MAC de la carte réceptrice :

uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x07, 0x0D, 0x64};

Créez des variables pour stocker les lectures de température, d’humidité et de pression du capteur BME280. Ces lectures seront transmises à l’autre carte :

// Define variables to store BME280 readings to be sent
float temperature;
float humidity;
float pressure;

Créez des variables pour stocker les relevés des capteurs provenant de l’autre carte :

// Define variables to store incoming readings
float incomingTemp;
float incomingHum;
float incomingPres;

La variable suivante stockera un message de réussite si les lectures sont livrées avec succès à l’autre carte.

// Variable to store if sending data was successful
String success;

Créez une structure qui stocke les relevés d’humidité, de température et de pression.

typedef struct struct_message {
  float temp;
  float hum;
  float pres;
} struct_message;

Ensuite, vous devez créer deux instances de cette structure. Un pour recevoir les lectures et un autre pour stocker les lectures à envoyer.

le BME280Lectures stockera les lectures à envoyer.

// Create a struct_message called BME280Readings to hold sensor readings
struct_message BME280Readings;

le lectures entrantes stockera les données provenant de l’autre carte.

// Create a struct_message to hold incoming sensor readings
struct_message incomingReadings;

Ensuite, nous devons créer deux fonctions de rappel. L’un sera appelé lors de l’envoi des données et l’autre lors de la réception des données.

Fonction de rappel OnDataSent()

le OnDataSent() La fonction sera appelée lorsque de nouvelles données seront envoyées. Cette fonction imprime simplement si le message a été livré avec succès ou non. Si le message est livré avec succès, la variable d’état renvoie 0, nous pouvons donc définir notre message de réussite sur « Réussite de la livraison »:

Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
if (status ==0) {
  success = "Delivery Success :)";
}

Si le message de réussite renvoie 1, cela signifie que la livraison a échoué :

else {
  success = "Delivery Fail :(";
}

Fonction de rappel OnDataRecv()

le OnDataRecv() La fonction sera appelée lorsqu’un nouveau paquet arrivera.

void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {

Nous enregistrons le nouveau paquet dans le lectures entrantes structure que nous avons créée précédemment :

memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));

Nous imprimons la longueur du message sur le moniteur série. Vous ne pouvez envoyer que 250 octets dans chaque paquet.

Serial.print("Bytes received: ");
Serial.println(len);

Ensuite, stockez les lectures entrantes dans leurs variables correspondantes. Pour accéder à la variable de température à l’intérieur lectures entrantes structure, il vous suffit d’appeler lectures entrantes.temp comme suit:

incomingTemp = incomingReadings.temp;

Le même processus est effectué pour les autres variables :

incomingHum = incomingReadings.hum;
incomingPres = incomingReadings.pres;

mettre en place()

Dans le mettre en place()initialisez ESP-NOW.

if (esp_now_init() != ESP_OK) {
  Serial.println("Error initializing ESP-NOW");
  return;
}

Ensuite, inscrivez-vous au OnDataSent fonction de rappel.

esp_now_register_send_cb(OnDataSent);

Pour envoyer des données à une autre carte, vous devez la coupler en tant que pair. Les lignes suivantes enregistrent et ajoutent un nouveau pair.

// Register peer
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;

// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
  Serial.println("Failed to add peer");
  return;
}

Inscrivez-vous pour le OnDataRecv fonction de rappel.

esp_now_register_recv_cb(OnDataRecv);

boucler()

Dans le boucler()on appelle le getLectures() fonction chargée d’obtenir de nouvelles lectures de température du capteur. Cette fonction est créée après la boucler().

Après avoir obtenu de nouvelles lectures de température, d’humidité et de pression, nous mettons à jour notre BME280Lecture structure avec ces nouvelles valeurs :

BME280Readings.temp = temperature;
BME280Readings.hum = humidity;
BME280Readings.pres = pressure;

Ensuite, nous pouvons envoyer le BME280Lectures structure via ESP-NOW :

// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &BME280Readings, sizeof(BME280Readings));

if (result == ESP_OK) {
  Serial.println("Sent with success");
}
else {
  Serial.println("Error sending the data");
}

Enfin, appelez le mettre à jour l’affichage() fonction qui mettra à jour l’affichage OLED avec les lectures provenant de l’autre carte ESP32.

updateDisplay();

le boucler() est exécuté toutes les 10 secondes.

C’est à peu près comme ça que le code fonctionne. Vous devez télécharger le code sur vos deux tableaux. Il vous suffit de modifier le code avec l’adresse MAC de la carte à laquelle vous envoyez des données.

Lecture recommandée: Guide pour écran OLED avec ESP32 et guide pour capteur BME280 avec ESP32.

Manifestation

Après avoir téléchargé le code sur les deux cartes, vous devriez voir l’OLED afficher les lectures du capteur de l’autre carte, ainsi qu’un message de livraison réussie.

Démonstration de données d'échange de protocole ESP32 ESP-NOW

Comme vous pouvez le voir, cela fonctionne comme prévu :

Démonstration de données d'échange de protocole ESP32 ESP-NOW

Nous avons testé la portée de communication entre les deux cartes et nous sommes en mesure d’obtenir une communication stable jusqu’à 220 mètres (environ 722 pieds) en champ libre. Dans cette expérience, les deux antennes embarquées ESP32 pointaient l’une vers l’autre.

Test de portée de communication ESP-NOW avec les cartes ESP32

Conclusion

Dans ce tutoriel, nous vous avons montré comment établir une communication bidirectionnelle avec deux cartes ESP32 à l’aide d’ESP-NOW. Il s’agit d’un protocole de communication très polyvalent qui peut être utilisé pour envoyer des paquets jusqu’à 250 octets. Le protocole de communication ESP-NOW peut également être utilisé avec les cartes ESP8266 : Mise en route avec ESP-NOW (ESP8266 NodeMCU avec Arduino IDE).

À titre d’exemple, nous vous avons montré l’interaction entre deux cartes, mais vous pouvez ajouter plusieurs cartes à votre configuration. Vous avez juste besoin de connaître l’adresse MAC de la carte à laquelle vous envoyez des données.

Nous publierons d’autres tutoriels sur ESP-MAINTENANT, alors restez à l’écoute. De plus, écrivez un commentaire ci-dessous en indiquant quel tutoriel vous aimeriez voir avec ESP-NOW.

Pour en savoir plus sur la carte ESP32, jetez un œil à nos ressources :

Merci d’avoir lu.