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).

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

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.

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.

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.

- 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 !
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(){
}
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.

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

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

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();
}
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.

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

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.

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.
-
Carte d'extension ESP32 30 broches ESP32 Shield Development Board Support ESP-WROOM-32 pour carte d'extension ESP32-DevKitC-32 ESP32 ESP32 30P DEVKIT -V1 Power Module Board ESP32S Type-C MicroUSBCompatible avec ArduinoIDE mixly, mind+ et d'autres logiciels de programmation Prise en charge de la tension externe VIN, entrée 5-12 V, version entrée 5,5 V) Puce pilote USB : CH340C, avec une bonne compatibilité du système, une vitesse de téléchargement plus élevée, et plus de stabilité. Puce de contrôle principale : prise en charge ESP32-DOWDQ6-V3 MCU double cœur 32 bits WiFi intégré, compatible Bluetooth Prend en charge l'alimentation USB, l'alimentation externe de 3,3 V et l'alimentation VIN, trois types d'alimentation : mode de développement