banner

Ir para o Forum

ESP-NOW: WiFi com 3x mais alcance


Utilizando o protocolo ESP-NOW para fazer pontes entre múltiplos ESP32, chegamos a um WiFi com 3x mais alcance, ou seja, 480 metros de distância. Alcançamos essa rede sem fio de 2,4 GHz com as antenas embutidas do ESP32. No nosso projeto de hoje, portanto, um ESP32 irá fazer a leitura de um pino e enviar o valor para outro ESP32. Esse outro ESP32 irá receber este valor e alterar a saída do pino e enviar este valor para um próximo ESP32. O próximo ESP32 irá fazer a mesma coisa e repassar para o próximo ESP32. Resumindo, montei um controle remoto com duas bridges (pontes) no meio.



Para este projeto, fizemos um software que envia os valores que selecionarmos para inúmeros ESP32. Nosso exemplo utiliza quatro chips, mas você pode utilizar quantos desejar, pois este protocolo é muito rápido. Quero destacar que, este esquema não é para fazer link de internet, mas, sim, para automação, ou seja, para enviar bit de controle, mesmo embora esse protocolo seja bem mais rápido que LoRa.

ESP32 Pinout

Pinout do ESP32


Comunicação

Comunicação

Como você vê na imagem:
1º: Master faz a leitura do pino e envia.
2º: O próximo ESP32, Slave 1, recebe, muda o valor do pino e envia para o próximo.
3º: O próximo ESP32, Slave 2, recebe, muda o valor do pino e envia para o próximo.
4º: Por fim, o quarto ESP32, Slave 3, recebe e muda o valor do pino.

Esp32EspNowSendReceive.ino

Em primeiro lugar, nós vamos incluir as bibliotecas ESP-NOW e WiFi. Vamos ainda definir o pino 2 para fazer a leitura e envio do valor, bem como o canal 1 para a conexão. Aponto que, se o Master estiver definido, será compilado o Master.ino. Do contrário, será compilado o Slave.ino. Por fim, crio um objeto que é o peer, o qual vai guardar o endereço.

//Libs do espnow e wifi
#include <esp_now.h>
#include <WiFi.h>

//Pino utilizado para leitura
//e que será enviado o valor
#define PIN 2

//Canal usado para conexão
#define CHANNEL 1

//Se MASTER estiver definido 
//o compilador irá compilar o Master.ino
//Se quiser compilar o Slave.ino remova ou
//comente a linha abaixo
#define MASTER

//Estrutura com informações
//sobre o próximo peer
esp_now_peer_info_t peer;

Esp32EspNowSendReceive.ino – modeStation

Aqui temos a função que inicializa o modo station. Expliquei bastante sobre esse assunto no ESP32 com protocolo ESP-NOW. Ainda nesta etapa, nós mostramos no monitor serial o Mac Address do ESP quando em modo station.

//Função para inicializar o modo station
void modeStation(){
    //Colocamos o ESP em modo station
    WiFi.mode(WIFI_STA);
    //Mostramos no Monitor Serial o Mac Address 
    //deste ESP quando em modo station
    Serial.print("Mac Address in Station: "); 
    Serial.println(WiFi.macAddress());
}

Esp32EspNowSendReceive.ino - InitESPNow

Tratamos nesta parte do código sobre a função de inicialização do ESP-NOW.

//Função de inicialização do ESPNow
void InitESPNow() {
    //Se a inicialização foi bem sucedida
    if (esp_now_init() == ESP_OK) {
        Serial.println("ESPNow Init Success");
    }
    //Se houve erro na inicialização
    else {
        Serial.println("ESPNow Init Failed");
        ESP.restart();
    }
}

Esp32EspNowSendReceive.ino – addPeer

Através do endereço MAC, adicionamos aqui um novo peer. Além disso, informamos o canal e adicionamos também o slave.

//Função que adiciona um novo peer
//através de seu endereço MAC
void addPeer(uint8_t *peerMacAddress){
    //Informamos o canal
    peer.channel = CHANNEL;
    //0 para não usar criptografia ou 1 para usar
    peer.encrypt = 0;
    //Copia o endereço do array para a estrutura
    memcpy(peer.peer_addr, peerMacAddress, 6);
    //Adiciona o slave
    esp_now_add_peer(&peer);
}

Esp32EspNowSendReceive.ino – send

Temos nesta parte a função que irá enviar o valor para o peer que tenha o MAC Address especificado. Trabalhamos com as possibilidades de envio bem sucedido e também de erro.

//Função que irá enviar o valor para 
//o peer que tenha o mac address especificado
void send(const uint8_t *value, uint8_t *peerMacAddress){
    esp_err_t result = esp_now_send(peerMacAddress, value, sizeof(value));
    Serial.print("Send Status: ");
    //Se o envio foi bem sucedido
    if (result == ESP_OK) {
        Serial.println("Success");
    }
    //Se aconteceu algum erro no envio
    else {
        Serial.println("Error");
    }
}

Master.ino

Aqui temos o #ifdef MASTER, que apenas irá compilar se o Master estiver definido na diretiva de compilação. Incluímos nesta parte o MAC Address para o qual enviaremos os dados.

//Apenas irá compilar se MASTER estiver definido
 #ifdef MASTER

//Mac Address do peer para o qual iremos enviar os dados
uint8_t peerMacAddress[] = {0x24, 0x0A, 0xC4, 0x0E, 0x3F, 0xD0};

Master.ino – setup

