Dans ce tutoriel, nous allons voir comment configurer deux ESP8266 afin d’établir une communication avec le protocole ESP-NOW. L’ESP8266 est une carte de développement intégrant le Bluetooth et 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 ESP8266 ou Wemos x2
- Câble USB A Mâle vers Mini B Mâle x2
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 de l’ESP8266. Un des gros intérêts, mise à part qu’il utilise un réseau dédié, est que l’un ou plusieurs des stations ESP8266 peuvent se connecter au Wifi en parallèle.
EPS-NOW permet aussi de communiquer entre plusieurs cartes ESP8266 et ESP32. Il suffit pour cela d’adapter le code au type de carte.
Code
Pour tester la communication ESP-NOW entre deux ESP8266, nous utilisons la librairie espnow.h disponible à l’installation du gestionnaire de carte. Nous allons définir et envoyer une structure de données entre la carte maître et la carte esclave. Cette structure doit être identique entre les deux cartes pour que les données soient comprises correctement.
Code émetteur
Pour que la carte émettrice puisse communiquer avec une autre carte ESP8266, 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 définir le rôle de l’esp en CONTROLLER dans le setup: esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
#include <espnow.h>//https://github.com/esp8266/Arduino/blob/master/tools/sdk/include/espnow.h #include <ESP8266WiFi.h> uint8_t broadcastAddress[] = {0xDC, 0x4F, 0x22, 0x58, 0xD2, 0xF5};// 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; unsigned long previousTime=0; // callback when data is sent void OnDataSent(uint8_t *mac_addr, uint8_t status) { Serial.print(F("\r\n Master packet sent:\t")); Serial.println(status == 0 ? "Delivery Success" : "Delivery Fail"); } 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("\nReciever initialized : ")); Serial.println(WiFi.macAddress()); // Define Send function esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); esp_now_register_send_cb(OnDataSent); // Register peer esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0); } void loop() { if((millis() -previousTime)>1000){ // Set values to send strcpy(myData.a, "data type char"); myData.b = random(1, 20); myData.c = 1.2; myData.d = "hello"; myData.e = false; // Send message via ESP-NOW uint8_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); if (result == 0) { Serial.println(F("Sent with success")); } else { Serial.println(F("Error sending the data")); } previousTime=millis(); } }
Code récepteur
Dans le code récepteur, 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.
N’oubliez pas de définir le rôle de l’esp en SLAVE dans le setup : esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
#include <espnow.h>// https://github.com/esp8266/Arduino/blob/master/tools/sdk/include/espnow.h #include <ESP8266WiFi.h> // Structure example to receive data // Must match the sender structure typedef struct struct_message { char a[32]; int b; float c; String d; bool e; } struct_message; struct_message myData; // callback when data is received void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) { memcpy(&myData, incomingData, sizeof(myData)); Serial.print("Bytes received: "); Serial.println(len); Serial.print("Char: "); Serial.println(myData.a); Serial.print("Int: "); Serial.println(myData.b); Serial.print("Float: "); Serial.println(myData.c); Serial.print("String: "); Serial.println(myData.d); Serial.print("Bool: "); Serial.println(myData.e); Serial.println(); } void setup() { // Initialize 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("Error initializing ESP-NOW"); return; } Serial.print(F("\nReciever initialized : ")); Serial.println(WiFi.macAddress()); // Define receive function esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); esp_now_register_recv_cb(OnDataRecv); } void loop() { }
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.
Bonus: Communication bidirectionnelle entre deux ESP8266
Nous avons vu comment envoyer des données d’une carte à une autre en utilisant le protocole ESP-NOW. Nous allons voir, maintenant, comment, en modifiant légèrement les codes, on peut obtenir une communication dans les deux sens.
Code Transceiver
#include <espnow.h>//https://github.com/esp8266/Arduino/blob/master/tools/sdk/include/espnow.h #include <ESP8266WiFi.h> const char nom[10]="Master"; //or slave uint8_t broadcastAddress[] = {0xDC, 0x4F, 0x22, 0x58, 0xD2, 0xF5};// REPLACE WITH OTHER STATION MAC ADDRESS // Structure example to send data // Must match the receiver structure typedef struct struct_message { char a[32]; int b; bool c; } struct_message; struct_message dataSent; struct_message dataRcv; unsigned long previousTime=0; // callbacks for sending and receiving data void OnDataSent(uint8_t *mac_addr, uint8_t status) { Serial.print("\r\n"+String(nom)+" packet sent:\t"); Serial.println(status == 0 ? "Delivery Success" : "Delivery Fail"); } void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) { memcpy(&dataRcv, incomingData, sizeof(dataRcv)); Serial.print("\r\nBytes received: "); Serial.println(len); Serial.print("From: "); Serial.println(dataRcv.a); 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_CONTROLLER); //ESP_NOW_ROLE_SLAVE if slave esp_now_register_send_cb(OnDataSent); esp_now_register_recv_cb(OnDataRecv); // Register peer esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0); //ESP_NOW_ROLE_CONTROLLER if slave } void loop() { if((millis() -previousTime)>1000){ // 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(); } }
N.B.: Pour obtenir le même code pour l’émetteur et le récepteur, nous utilisons la même structure de données pour les messages envoyés et reçu. Il est possible de définir des structures différentes en fonction de la provenance du message. Tout en gardant à l’esprit que la carte qui réceptionne doit connaître la structure du message reçu pour pouvoir le déchiffrer.
Pour passer d’un code MASTEr à un code SLAVE, vous devez modifier:
- Le nom de la station nom[10] (Optional)
- L’argument de la fonction esp_now_set_self_role
- L’argument de la fonction esp_now_add_peer
Résultat
Grâce au même code avec quelques légères modification, il est possible d’établir une communication bidirectionnelle entre deux ESP8266
C’est toujour bon de rappeler les bases pour comprendre et avancer.
Merci .
Un tuto court mais efficace