fbpixel
Étiquettes : , ,
5
(1)

Dans ce tutoriel, nous allons voir comment configurer un réseau de plusieurs ESP32 avec le protocole ESP-NOW. L’ESP32 est une carte de développement intégrant le Wifi. Elle peut donc se connecter et échanger des données avec des appareils connectés à ce même réseau.

Matériel

  • Ordinateur
  • NodeMCU ESP32 ou NodeMCU ESP8266 ou Wemos x3
  • Câble USB A Mâle vers Mini B Mâle x3

Description ESP-NOW

ESP-NOW est un protocole de communication, développé par Espressif, permettant la communication sans fil de plusieurs appareils sans utiliser de réseau particulier. Il permet l’échange à haute vitesse de petits paquets de données sur les bandes de fréquence 2.4GHz et ce jusqu’à 200m de distance. Il nécessite un appairage initiale mais une fois cela fait la communication est persistante et s’établit d’elle même au démarrage. Un des gros intérêts, mise à part qu’il utilise un réseau dédié, est que l’un ou plusieurs des stations ESP32 ou ESP8266 peuvent se connecter au Wifi en parallèle.

Il est possible grâce à ce protocole de créer un réseau de NodeMCU qui communiquent entre elles.

Code

Nous allons établir une communication bidirectionnelle entre plusieurs ESP32 à l’aide la librairie espnow.h disponible à l’installation du gestionnaire de carte. Nous allons définir et envoyer une structure de données identique pour toute les cartes afin de simplifier le code.

Code Master

Pour que la carte émettrice puisse communiquer avec une autre carte, elle a besoin de son adresse MAC. Vous pouvez récupérer cette adresse au démarrage de la carte réceptrice dans les messages envoyés à partir de la fonction setup() (Serial.println(WiFi.macAddress());). Nous allons définir une fonction qui s’exécute après l’envoie d’un message pour vérifier si la transmission s’est bien passée.

N’oubliez pas de modifier les adresses des cartes esclaves correspondant aux cartes que vous utilisez.

#include <esp_now.h>
#include <WiFi.h>
const char nom[10]="Master"; 
uint8_t broadcastAddress[2][6] = {
 {0x2C, 0xF4, 0x32, 0x15, 0x52, 0x22}, //station0
 {0xA0, 0x20, 0xA6, 0x08, 0x20, 0xD9}  //station1
};// REPLACE WITH RECEIVER MAC ADDRESS
// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
 char a[32];
 int b;
 float c;
 String d;
 bool e;
} struct_message;
struct_message myData;
struct_message dataRcv;
unsigned long previousTime=0;
// callbacks for sending and receiving data
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
 Serial.print(F("\r\nMaster packet sent:\t"));
 Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
 memcpy(&dataRcv, incomingData, sizeof(dataRcv));
 Serial.print("\r\nBytes received: ");
 Serial.println(len);
 Serial.print("From slave: ");
 Serial.println(dataRcv.a);
 Serial.println();
}
void setup() {
 // Init Serial Monitor
 Serial.begin(115200);
 // Set device as a Wi-Fi Station
 WiFi.mode(WIFI_STA);
 // Init ESP-NOW
 if (esp_now_init() != ESP_OK) {
   Serial.println(F("Error initializing ESP-NOW"));
   return;
 }
 Serial.print(F("Reciever initilized : "));
 Serial.println(WiFi.macAddress());
 
 // Define callback functions
 esp_now_register_send_cb(OnDataSent);
 esp_now_register_recv_cb(OnDataRecv);
 // Register peer
 esp_now_peer_info_t peerInfo;
 peerInfo.channel = 0;
 peerInfo.encrypt = false;
   
 memcpy(peerInfo.peer_addr, broadcastAddress[0], 6);
 if (esp_now_add_peer(&peerInfo) != ESP_OK){
   Serial.println("Failed to add peer");
   return;
 }
 memcpy(peerInfo.peer_addr, broadcastAddress[1], 6);
 if (esp_now_add_peer(&peerInfo) != ESP_OK){
   Serial.println("Failed to add peer");
   return;
 }
 
}
void loop() {
 if((millis() -previousTime)>5000){ 
   // Set values to send
   strcpy(myData.a, nom);
   myData.b = random(1, 20);
   myData.c = 1.2;
   
   myData.e = false;
 
   // Send message via ESP-NOW
   myData.d = "Slave0";
   esp_err_t result0 = esp_now_send(broadcastAddress[0], (uint8_t *) &myData, sizeof(myData));
   
   myData.d = "Slave1";
   esp_err_t result1 = esp_now_send(broadcastAddress[1], (uint8_t *) &myData, sizeof(myData));
   previousTime=millis();
 }
}

