OBJETIVOS
El objetivo de esta práctica es explicar, de manera clara y sencilla, el protocolo de comunicación ESP-NOW.
Este protocolo nos permite realizar una comunicación de alta eficiencia entre procesadores ESP, utilizando un protocolo privado desarrollado por Espressif. Este protocolo es compatible con cualquiera de los modos de conexión WiFi de los procesadores (ACCESS POINT, STATION o ACCESS POINT + STATION), dando una mayor flexibilidad al uso de las tarjetas.
La comunicación ESP-NOW es del tipo maestro/esclavo donde tenemos un maestro y, potencialmente, múltiples esclavos. Cada dispositivo se puede comunicar con un máximo de 20 pares (de los cuales únicamente 10 pueden tener clave de comunicación si no se utiliza conexión WiFi o es de tipo STATION y 6 si es de tipo ACCESS POINT o ACCESS POINT + STATION).
Las conexiones entre pares son muy rápidas, aproximadamente 10 veces más rápidas que una conexión WiFi. Así mismo, una vez conectados los pares, las conexiones son «persistentes«, lo que facilita una comunicación inmediata entre los pares.
Esta comunicación tan fluida reduce sensiblemente el consumo eléctrico, siendo algo reseñable para el uso en sensores o mandos inalámbricos conectados a baterías, posibilitando que en unos cientos de milisegundos, seamos capaces de activar un procesador ESP desde el reposo, tomar un dato o enviar una orden y volver el procesador a situación de reposo. Esto incrementa la duración de la batería.
Ejemplo práctico
Al final de esta página, para dar un uso a las explicaciones teóricas, se ha desarrollado un el ejemplo práctico en el que se comunican dos circuitos independientes mediante el protocolo ESP-NOW . Para simplificar la programación los circuitos, no se han implementado conexiones WiFi en ningún caso.
El funcionamiento de los circuitos es básicamente como se describe a continuación:
- El circuito maestro toma lecturas del voltaje que deja pasar un potenciómetro conectado en la entrada analógica de una placa NodeMCU (ESP8266). La placa, mediante la comunicación ESP-NOW, envía los datos al circuito esclavo. Adicionalmente se envían al circuito esclavo las lecturas del milisegundo en el que se realiza cada una de las comunicaciones (tomando como referencia el momento en el que se encendió la placa).
- El circuito esclavo dispone de una placa Mini-NodeMCU (ESP8266) que recibe ambas lecturas. En función de la lectura del voltaje, traslada el valor para regular la intensidad de iluminación de un LED conectado a una salida PWM de la placa.
MATERIAL NECESARIO
CONCEPTOS BÁSICOS DE LA COMUNICACIÓN ESP-NOW
Papeles de los dispositivos en la comunicación ESP-NOW
La comunicación ESP-NOW es una comunicación entre pares (maestro y esclavo). Es el dispositivo maestro quien gobierna toda la iniciativa de comunicación y los esclavos solo responden a la petición del maestro, si los corresponde.
Existe la posibilidad de que un dispositivo pueda tener simultáneamente el papel de maestro y esclavo. Esto sucede si el dispositivo es maestro de uno o varios esclavos y a su vez sea esclavo de otro maestro.
Si un dispositivo no tiene ningún papel, estará en estado ocioso.
En la tabla se resumen las cuatro posibilidades, con sus correspondientes denominaciones:
Ocioso –sin función- | ESP_NOW_ROLE_IDLE = 0 |
Maestro | ESP_NOW_ROLE_CONTROLLER =1 |
Esclavo | ESP_NOW_ROLE_SLAVE = 2 |
Maestro+Esclavo | ESP_NOW_ROLE_MAX = 3 |
MAC de comunicación ESP-NOW
Cada procesador ESP disponen de dos direcciones MAC, para posibilitar las conexiones WiFi en los modos Access Point y Station. Las direcciones MAC son respectivamente AP MAC y STA MAC.
Estas direcciones MAC se pueden obtener con el siguiente sketch:
#include <ESP8266WiFi.h> void setup() { Serial.begin(115200); Serial.println();Serial.println(); Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress()); Serial.print("STA MAC: "); Serial.println(WiFi.macAddress()); } void loop() {}
La dirección MAC que debemos asignar a un par, depende de la conexión WiFi que tenga establecida y su papel en el par de comunicación. En la siguiente tabla se resumen las posibles combinaciones y la MAC a elegir:
TIPO DE CONEXIÓN WiFi | |||||
SIN CONEXIÓN | AP | STA | AP+STA | ||
PAPEL | MAESTRO | STA MAC | AP MAC | STA MAC* | AP MAC |
ESCLAVO | STA MAC | AP MAC* | STA MAC | STA MAC* |
*Conexiones WiFi sugeridas por Spressif, en el caso de que se utilicen. (Maestro-STA y Esclavo-AP o AP+STA)
Funciones ESP-NOW
Las funciones de la librería espnow.h utilizadas para la comunicación ESP-NOW son bastante extensas.
Para hacer un repaso de las mismas, conviene agruparlas en tres bloques, que se corresponden con los pasos necesarios para realizar una correcta comunicación:
¡¡¡IMPORTANTE!!!
Para hacer funcionar la comunicación ESP-NOW, si se tiene instalado en el IDE de Arduino como Gestor de Tarjetas para procesadores ESP el esp8266 by ESP8266 Community versión 2.3.0*, es necesario editar el fichero: ~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.1.0/platform.txt, buscar «compiler.c.elf.libs«, y añadir al final de la línea «-lespnow«. Si no se hace, obtendremos el mensaje de error de «espnow library not found«. *Para ver el Gestor de Tarjetas instalado se puede seguir la siguiente secuencia: Herramientas -> Placa:»NodeMCU 1.0(ESP-12E Module)» -> Gestor de tarjetas. |
INICIALIZA el protocolo de comunicación ESP-NOW |
esp_now_init() |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } //INICIALIZACIÓN DEL PROTOCOLO ESP-NOW void setup() { Serial.begin(115200); Serial.println(); if (esp_now_init()==0) { Serial.println("Conexion ESP-NOW inicializada."); } else{ Serial.println("Conexion ESP-NOW no inicializada."); ESP.restart(); } } void loop() {} |
DESINICIALIZA el protocolo de comunicación ESP-NOW |
esp_now_deinit() |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); //INICIALIZACIÓN DEL PROTOCOLO ESP-NOW if (esp_now_init()==0) { Serial.println("Conexion ESP-NOW inicializada."); } else{ Serial.println("Conexion ESP-NOW no inicializada."); ESP.restart(); } delay(2000); //DESINICIALIZACIÓN DEL PROTOCOLO ESP-NOW if (esp_now_deinit()==0) { Serial.println("Conexion ESP-NOW desinicializada."); } else{ Serial.println("Conexion ESP-NOW inicializada."); } } void loop() {} |
CREACIÓN DE LA TABLA DE COMUNICACIÓN ESP-NOW
Una vez inicializado el protocolo de comunicación ESP-NOW, se debe introducir en cada dispositivo los datos de comunicación propios y de los dispositivos pares a los que se va a enviar información . Estos datos se almacenan en una tabla, necesaria para poder habilitar las comunicaciones.
- Los datos que almacena la tabla del dispositivo local son el papel (rol) y la clave de cifrado. Las funciones relacionadas son:
ESTABLECE el papel del dispositivo en la comunicación entre pares y lo almacena en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_set_self_role(uint8_t role) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); //SE ESTABLECE EL PAPEL DEL DISPOSITIVO EN LA COMUNICACIÓN if (esp_now_set_self_role(1)==0){ //1-> maestro Serial.println("Declarado elemento como MAESTRO."); } else{ Serial.println("Error en la declaracion!!!"); } } void loop() {} |
CONSULTA el papel del dispositivo en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_get_self_role() |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); //esp_now_set_self_role(0); //0-> ocioso. esp_now_set_self_role(1); //1-> maestro. //esp_now_set_self_role(2); //2-> esclavo. //esp_now_set_self_role(3); //3-> maestro+esclavo //CONSULTA DEL PAPEL DEL DISPOSITIVO Serial.print("El dispositivo esta declarado como: "); Serial.println(esp_now_get_self_role()); Serial.println("0=OCIOSO, 1=MAESTRO, 2=ESCL. y 3=MAESTR+ESCL."); } void loop() {} |
ESTABLECE la CLAVE DE CIFRADO para la CLAVE DE COMUNICACIÓN |
esp_now_set_kok(uint8_t *key, uint8_t len) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro //CLAVE DE CIFRADO DE LA CLAVE DE COMUNICACIÓN uint8_t key[16]={0,256,1,2,3,4,5,6,7,6,5,4,3,2,1,0}; uint8_t len=16; if (esp_now_set_kok(key,len)==0){ //Todos los elementos de la red ESP-NOW deben compartir la misma clave Serial.println("Establecida nueva CLAVE DE CIFRADO."); } else{ Serial.println("Error al establecer la clave de cifrado!!!"); } } void loop() {} |
- Los datos que almacena la tabla de los dispositivos pares son la dirección MAC, papel, canal de comunicación y la clave de comunicación. Las funciones relacionadas son:
AÑADE un nuevo par a la TABLA DE COMUNICACIÓN ESP-NOW.
Guarda su MAC, papel, canal y clave de comunicación. |
esp_now_add_peer(uint8_t *mac_addr, uint8_t role, uint8_t channel, uint8_t *key, uint8_t key_len) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro //INCLUIMOS UN PAR EN LA TABLA DE COMUNICACIÓN uint8_t mac_addr[6]={0x5C,0xCF,0x7F,0x16,0x50,0xB9}; uint8_t role=2; //2-> esclavo uint8_t channel=3; //canal 3 uint8_t key[0]={}; //sin clave (NULL) //uint8_t key[16]={0,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1} //clave uint8_t key_len=sizeof(key); if (esp_now_add_peer(mac_addr,role,channel,key,key_len)==0) { Serial.print("Par ESP: 5C:CF:7F:16:50:B9"); Serial.println(" incluido en la TABLA DE COMUNICACION"); } else{ Serial.print("Par ESP: 5C:CF:7F:16:50:B9"); Serial.println("NO incluido en la TABLA DE COMUNICACI0N!!!"); } } void loop() {} |
BORRA un par de la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_del_peer(uint8_t *mac_addr) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro uint8_t mac_addr[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x50, 0xB9}; esp_now_add_peer(mac_addr,2,3,NULL,0); //ESP 5C:CF:7F:16:50:B9 esclavo, canal 3, sin clave Serial.print("Par ESP: 5C:CF:7F:16:50:B9"); Serial.println(" incluido en la TABLA DE COMUNICACION"); delay(2000); //BORRAMOS EL PAR DE LA TABLA DE COMUNICACIÓN if (esp_now_del_peer(mac_addr)==0) { Serial.print("Par ESP: 5C:CF:7F:16:50:B9"); Serial.println(" borrado de la TABLA DE COMUNICACION"); } else{ Serial.print("Par ESP: 5C:CF:7F:16:50:B9"); Serial.println(" NO borrado de la TABLA DE COMUNICACION"); } } void loop() {} |
COMPRUEBA si un par está incluido en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_is_peer_exist(uint8_t *mac_addr) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro uint8_t mac_addr[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x50, 0xB9}; esp_now_add_peer(mac_addr,2,3,NULL,0); //ESP 5C:CF:7F:16:50:B9 esclavo, canal 3, sin clave Serial.print("Par ESP 5C:CF:7F:16:50:B9"); Serial.println(" incluido en la TABLA DE COMUNICACION"); delay(2000); //COMPROBAMOS SI EL PAR ESTÁ INCLUIDO EN LA TABLA DE COMUNICAC. Serial.print("Comprobamos si el par ESP 5C:CF:7F:16:50:B9"); Serial.println(" está incluido en la TABLA DE COMUNICACION."); Serial.print("Resultado de la comprobacion: "); Serial.println(esp_now_is_peer_exist(mac_addr)); Serial.println("0 = El par no esta incluido en la TABLA"); Serial.println(">0 El par realmente esta incluido en la TABLA"); Serial.println("<0 Error en la comprobacion"); } void loop() {} |
CONSULTA la dirección MAC de los pares almacenados en la TABLA DE COMUNICACIÓN ESP-NOW. |
esp_now_fetch_peer(bool restart) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //INCLUIMOS TRES PARES EN LA TABLA DE COMUNICACIÓN uint8_t mac_addr1[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x2C, 0xB9}; esp_now_add_peer(mac_addr1,2,1,NULL,0); uint8_t mac_addr2[6] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45}; esp_now_add_peer(mac_addr2,2,2,NULL,0); uint8_t mac_addr3[6] = {0x50, 0x51, 0x52, 0x53, 0x54, 0x55}; esp_now_add_peer(mac_addr3,2,3,NULL,0); //OBTENEMOS LA DIRECCIÓN MAC DE LOS PARES ALMACENADOS EN LA TABLA uint8_t *MACpar; MACpar= esp_now_fetch_peer(1); //PRIMER PAR Serial.printf("IP local: %02X:%02X:%02X:%02X:%02X:%02X\n", MACpar[0],MACpar[1],MACpar[2],MACpar[3],MACpar[4],MACpar[5]); MACpar= esp_now_fetch_peer(0); //SIGUIENTE PAR Serial.printf("IP local: %02X:%02X:%02X:%02X:%02X:%02X\n", MACpar[0],MACpar[1],MACpar[2],MACpar[3],MACpar[4],MACpar[5]); MACpar= esp_now_fetch_peer(0); //SIGUIENTE PAR Serial.printf("IP local: %02X:%02X:%02X:%02X:%02X:%02X\n", MACpar[0],MACpar[1],MACpar[2],MACpar[3],MACpar[4],MACpar[5]); } void loop() {} |
CONSULTA el papel de un par en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_get_peer_role(uint8_t *mac_addr) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro uint8_t mac_addr[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x50, 0xB9}; esp_now_add_peer(mac_addr,0,3,NULL,0); //ESP 5C:CF:7F:16:50:B9 ocioso, canal 3, sin clave Serial.print("Par ESP: 5C:CF:7F:16:50:B9"); Serial.print(" incluido en la TABLA DE COMUNICACION"); CONSULTAMOS EL PAPEL DEL PAR EN LA TABLA DE COMUNICACIÓN Serial.print("El papel del ESP 5C:CF:7F:16:50:B9 es de: "); Serial.println(esp_now_get_peer_role(mac_addr)); Serial.println("0=OCIOSO, 1=MAESTRO, 2=ESCL. y 3=MAESTR+ESCL."); } void loop() {} |
.
MODIFICA el papel de un par en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_set_peer_role(uint8_t *mac_addr, uint8_t role) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro uint8_t mac_addr[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x50, 0xB9}; esp_now_add_peer(mac_addr,0,3,NULL,0); //ESP 5C:CF:7F:16:50:B9 ocioso, canal 3, sin clave Serial.print("Par ESP: 5C:CF:7F:16:50:B9"); Serial.print(" incluido en la TABLA DE COMUNICACION"); CONSULTAMOS EL PAPEL DEL PAR EN LA TABLA DE COMUNICACIÓN Serial.print("El papel del ESP 5C:CF:7F:16:50:B9 es de: "); Serial.println(esp_now_get_peer_role(mac_addr)); Serial.println("0=OCIOSO, 1=MAESTRO, 2=ESCL. y 3=MAESTR+ESCL."); delay(2000); MODIFICAMOS EL PAPEL DEL PAR EN LA TABLA DE COMUNICACIÓN if(esp_now_set_peer_role(mac_addr,2)==0){ Serial.print("Se ha modificado el papel del par a ESCLAVO"); } else{ Serial.print("No se ha logrado modificar papel del par!!!"); } } void loop() {} |
CONSULTA el canal de comunicación de un par en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_get_peer_channel(uint8_t *mac_addr) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro uint8_t mac_addr[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x50, 0xB9}; esp_now_add_peer(mac_addr,2,3,NULL,0); //ESP 5C:CF:7F:16:50:B9 esclavo, canal 3, sin clave Serial.print("Par ESP: 5C:CF:7F:16:50:B9"); Serial.print(" incluido en la TABLA DE COMUNICACION"); CONSULTAMOS EL CANAL DE COMUNICACIÓN DEL PAR EN LA TABLA Serial.print("El canal de comunicacion del "); Serial.print("ESP 5C:CF:7F:16:50:B9 es el: "); Serial.println(esp_now_get_peer_channel(mac_addr)); } void loop() {} |
.
MODIFICA el canal de un par en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_set_peer_channel(uint8_t *mac_addr, uint8_t channel) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro uint8_t mac_addr[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x50, 0xB9}; esp_now_add_peer(mac_addr,2,3,NULL,0); //ESP 5C:CF:7F:16:50:B9 esclavo, canal 3, sin clave Serial.print("Par ESP: 5C:CF:7F:16:50:B9"); Serial.print(" incluido en la TABLA DE COMUNICACION"); CONSULTAMOS EL CANAL DE COMUNICACIÓN DEL PAR EN LA TABLA Serial.print("El canal de comunicación del "); Serial.print("ESP 5C:CF:7F:16:50:B9 es de: "); Serial.println(esp_now_get_channel_role(mac_addr)); delay(2000); MODIFICAMOS EL CANAL DE COMUNICACIÓN DEL PAR EN LA TABLA if(esp_now_set_peer_channel(mac_addr,2)==0){ //La comprobación también modifica el canal de comunicación!!! Serial.print("Se ha modificado el canal de comunicac. al 2"); } else{ Serial.print("No se ha modificado el canal de comunicac.!!!"); } } void loop() {} |
CONSULTA la clave de comunicación de un par en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_get_peer_key(uint8_t *mac_addr, uint8_t *key, uint8_t, key_len) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro uint8_t mac_addr[6]={0x5C,0xCF,0x7F,0x16,0x50,0xB9}; uint8_t key[16]={0,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; esp_now_add_peer(mac_addr,2,3,key,16); //ESP 5C:CF:7F:16:50:B9 esclavo, canal 3, clave 0,255,1,1,1,... Serial.print("Par ESP 5C:CF:7F:16:50:B9 incluido en la "); Serial.print("TABLA DE COMUNICACIÓN con clave "); Serial.println("0,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1"); //CONSULTAMOS LA CLAVE DE COMUNICACIÓN uint8_t clave[16]; uint8_t longitud_clave[1]; esp_now_get_peer_key(mac_addr,clave,longitud_clave); char PARclave[16]; sprintf(PARclave,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", clave[0],clave[1],clave[2],clave[3],clave[4],clave[5], clave[6],clave[7],clave[8],clave[9],clave[10],clave[11], clave[12],clave[13],clave[14],clave[15]); Serial.println(PARclave); Serial.println(longitud_clave[0]); } void loop() {} |
.
MODIFICA la clave de un par en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_set_peer_key(uint8_t *mac_addr, uint8_t role) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //1-> maestro uint8_t mac_addr[6]={0x5C,0xCF,0x7F,0x16,0x50,0xB9}; uint8_t key[16]={0,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; esp_now_add_peer(mac_addr,2,3,key,16); //ESP 5C:CF:7F:16:50:B9 esclavo, canal 3, clave 0,255,1,1,1,... Serial.print("Par ESP 5C:CF:7F:16:50:B9 incluido en la "); Serial.print("TABLA DE COMUNICACION con clave "); Serial.println("0,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1"); //MODIFICAMOS LA CLAVE DE COMUNICACIÓN DEL PAR EN LA TABLA uint8_t key2[16]={0,255,2,2,2,2,2,2,2,2,2,2,2,2,2}; if (esp_now_set_peer_key(mac_addr,key2,16)==0){ Serial.print("Asignada clave 0,255,2,2,2,2,2,2,2,2,2,2,2,2,2"); Serial.println(",2 al par ESP 0x5C:0xCF:0x7F:0x16:0x50:0xB9."); } else{ Serial.println("Error en la modificacion de clave!!!"); } } void loop() {} |
COMPRUEBA la clave de comunicación de un par en la TABLA DE COMUNICACIÓN ESP-NOW |
esp_now_get_peer_key(uint8_t *mac_addr, uint8_t *key, uint8_t, key_len) |
Parámetros:
|
Respuesta:
|
Ejemplo:
#include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } void setup() { Serial.begin(115200); Serial.println(); esp_now_init(); esp_now_set_self_role(1); //INCLUIMOS TRES PARES EN LA TABLA DE COMUNICACIÓN uint8_t mac_addr1[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x2C, 0xB9}; esp_now_add_peer(mac_addr1,2,1,NULL,0); uint8_t mac_addr2[6] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45}; uint8_t key [16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,255}; esp_now_add_peer(mac_addr2,2,2,key,16); uint8_t mac_addr3[6] = {0x50, 0x51, 0x52, 0x53, 0x54, 0x55}; esp_now_add_peer(mac_addr3,2,3,NULL,0); //OBTENEMOS EL NÚMERO DE PARES TOTALES Y CON CLAVE DE COMUNICAC. uint8_t all_cnt[1]; uint8_t encryp_cnt[1]; esp_now_get_cnt_info(all_cnt, encryp_cnt); Serial.print("PARES TOTALES EN LA TABLA ESP-NOW: "); Serial.println(all_cnt[0]); Serial.print("PARES CON CLAVE DE COMUNICAC. EN LA T. ESP-NOW: "); Serial.println(encryp_cnt[0]); } void loop() {} |
.
A modo de simplificación, debemos saber que las funciones fundamentales para gestionar los pares en la tabla son esp_now_add_peer() y esp_now_del_peer(). Con ellas prácticamente se pueden suplir todas las necesidades para realizar una correcta comunicación.
ENVÍA un paquete de datos. |
esp_now_send(uint8_t *da, uint8_t *data, uint8_t *len) |
Parámetros:
|
Respuesta:
|
REGISTRA un paquete de datos enviados por un par |
esp_now_register_recv_cb([](uint8_t *mac_addr, uint8_t *data, uint8_t len){instrucciones}) |
Parámetros:
|
Respuesta:
|
NO REGISTRA un paquete de datos enviados por un par |
esp_now_unregister_recv_cb() |
Parámetros:
|
Respuesta:
|
COMPRUEBA si un paquete de datos enviado ha sido recibido correctamente por un par |
esp_now_register_send_cb([](uint8_t *mac_addr, uint8_t status){instrucciones}) |
Parámetros:
|
Respuesta:
|
NO COMPRUEBA si un paquete de datos enviado ha sido recibido correctamente por un par |
esp_now_unregister_send_cb() |
Parámetros:
|
Respuesta:
|
Las funciones que se señalan a continuación son las que se utilizarán en un esquema clásico de comunicación ESP-NOW:
CIRCUITOS ELECTRÓNICOS DEL EJEMPLO PRÁCTICO
Los circuitos que debemos conexionar son los siguientes:
SKETCHS
/* Ejemplo de comunicación ESP-NOW por Dani No www.esploradores.com ***ESTE SKETCH CORRESPONDE AL PAR MAESTRO*** El sketch permite el envío de dos datos mediante la comunicación ESP-NOW a un par esclavo: - En la variable -potenciometro- se envía el dato de la lectura de la entrada analógica del ESP. Se leen y envían -valores entre 0 y 1023- que se hacen variar mediante un potenciómetro y se utilizarán para regular la intensidad del LED conectado en el circuito esclavo. - En la variable -tiempo- se envía el dato del milisegundo en el que el que se envían los datos al circuito esclavo. ¡¡¡IMPORTANTE!!! Para hacer funcionar la comunicación ESP-NOW si se tiene instalado en Arduino como gestor de tarjetas el: esp8266 by ESP8266 Community versión 2.3.0 (Se puede comprobar buscándolo en: Herramientas->Placa:"NodeMCU 1.0(ESP-12E Module)"->Gestor de tarjetas..., es necesario editar el fichero: ~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.1.0/platform.txt, buscar "compiler.c.elf.libs", y añadir al final de la línea "-lespnow". */ #include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } //***ESTRUCTURA DE LOS DATOS TRANSMITIDOS MAESTRO/ESCLAVO***// //Se de establecer IGUAL en el par esclavo struct ESTRUCTURA_DATOS { uint16_t potenciometro; uint32_t tiempo; }; void setup() { //***INICIALIZACIÓN DEL PUERTO SERIE***// Serial.begin(115200); Serial.println();Serial.println(); //***INICIALIZACIÓN DEL PROTOCOLO ESP-NOW***// if (esp_now_init()!=0) { Serial.println("*** ESP_Now init failed"); ESP.restart(); delay(1); } //***DATOS DE LAS MAC (Access Point y Station) del ESP***// Serial.print("Access Point MAC de este ESP: "); Serial.println(WiFi.softAPmacAddress()); Serial.print("Station MAC de este ESP: "); Serial.println(WiFi.macAddress()); //***DECLARACIÓN DEL PAPEL DEL DISPOSITIVO ESP EN LA COMUNICACIÓN***// //0=OCIOSO, 1=MAESTRO, 2=ESCLAVO y 3=MAESTRO+ESCLAVO esp_now_set_self_role(1); //***EMPAREJAMIENTO CON EL ESCLAVO***// // Dirección MAC del ESP con el que se empareja (esclavo) // Se debe introducir la STA MAC correspondiente uint8_t mac_addr[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x50, 0xB9}; uint8_t role=2; uint8_t channel=3; uint8_t key[0]={}; //no hay clave //uint8_t key[16] = {0,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; uint8_t key_len=sizeof(key); Serial.print("Tamaño de *key: "); Serial.println(key_len); esp_now_add_peer(mac_addr,role,channel,key,key_len); } void loop() { //***DATOS A ENVIAR***// ESTRUCTURA_DATOS ED; ED.potenciometro = analogRead(A0); Serial.print("Dato potenciometro: "); Serial.print(ED.potenciometro); delay(20); ED.tiempo = millis(); Serial.print(". Dato tiempo: "); Serial.print(ED.tiempo); //***ENVÍO DE LOS DATOS***// //uint8_t *da=NULL; //NULL envía los datos a todos los ESP con los que está emparejado uint8_t da[6] = {0x5C, 0xCF, 0x7F, 0x16, 0x50, 0xB9}; uint8_t data[sizeof(ED)]; memcpy(data, &ED, sizeof(ED)); uint8_t len = sizeof(data); esp_now_send(da, data, len); delay(1); //Si se pierden datos en la recepción se debe subir este valor //***VERIFICACIÓN DE LA RECEPCIÓN CORRECTA DE LOS DATOS POR EL ESCLAVO***// esp_now_register_send_cb([](uint8_t* mac, uint8_t status) { char MACesclavo[6]; sprintf(MACesclavo,"%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); Serial.print(". Enviado a ESP MAC: "); Serial.print(MACesclavo); Serial.print(". Recepcion (0=0K - 1=ERROR): "); Serial.println(status); }); }
/* Ejemplo de comunicación ESP-NOW por Dani No www.esploradores.com ***ESTE SKETCH CORRESPONDE AL PAR ESCLAVO*** El sketch permite la recepción de una comunicación vía ESP-NOW de dos datos enviados por el par maestro. - En la variable -potenciometro- se envía el dato de la lectura de la entrada analógica del circuito maestro -valores entre 0 y 1023-, que se utilizarán para regular la intensidad del LED conectado en el circuito esclavo. - En la variable -tiempo- se envía el dato del milisegundo en el que el circuito maestro realiza la comunicación con el circuito esclavo. ¡¡¡IMPORTANTE!!! Para hacer funcionar la comunicación ESP-NOW si se tiene instalado en Arduino como gestor de tarjetas el: esp8266 by ESP8266 Community versión 2.3.0 (Se puede comprobar buscándolo en: Herramientas->Placa:"NodeMCU 1.0(ESP-12E Module)"->Gestor de tarjetas..., es necesario editar el fichero: ~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.1.0/platform.txt, buscar "compiler.c.elf.libs", y añadir al final de la línea "-lespnow". */ #include <ESP8266WiFi.h> extern "C" { #include <espnow.h> } //***ESTRUCTURA DE LOS DATOS TRANSMITIDOS MAESTRO/ESCLAVO***// //Se de establecer IGUAL en el par maestro struct ESTRUCTURA_DATOS { uint16_t potenciometro = 0; uint32_t tiempo = 0; }; //***PIN de conexión del LED a regular con el potenciometro del ESP MAESTRO***// int PinLED = 5; //Pin D1 void setup() { //***INICIALIZACIÓN DEL PUERTO SERIE***// Serial.begin(115200); Serial.println(); //***INICIALIZACIÓN DEL PROTOCOLO ESP-NOW***// if (esp_now_init()!=0) { Serial.println("Protocolo ESP-NOW no inicializado..."); ESP.restart(); delay(1); } //***DATOS DE LAS MAC (Access Point y Station) del ESP***// Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress()); Serial.print("STA MAC: "); Serial.println(WiFi.macAddress()); //***DECLARACIÓN DEL PAPEL DEL DISPOSITIVO ESP EN LA COMUNICACIÓN***// //0=OCIOSO, 1=MAESTRO, 2=ESCLAVO y 3=MAESTRO+ESCLAVO esp_now_set_self_role(2); //***DECLARACIÓN del PinLED como SALIDA***// pinMode(PinLED, OUTPUT); } void loop() { //***RECEPCIÓN DE LA COMUNICACIÓN ESP-NOW***// esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data, uint8_t len) { char MACmaestro[6]; sprintf(MACmaestro, "%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); Serial.print("Recepcion desde ESP MAC: "); Serial.print(MACmaestro); ESTRUCTURA_DATOS ED; memcpy(&ED, data, sizeof(ED)); Serial.print(". Dato potenciometro: "); Serial.print(ED.potenciometro); Serial.print(". Dato tiempo: "); Serial.println(ED.tiempo); analogWrite(PinLED,ED.potenciometro); }); }
Una vez subidos los sketchs a las placas, se podrá regular la intensidad de iluminación del led desde el potenciómetro y/o visualizar las comunicaciones realizadas y la información transmitida en el puerto serie.
85 Comments
Leave your reply.