Étiquettes : ,

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.

espnow-esp8266-master-results Communication entre deux ESP8266 avec ESP-NOW
espnow-esp8266-slave-results Communication entre deux ESP8266 avec ESP-NOW

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

espnow-esp8266-transceiver0-results Communication entre deux ESP8266 avec ESP-NOW
espnow-esp8266-transceiver1-results Communication entre deux ESP8266 avec ESP-NOW

Sources