Vamos chamar as funções de inicializam o modo station e o ESP-NOW, adicionar o peer, registrar o callback e executar a função onDataSent. Por fim, colocamos o pino em modo de leitura, a qual é feita e os dados enviados.

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

  //Chama a função que inicializa o modo station
  modeStation();

  //Chama a função que inicializa o ESPNow
  InitESPNow();

  //Adiciona o peer
  addPeer(peerMacAddress);

  //Registra o callback que nos informará 
  //sobre o status do envio.
  //A função que será executada é onDataSent
  //e está declarada mais abaixo
  esp_now_register_send_cb(OnDataSent);
  
  //Colocamos o pino em modo de leitura
  pinMode(PIN, INPUT);

  //Lê o valor do pino e envia
  readAndSend();
}

Master.ino - readAndSend

Temos aqui a readAndSend, que é a função responsável pela leitura do pino e o envio do valor para o peer.

//Função responsável pela
//leitura do pino e envio
//do valor para o peer
void readAndSend(){
  //Lê o valor do pino
  uint8_t value = digitalRead(PIN);
  //Envia o valor para o peer
  send(&value, peerMacAddress);
}

Master.ino – OnDataSent

Já OnDataSent é a função que serve de callback para nos avisar sobre a situação do envio que fizemos. Lembrando que, quando recebemos o resultado do último envio já podemos ler e enviar novamente.

//Função que serve de callback para nos avisar
//sobre a situação do envio que fizemos
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");

  //Quando recebemos o resultado do último envio
  //já podemos ler e enviar novamente
  readAndSend();
}

Master.ino – loop

No Loop, não precisamos fazer nada, pois sempre que recebemos o feedback do envio através da função OnDataSent nós enviamos os dados novamente, fazendo com que os dados estejam sempre sendo enviados em sequência.

//Não precisamos fazer nada no loop
//pois sempre que recebemos o feedback
//do envio através da função OnDataSent
//nós enviamos os dados novamente,
//fazendo com que os dados estejam sempre
//sendo enviados em sequência
void loop() {
}
#endif

Slave.ino

Iniciando o código do Slave, destacamos que apenas irá compilar se Master não estiver definido. No caso de compilarmos como Slave, temos, então, o Mac Address do peer para o qual iremos enviar os dados.

//Apenas irá compilar se MASTER não estiver definido
#ifndef MASTER

//Mac Address do peer para o qual iremos enviar os dados
uint8_t peerMacAddress[6] = {0x24, 0x0A, 0xC4, 0x0E, 0x46, 0xCC};

Slave.ino – setup

No Setup do Slave, novamente vamos chamar as funções que inicializam o modo station e o ESP-NOW, adicionar o peer e registrar o callback. A novidade é que, desta vez, temos dois callbacks. Então, vamos executar a função onDataRecv, que informará que recebemos os dados, bem como a função onDataSent, que informará sobre o status do envio de dados. Por fim, colocamos o pino em modo de saída.

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

  //Chama a função que inicializa o modo station
  modeStation();

  //Chama a função que inicializa o ESPNow
  InitESPNow();

  //Adiciona o peer
  addPeer(peerMacAddress);

  //Registra o callback que nos informará
  //que recebemos dados.
  //A função que será executada
  //é onDataRecv e está declarada mais abaixo
  esp_now_register_recv_cb(onDataRecv);

  //Registra o callback que nos informará 
  //sobre o status do envio.
  //A função que será executada
  //é onDataSent e está declarada mais abaixo
  esp_now_register_send_cb(onDataSent);

  //Colocamos o pino como saída
  pinMode(PIN, OUTPUT);
}

Slave.ino – onDataRecv

Esta função onDataRecv serve de callback, sendo que, toda vez que houver o envio, ela vai chamar a função send(value, peerMacAddress);, isso para enviar o valor lido para o próximo ESP.

//Função que serve de callback para nos avisar
//que recebemos dados
void onDataRecv(const uint8_t *mac_addr, const uint8_t *value, int len) {
  //Coloca o valor recebido na saída do pino
  digitalWrite(PIN, *value);
  //Envia o valor lido para o próximo esp
  //Se este for o último, comente esta linha antes de compilar
  send(value, peerMacAddress);
}

Slave.ino – onDataSent

Já esta função serve de callback para nos avisar sobre a situação do envio que fizemos.

//Função que serve de callback para nos avisar
//sobre a situação do envio que fizemos
void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

Slave.ino – loop

Novamente, não precisamos fazer nada no Loop, pois nós enviamos os dados assim que recebemos do outro ESP pelo callback.

//Não precisamos fazer nada no loop
//nós enviamos os dados assim que 
//recebemos do outro esp pelo callback
void loop() {
}
#endif




Faça o download dos arquivos:



5 comentários:

  1. Olá Fernando, estou curtindo muito os seus vídeos, gostaria de saber se é possível criar uma comunicação com os esp01 com rede MESH?....Parabéns pelos vídeos!!!

    ResponderExcluir
  2. Olá fernando, onde consigo esta biblioteca esp_now.h?

    ResponderExcluir
    Respostas
    1. Olá, Lucas.
      Na verdade, ela já deveria vir quando se instala o ESP32 com o board manager do Arduino. Tecnicamente é só instalar isso que funciona.
      Sugiro para você este vídeo “ESP32: Como instalar na IDE do Arduino”, que está no link: https://youtu.be/_4igHlpnlLI
      Abraço

      Excluir
    2. Opá, uma pergunta, consigo utilizar o ESP_NOW com o ESP01? me parece que sim né? neste caso onde acho o esp_now.h? Obrigado e parabéns pelos videos.

      Excluir
  3. Boa tarde Fernando...
    Como faço para adicionar um slave esp8266, tentei adicionar um outro nodemcu e/ou esp01 mas da erro ao compilar o código!

    ResponderExcluir

Tecnologia do Blogger.