Comunicação entre dois ESP32 com ESP-NOW

Posted by

Existe uma forma de fazer comunicação entre dois ESP32 (ou mais) com um protocolo desenvolvido pela própria Espressif, chamado ESP-NOW. A ideia é utilizar a infraestrutura do WiFi já presente nos chips para transitar pacotes de até 250 bytes.

Protocolo de comunicação peer-to-peer ESP-NOW
Protocolo de comunicação peer-to-peer ESP-NOW

O protocolo funciona também sobre Bluetooth, e pode ser usado tanto na série ESP8266 como ESP32-S e ESP32-C. A ideia é uma troca de informações rápida e com baixo consumo de energia.

Á esquerda Beetle ESP32-C3 e á direita minha dev board ESP32-C6
Á esquerda Beetle ESP32-C3 e á direita minha dev board ESP32-C6

Vou utilizar dois ESP32 para testar o ESP-NOW: um ESP32-C3 da DFRobot e minha placa de desenvolvimento ESP32-C6. Basearei este tutorial no ótimo artigo da RandomNerdTutorials, daqui. Utilizaremos o ambiente do Arduino e sua IDE para nossos testes.

A página oficial do ESP-NOW é um ótima leitura, recomendo. Lá cita exemplo de controle de veículos remotamente (carros, aviões, quadcópteros, barcos de controle remoto). Cita que via WiFi a distância de controle com linha de visão pode chegar a 200 metros.

Para começar, comunicação simples

A primeira coisa que precisamos para começar a pensar em comunicação, é conhecer o endereço MAC de cada ESP32. Para isso faça o upload do código abaixo para cada placa separadamente.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.  
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <WiFi.h>
#include <esp_wifi.h>

void readMacAddress(){
  uint8_t baseMac[6];
  esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);
  if (ret == ESP_OK) {
    Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
                  baseMac[0], baseMac[1], baseMac[2],
                  baseMac[3], baseMac[4], baseMac[5]);
  } else {
    Serial.println("Failed to read MAC address");
  }
}

void setup(){
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.STA.begin();

  Serial.print("[DEFAULT] ESP32 Board MAC Address: ");
  readMacAddress();
}
 
void loop(){

}

Endereço MAC obtido da placa DFRobot Beetle ESP32-C3: 74:4d:bd:e2:c6:80. Endereço da minha dev board Xiao ESP32-C6: f0:f5:bd:18:fc:3c. Lembrando que cada placa tem um endereço individual, único. O próximo passo é rodar um exemplo; primeiro faremos um no estilo transmissor-receptor.

A placa Beetle ESP32-C3 será o transmissor e a placa dev Xiao ESP32-C6 o receptor. Usaremos código deste link tanto para o transmissor como para o receptor. No transmissor (código abaixo) devemos colocar o endereço MAC do receptor, fora isso nenhuma informação é necessária. Nem mesmo a senha do WiFi, já que a comunicação ESP-NOW não passa pelo modem de sua casa.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <esp_now.h>
#include <WiFi.h>

// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0xf0, 0xf5, 0xbd, 0x18, 0xfc, 0x3c}; // MAC of my Beetle ESP32-C3

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
  char a[32];
  int b;
  float c;
  bool d;
} struct_message;

// Create a struct_message called myData
struct_message myData;

esp_now_peer_info_t peerInfo;

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "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() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}
 
void loop() {
  // Set values to send
  strcpy(myData.a, "THIS IS A CHAR");
  myData.b = random(1,20);
  myData.c = 1.2;
  myData.d = false;
  
  // Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
   
  if (result == ESP_OK) {
    Serial.println("Sent with success");
  }
  else {
    Serial.println("Error sending the data");
  }
  delay(2000);
}

No receptor o código é bem simples e não requer nenhuma configuração, nem MAC nem senha de WiFi. Veja abaixo e faça upload para sua placa receptora.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/  
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

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

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    bool d;
} struct_message;

// Create a struct_message called myData
struct_message myData;

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int 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("Bool: ");
  Serial.println(myData.d);
  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() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}
 
void loop() {

}

O que estes códigos fazem é trocar informação na forma de quatro tipos de dados: Char, int, Float a Bool. O dado int é obtido utilizando-se a função random(), demais dados são fixos. Veja na imagem abaixo a saída do monitor serial do receptor (no meu caso o Xiao ESP32-C6).

Dados transitados entre dois ESP32 via ESP-NOW
Dados transitados entre dois ESP32 via ESP-NOW

É mostrada a quantidade de bytes recebidos, no caso são 44. Aí vem o texto “THIS IS A CHAR”, depois um int aleatório (entre 1 e 20) e então um Float de valor 1.20 e um Bool “False” (0).

Para finalizar

Além da comunicação que mostramos aqui, emissor-receptor, ainda é possível implementar comunicação de mão dupla entre dois e até mais ESP’s. Mostraremos este tipo de comunicação no futuro, quando pretendemos implementar um carrinho de controle remoto. Fiquem ligados.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *