Etiquetas: ,

En este tutorial, veremos cómo configurar dos ESP8266 para establecer comunicación utilizando el protocolo ESP-NOW. El ESP8266 es una placa de desarrollo que integra Bluetooth y WiFi. Por lo tanto, puede conectarse e intercambiar datos con dispositivos conectados a la misma red.

Hardware

  • Ordenador
  • NodeMCU ESP8266 o Wemos x2
  • Cable USB A macho a Mini B macho x2

Descripción ESP-NOW

ESP-NOW es un protocolo de comunicación desarrollado por Espressif que permite la comunicación inalámbrica entre varios dispositivos sin necesidad de una red específica. Permite intercambiar pequeños paquetes de datos a alta velocidad a través de las bandas de frecuencia de 2,4 GHz, a una distancia de hasta 200 m. Requiere un emparejamiento inicial, pero una vez realizado la comunicación es persistente y se establece cuando se pone en marcha el ESP8266. Una de las grandes ventajas, además de que utiliza una red dedicada, es que una o varias estaciones ESP8266 pueden conectarse al Wifi en paralelo.

EPS-NOW también se puede utilizar para comunicarse entre varias tarjetas ESP8266 y ESP32. Basta con adaptar el código al tipo de tarjeta.

Código

Para probar la comunicación ESP-NOW entre dos ESP8266s, utilizamos la librería espnow.h disponible cuando se instala el gestor de tarjetas. Vamos a definir y enviar una estructura de datos entre la tarjeta maestra y la tarjeta esclava. Esta estructura debe ser idéntica entre las dos tarjetas para que los datos se entiendan correctamente.

Código émetteur

Para que la tarjeta emisora pueda comunicarse con otra tarjeta ESP8266, necesita su dirección MAC. Puede recuperar esta dirección cuando la tarjeta receptora se inicia a partir de los mensajes enviados mediante la función setup() (Serial.println(WiFi.macAddress());). Vamos a definir una función que se ejecute después de enviar un mensaje para comprobar que la transmisión se ha realizado correctamente.

No olvides establecer el rol de esp a CONTROLADOR en la configuración: 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();
  }
}

Código récepteur

En el código del receptor, crearemos una función que se ejecuta cuando se recibe un mensaje. Esta función se utiliza para procesar la información recibida. En este ejemplo, mostramos los datos contenidos en la estructura.

No olvides definir el rol de esp como ESCLAVO en la configuración: 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() {
}

Cuando cargues el código por primera vez, fíjate bien en el mensaje de configuración que contiene la dirección MAC del receptor. Debes introducirla en el código del transmisor para garantizar el emparejamiento y la comunicación correctos.

Resultados

Una vez definida la dirección MAC de la tarjeta receptora y cargados los códigos en cada tarjeta, se establece la comunicación y la estructura se envía y descifra correctamente.

espnow-esp8266-master-results Comunicación entre dos ESP8266 con ESP-NOW
espnow-esp8266-slave-results Comunicación entre dos ESP8266 con ESP-NOW

Bonus: Comunicación bidireccional entre dos ESP8266s

Hemos visto cómo enviar datos de una tarjeta a otra utilizando el protocolo ESP-NOW. Ahora vamos a ver cómo, modificando ligeramente los códigos, podemos obtener una comunicación bidireccional.

Código 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.: Para obtener el mismo código para el emisor y el receptor, utilizamos la misma estructura de datos para los mensajes enviados y recibidos. Es posible definir estructuras diferentes en función del origen del mensaje. No obstante, hay que tener en cuenta que la tarjeta receptora debe conocer la estructura del mensaje recibido para poder descifrarlo.

Para pasar de un código MASTEr a un código ESCLAVO, es necesario modificar el código:

  • nombre de la estación nombre[10] (Opcional)
  • argumento de la función esp_now_set_self_role
  • argumento de la función esp_now_add_peer

Resultados

Utilizando el mismo código con unas ligeras modificaciones, es posible establecer una comunicación bidireccional entre dos ESP8266.

espnow-esp8266-transceiver0-results Comunicación entre dos ESP8266 con ESP-NOW
espnow-esp8266-transceiver1-results Comunicación entre dos ESP8266 con ESP-NOW

Fuentes