Code Slave

Dans le code SLAVE, nous allons créer une fonction qui s’exécute à la réception d’un message. Cette fonction permet de traiter les informations reçues. Dans cet exemple, nous affichons les données contenues dans la structure.

Il faudra modifier le code Slave pour chaque carte esclave afin que les données et identifiant soit différent.

#include <esp_now.h>
#include <WiFi.h>
const char nom[10]="Slave0"; 
uint8_t broadcastAddress[] = {0x3C, 0x61, 0x05, 0x30, 0x0A, 0x28};// REPLACE WITH MASTER MAC ADDRESS
//{0xDC, 0x4F, 0x22, 0x58, 0xD2, 0xF5} //station0
// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
 char a[32];
 int b;
 float c;
 String d;
 bool e;
} struct_message;
struct_message dataSent;
struct_message dataRcv;
unsigned long previousTime=0;
// callbacks for sending and receiving data
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
 Serial.print("\r\n"+String(nom)+" packet sent:\t");
 Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
 memcpy(&dataRcv, incomingData, sizeof(dataRcv));
 Serial.print("\r\nBytes received: ");
 Serial.println(len);
 Serial.print("From: ");
 Serial.println(dataRcv.a);
 Serial.print("To: ");
 Serial.println(dataRcv.d);
 Serial.print("Sensor: ");
 Serial.println(dataRcv.b);
 Serial.print("Status: ");
 Serial.println(dataRcv.c);
 Serial.println();
}
void setup() {
 // Init Serial Monitor
 Serial.begin(115200);
 // Set device as a Wi-Fi Station
 WiFi.mode(WIFI_STA);
 // Init ESP-NOW
 if (esp_now_init() != ESP_OK) {
   Serial.println(F("Error initializing ESP-NOW"));
   return;
 }
 Serial.print(F("Reciever initialized : "));
 Serial.println(WiFi.macAddress());
 
 // Define callback functions
 esp_now_register_send_cb(OnDataSent);
 esp_now_register_recv_cb(OnDataRecv);
 // 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(F("Failed to add peer"));
   return;
 }
}
void loop() {
 if((millis() -previousTime)>1500){
   // Set values to send
   strcpy(dataSent.a, nom);
   dataSent.b = random(100, 200);
   dataSent.c = false;
 
   // Send message via ESP-NOW
   esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &dataSent, sizeof(dataSent));
 
   previousTime=millis();
 }
}

(Code pour ESP8266 ci-dessous)

Lorsque vous téléversez pour la première fois le code, observez bien le message du setup contenant l’adresse MAC du récepteur. Vous devez la placer dans le code de l’émetteur pour réussir l’appairage et que la communication fonctionne.

Résultat

Une fois l’adresse MAC de la carte réceptrice définie et les codes téléversés sur chaque carte, la communication s’établit et la structure est envoyée et déchiffrée correctement.

  • Master
  • Slave0
  • Slave1

ATTENTION: lors de la réalisation de ce tutoriel, une des cartes semblait défectueuse et n’envoyait pas de message au maitre alors qu’elle en recevait. A tester et valider avec une autre cartes

Bonus: Communication entre ESP32 et ESP8266

