fbpixel
Etiquetas: , ,
0
(0)

Neste tutorial, veremos como configurar uma rede de vários ESP32s usando o protocolo ESP-NOW. O ESP32 é uma placa de desenvolvimento com WiFi incorporado. Pode, portanto, ligar-se e trocar dados com dispositivos ligados à mesma rede.

Hardware

  • Computador
  • NodeMCU ESP32 ou NodeMCU ESP8266 ou Wemos x3
  • Cabo USB A macho para Mini B macho x3

Descrição ESP-NOW

O ESP-NOW é um protocolo de comunicação desenvolvido pela Espressif, que permite a comunicação sem fios entre vários dispositivos sem a necessidade de uma rede específica. Permite a troca de pequenos pacotes de dados a alta velocidade nas bandas de frequência de 2,4 GHz, até 200 m de distância. Requer um emparelhamento inicial, mas uma vez efectuado, a comunicação é persistente e estabelece-se logo no arranque. Uma das grandes vantagens, para além do facto de utilizar uma rede dedicada, é que uma ou mais estações ESP32 ou ESP8266 podem ligar-se à rede Wifi em paralelo.

Utilizando este protocolo, é possível criar uma rede de NodeMCUs que comunicam entre si.

Código

Vamos estabelecer uma comunicação bidirecional entre vários ESP32 utilizando a biblioteca espnow.h disponível quando instala o gestor de cartões. Vamos definir e enviar uma estrutura de dados idêntica para todos os cartões, a fim de simplificar o código.

Código Mestre

Para que o cartão emissor possa comunicar com outro cartão, é necessário o seu endereço MAC. É possível obter este endereço quando a placa recetora é iniciada a partir de mensagens enviadas através da função setup() (Serial.println(WiFi.macAddress());). Vamos definir uma função que é executada depois de uma mensagem ter sido enviada para verificar se a transmissão foi bem sucedida.

Não se esqueça de alterar os endereços dos cartões slave correspondentes aos cartões que está a utilizar.

#include <esp_now.h>
#include <WiFi.h>
const char nom[10]="Mestre"; 
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\nMestre 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 = "Escravo0";
    esp_err_t result0 = esp_now_send(broadcastAddress[0], (uint8_t *) &myData, sizeof(myData));
    

    myData.d = "Escravo1";
    esp_err_t result1 = esp_now_send(broadcastAddress[1], (uint8_t *) &myData, sizeof(myData));
    previousTime=millis();
  }
}

Código Slave

No código SLAVE, vamos criar uma função que é executada quando uma mensagem é recebida. Esta função é utilizada para processar a informação recebida. Neste exemplo, exibimos os dados contidos na estrutura.

O código Slave deve ser modificado para cada cartão Slave, de modo a que os dados e o identificador sejam diferentes.

#include <esp_now.h>
#include <WiFi.h>

const char nom[10]="Escravo0"; 
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();
  }
}

(Código pour ESP8266 ci-dessous)

Quando carregar o código pela primeira vez, observe atentamente a mensagem de configuração que contém o endereço MAC do recetor. Deve introduzi-lo no código do transmissor para assegurar o emparelhamento e a comunicação com êxito.

Resultados

Uma vez definido o endereço MAC do cartão recetor e carregados os códigos em cada cartão, a comunicação é estabelecida e a estrutura é enviada e desencriptada corretamente.

  • Mestre
  • Escravo0
  • Escravo1

ATENÇÃO: durante este tutorial, um dos cartões parecia estar com defeito e não enviava uma mensagem ao mestre, embora a recebesse. A ser testado e validado com outro cartão

Bónus: Comunicação entre o ESP32 e o ESP8266

Para integrar os cartões ESP8266 na sua rede ESP-NOW, basta modificar algumas linhas de código.

Convido-o a rever o tutorial sobre o ESP-NOW e o ESP8266

Para mudar de um código ESP32 para um código ESP8266, é necessário mudar:

  • Inclui no início do código
  • Adicionar uma função esp_now_set_self_role com a função correcta definida em cada caso
  • Modificar os argumentos da função esp_now_add_peer
  • Modificar os tipos de argumentos das funções OnDataRecv e OnDataSent
#include <espnow.h>//https://github.com/esp8266/Arduino/blob/master/tools/sdk/include/espnow.h
#include <ESP8266WiFi.h>

const char nom[10]="Escravo0"; 
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();
  }
}

Bónus: Mostrar o endereço MAC para o copiar

É possível visualizar o endereço MAC do Maestro ou dos Slaves num formato que permita a sua cópia direta para 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("}"); 
}

Fontes

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

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?