Pour intégrer des cartes ESP8266 dans votre réseau ESP-NOW, il suffit de modifier quelque ligne de code.

Je vous invite à revoir le tutoriel sur ESP-NOW et ESP8266

Pour passer d’un code ESP32 à un code ESP8266, vous devez modifier:

  • Les includes en début de code
  • Rajouter une fonction esp_now_set_self_role avec le bon rôle défini dans chaque cas
  • Modifier les aguments de la fonction esp_now_add_peer
  • Modifier les types des arguments des fonctions OnDataRecv et OnDataSent
#include <espnow.h>//https://github.com/esp8266/Arduino/blob/master/tools/sdk/include/espnow.h
#include <ESP8266WiFi.h>
const char nom[10]="Slave0"; 
uint8_t broadcastAddress[] = {0x3C, 0x61, 0x05, 0x30, 0x0A, 0x28};// REPLACE WITH MASTER MAC ADDRESS
//{0xDC, 0x4F, 0x22, 0x58, 0xD2, 0xF5} //station0
// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
 char a[32];
 int b;
 float c;
 String d;
 bool e;
} struct_message;
struct_message dataSent;
struct_message dataRcv;
unsigned long previousTime=0;
// callbacks for sending and receiving data
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
 Serial.print("\r\n"+String(nom)+" packet sent:\t");
 Serial.println(status == 0 ? "Delivery Success" : "Delivery Fail");
}
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
 memcpy(&dataRcv, incomingData, sizeof(dataRcv));
 Serial.print("\r\nBytes received: ");
 Serial.println(len);
 Serial.print("From: ");
 Serial.println(dataRcv.a);
 Serial.print("To: ");
 Serial.println(dataRcv.d);
 Serial.print("Sensor: ");
 Serial.println(dataRcv.b);
 Serial.print("Status: ");
 Serial.println(dataRcv.c);
 Serial.println();
}
void setup() {
 // Init Serial Monitor
 Serial.begin(115200);
 // Set device as a Wi-Fi Station
 WiFi.mode(WIFI_STA);
 // Init ESP-NOW
 if (esp_now_init() != 0) {
   Serial.println(F("Error initializing ESP-NOW"));
   return;
 }
 Serial.print(F("Reciever initialized : "));
 Serial.println(WiFi.macAddress());
 
 // Define callback functions
 esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
 esp_now_register_send_cb(OnDataSent);
 esp_now_register_recv_cb(OnDataRecv);
 // Register peer
 esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_CONTROLLER, 1, NULL, 0);
}
void loop() {
 if((millis() -previousTime)>1500){
   // Set values to send
   strcpy(dataSent.a, nom);
   dataSent.b = random(100, 200);
   dataSent.c = false;
 
   // Send message via ESP-NOW
   uint8_t result = esp_now_send(broadcastAddress, (uint8_t *) &dataSent, sizeof(dataSent));
 
   previousTime=millis();
 }
}

Bonus: Afficher l’adresse MAC pour la copier

Il est possible d’afficher l’adresse MAC du Master ou des Slaves dans un format qui permet de le copier directement dans broadcastAddress.

void getMacAdress(const uint8_t * mac){
 /*for (int i=0; i<6; i++){ 
    if (mac[i]<10) Serial.print(0,HEX),Serial.print(mac[i],HEX); // FF:FF:FF:FF:FF:FF
    else Serial.print(mac[i],HEX);
    if(i<5) Serial.print(",");
  } */
 Serial.print("{");
 for (int i=0; i<6; i++){ 
   Serial.print("0x");
   if (mac[i]<10) Serial.print(0,HEX),Serial.print(mac[i],HEX);  // {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}
   else Serial.print(mac[i],HEX);
   if(i<5) Serial.print(",");
 }
 Serial.print("}"); 
}

Sources

How useful was this post?

Click on a star to rate it!

Average rating 5 / 5. Vote count: 1

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?