O que é ESP-NOW – E como Funciona? – Código exemplo explicado!!!

O que é ESP-NOW - E como Funciona? - Código exemplo explicado! - fvml
O que é ESP-NOW – E como Funciona? – Código exemplo explicado!

Olá a Todos!!!

Neste artigo, você encontrará um guia prático para dominar o protocolo ESP-NOW da Espressif, que permite comunicação ponto a ponto sem roteador, com latência inferior a 10ms e consumo ultrabaixo de energia. 

Sendo conveniente para ser utilizado em dispositivos que trabalhe com pilhas ou baterias, como controles remotos, sensores de incêndio wireless, joystick sem fio e etc.

Você aprenderá a configurar ESP8266 e ESP32, enviar mensagens, criar redes mesh simples e solucionar falhas de transmissão, tornando seus projetos IoT mais ágeis e eficientes


O protocolo é semelhante à conectividade sem fio de baixa potência de
2,4 GHz que é frequentemente implantada em mouses e
teclados sem fio. 

Assim, o emparelhamento entre dispositivos é necessário antes de sua
comunicação. Após o emparelhamento, a conexão é segura e
ponto-a-ponto, sem necessidade de uma rede de apoio, e com uma
velocidade de conexão surpreendentemente rápida. 

    ✅ O que é o Protocolo ESP-NOW


    O protocolo ESP-NOW é um protocolo de comunicação M2M (Machine To Machine) ou seja, é a comunicação entre
    ESPs8266 (mestre e esclavo) ou mesmo, ambos os
    seguimentos.

    Devido ao protocolo ESP-NOW ter também os modos de
    Mestre/Escravo cujo o dispositivo podem se tornar
    mestre e escravo ao mesmo tempo, que interagem entre si, podendo
    responderem ambos comandos enviados por outro ESP, e ainda
    podendo responder não só ponto à ponto, mas, um
    ESP Mestre/Escravo pode responder ou enviar comandos para outros
    ESPs escravos, mestres, ou
    mestre/escravo.

    ⚙️ Recursos do protocolo ESP-NOW

    • ✔️ Comunicação Uni-cast criptografada e não criptografada.
    • ✔️ Dispositivos pares criptografados e não criptografados.
    • ✔️ Carga útil de até 250 bytes.
    • ✔️ A função de retorno de chamada de envio que pode ser configurada
      para informar a camada de aplicação o sucesso ou falha na
      transmissão.


    Limitações do protocolo ESP-NOW

    • ❌ Não Suporta BroadCast
    • ❌ Pares criptografados limitados.
    • ❌ No máximo 10 pares criptografados são suportados no modo Station;
      6 no máximo no modo SoftAP ou SoftAP + Station. Vários pares não
      criptografados são suportados, no entanto, seu número total deve
      ser menor que 20, incluindo pares criptografados.
    • ❌ A carga útil é limitada a 250 bytes.

    🔧 Como funciona o protocolo ESP-NOW


    O funciona com um protocolo de comunicação WI-FI sem conexão,
    definido pelo Espressif. No ESP-NOW, os dados do
    aplicativo são encapsulados em um quadro de ação específico do
    fornecedor e depois transmitidos de um
    dispositivo WI-FI para outro sem conexão. A
    CTR com o protocolo CBC-MAC (CCMP) é usada para
    proteger o quadro de ação por segurança.


    Iremos exemplificar o funcionamento do protocolo ESP-NOW dando
    um exemplo de comunicação básico, nesse exemplo iremos
    utilizar um par de NodeMCU ESP8266 pelo qual iremos
    enviar dados para um outro NodeMCU ESP8266, e iremos
    explicar o código por partes para que possamos entender melhor o
    funcionamento dessa comunicação.


    Começaremos pela biblioteca espnow.h que será
    utilizada para estabelecer a comunicação entre os ESP8266, será
    essa biblioteca que iremos utilizar em nosso exemplo. 

    As funções intrínsecas na biblioteca espnow.h utilizados
    para execução das comunicações são bastante abrangentes, no entanto
    iremos centralizar nas principais funções seguindo um exemplo de
    comunicação entre dois NodeMCU, que irá estabelecer uma
    comunicação entre eles e um dos ESP8266 irá acionar um botão e
    o outro receberá essa informação e irá acender o LED.

    🔌Inicializando ESP-NOW


    O primeiro passo para fazer essa comunicação entre os
    ESPs8266 é inicializar a biblioteca, existem
    duas bibliotecas mais conhecidas desenvolvidas para ESPs,
    a primeira é a biblioteca: esp_now.h, que é
    uma biblioteca desenvolvida para ser utilizada com
    ESP32.

    Outra é biblioteca espnow.h, essa é uma biblioteca
    desenvolvida para ser utilizada com o ESP8266 e é a
    biblioteca que iremos utilizar em nosso exemplo.

    💻 Código ESP-NOW do “Master”


    O termo utilizado “Master” na verdade é uma atribuição que fazemos para determinar qual será o
    ESP que irá “comandar” digo “entre aspas” pois
    todos os ESPs estão em modo STAStation“, que nesse caso ambos podem ser “Master” não ha distinção
    entre ambos, então utilizamos a atribuição só para termos base e
    entendermos melhor os códigos.

    • Nas primeiras linhas – iniciaremos o código chamando as bibliotecas que são
      pertinentes para o uso com o ESP8266:

    8
    9
    10
    11
    #include <ESP8266WiFi.h>
    extern "C" {
    #include <espnow.h>
    }

    • Na linha 13 – Temos o endereço Mac do Módulo ESP Slave, e é ele que
      irá receber os comandos, e acionará “
      as cargas” os
      LEDs. 
    • Na linha 14 – definimos o canal da transmissão WI-FI para o
      canal 4. 
    • E na linha 15 – temos uma variável tipo inteira para comutar o
      estado anterior do Led, já estamos determinando o estado de
      inicialização dela no nível baixo, LOW.

    13
    14
    15
    uint8_t mac[] = {0x36, 0x33, 0x33, 0x33, 0x33, 0x33};
    #define WIFI_CHANNEL 4
    int prevstate = LOW;

    • Na Linha 19 à 23 – temos a declaração das
      estruturas de controle de dados 1 e 2, que devem
      estar correspondidas com o ESP
      Slave, e deverá ser programado
      com as mesmas configurações.

    No primeiro parâmetro temos a
    estrutura de controle de dados 1
    , será o (buttonpressed) que corresponderá o pressionar do
    botão.

    19
    20
    21
    22
    23
    struct __attribute__((packed))                               
    DataStruct {
    char text[32];
    };
    DataStruct buttonpressed;

    • Na Linha 25 à 29 – Temos a
      estrutura de controle de dados 2, que será o
      (buttonreleased) que corresponderá quando soltarmos o
      botão.

    25
    26
    27
    28
    29
    struct __attribute__((packed))                               
    DataStruct {
    char text[32];
    };
    DataStruct buttonreleased;

    Depois dos processos de declarações, estruturas, e inclusão
    de variáveis, entraremos no
    Void setup() onde
    iremos atribuir os parâmetros de pinagens, inicialização das
    funções, os modos com que o controlador irá funcionar, ou
    seja, uma configuração inicial geral.

    • Na Linha 32 
      Iniciamos a função
      void setup()
    • Na linha 33 
      Declaramos a GPIO D1 como entrada, utilizando o
      parâmetro INPUT_PULLUP, que estabelece o resistor
      pullup interno, fazendo com que não precisemos colocar
      um resistor externo.
    • Na linha 34 – Declaramos a GPIO D0 como Saída, que será
      utilizada com o LED de indicação.
    • Na linha 35 – Temos a inicialização do Serial Monitor e o parâmetro de velocidade de transferência de dados setada em (115200).

    32
    33
    34
    35
    void setup() {                                            
       pinMode(D1,INPUT_PULLUP);
       pinMode(D0,OUTPUT);
       Serial.begin(115200);

    • Na Linha 37 – Iniciamos o modo em que o ESP irá trabalhar que
      no caso, estamos utilizando o Modo Station STA“,
      ambos os ESPs irão trabalhar com esse mesmo modo.
    • Na Linha 38 – Iniciamos a função que certifica de que nada irá
      estar conectado ao ESP antes de ele iniciar os parâmetros
      de transmissão ESP-NOW.

    37
    38
    WiFi.mode(WIFI_STA);                                          
    WiFi.disconnect();

    • Na Linha 39 – Utilizamos a função Serial.printf() para imprimir o
      endereço Mac do módulo Master ESP8266.
    • Na Linha 40 – Utilizamos a função Serial.printf() para imprimir o endereço Mac do Módulo Slave ESP8266.
    • Na Linha 41 – Utilizamos a
      função Serial.printf() para imprimir o
      Canal utilizado para fazer a transmissão e recepção entre os
      módulos.

    39
    40
    41
    Serial.printf("This mac: %s, ", WiFi.macAddress().c_str());
    Serial.printf("slave mac: %02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    Serial.printf(", channel: %in", WIFI_CHANNEL);

    • Na Linha 42 – Faz-se uma comparação declarando uma condicional if,
      que verifica se a função esp_now_init(), que inicia o
      protocolo ESP-NOW, foi inicializada
      corretamente. 

    Essa função tem dois valores de retorno: 0 = Erro, e
    1 = OK, então na comparação, analisa-se a função
    esp_now_init(), se o valor de retorno for igual
    1, a inicialização foi estabelecida com sucesso, se
    o valor de retorno for igual a 
    0, na próxima
    linha…

    • Na Linha 44 – Ele imprime
      no Serial Monitor a mensagem de falha na
      inicialização.

    42
     44
    if (esp_now_init() != 0){
    Serial.println("*** ESP_Now initialization failed");}
    • Na Linha 46 – Temos a função que determinará o modo de trabalho do ESP8266, que no nosso caso, estamos colocando-a
      como Master:

    Existem ainda dois modos a mais que podem ser
    implementadas substituindo os parâmetros
    apropriados: 

    ESP_NOW_ROLE_SLAVE  para coloca-lo no modo Slave.

    ESP_NOW_ROLE_COMBO para coloca-lo no modo Master +
    Slave

    • Na Linha 47 – Temos a função que adiciona os dados requeridos do Slave; Armazena o Endereço MAC; Seta o Modo de operação Módulo; Seta o Canal do Módulo;
      Seta a chave de 16 bytes necessária para a comunicação
      ESP-NOW; E seta o comprimento da chave, que deve ter
      16 bytes

    No nosso caso, estamos passando esses dois últimos parâmetros com NULL, e 0. Quando
    colocamos zero no ultimo parâmetro de retorno, isso
    quer dizer que a comunicação está OK.

    • Na Linha 48 – temos a função strcpy() que copia a
      string Button pressed” e aponta para a fonte de
      destino a string tipo chartext” que está
      concatenada com a estrutura de dados
      buttonpressed.
    • Na Linha 49 – Temos a mesma função, o que difere é a string e
      para onde ela aponta.
    • Na Linha 50 – Ele imprime no Serial Monitor a mensagem de Setup Concluído.

    46
     47
    48
    49
    50
    esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);                                             
    esp_now_add_peer(mac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULL, 0);
    strcpy(buttonpressed.text,"Button pressed");
    strcpy(buttonreleased.text,"Button Released");
    Serial.println("Setup finished");

    • Na Linha 54 – Entramos  na função
      void loop, que é a função que
      fica rodando todo o programa que estiver dentro dessa função, no
      nosso caso fizemos outra função dentro dela.
    • Na Linha 55 – Temos a função sendData,
      que constantemente fica analisando se houve o pressionar da
      chave Switch, e se sim, ele
      envia esses dados para o ESP Client.

    54
     55
    void loop() {                                       
    sendData();

    • Na Linha 59 – Entramos  na função void sendData, que como já dito acima é responsável por verificar o
      pressionar do botão e enviar se caso foi pressionado ou
      solto.
    • Na Linha 60 – Declaramos uma variável int” tipo Inteira, que recebe a função digitalRead(D1), que ler se a
      chave Switch que está ligado na GPIO D1 foi
      pressionada
      , caso ela seja LOW ou HIGH, a variável currentstate
      recebe essa informação, e as mantém na sua memória.

    59
     60
    void sendData() {                                      
    int currentstate = digitalRead(D1);

    • Na Linha 61 – Temos a função if, que faz um comparação lógica se a
      variável global, descrita no início do
      programa prevstate é diferente da variável currentstate que
      recebeu a leitura da GPIO D1. 
    • Na Linha 62 – Entramos em outro if dentro do
      if anterior, que faz uma comparação se o estado da
      variável currentstate é igual a HIGH ou
      LOW.

    60
     61
    if(prevstate != currentstate){                                 
      if(currentstate == HIGH){

    • Na Linha 63 –  Temos uma variável bs de 8 bits
      que recebe o operador sizeof que 
      retorna o tamanho da string buttonpressed. e
      armazena na varável bs.
    • Na Linha 64 –  Temos a função memcpy padrão que armazena todo conteúdo que
      está dentro dela na memória.

    63
     64
    uint8_t bs[sizeof(buttonpressed)];                               
      memcpy(bs, &buttonpressed, sizeof(buttonpressed));

    • Na Linha 65 – Temos a função que envia o pacote de dados para o
      ESP Salve que tenha o endereço
      MAC cadastrado no início do código, como já apresentado
      na Linha 6. 

    Essa função é seguido de três parâmetros que vale a pena
    abordar:

    1. Parâmetro: Endereço MAC –  Se for NULL, o pacote será enviado para todos
    os 
    endereços MAC gravados pelo ESP-NOW.

    2. Parâmetro: Dados a ser enviado

    3. Parâmetro: Tamanho dos dados.

    • Na Linha 66 – Temos a já bastante conhecida função que imprime no serial
      monitor a string
      buttonpressed.
    • Na Linha 67 – Temos a também conhecida função que escreve na porta digital IO
      o estabelecido dentro da sua função com dois parâmetros
      (
      Porta, Estado).

    65
     66
    67
    esp_now_send(NULL, bs, sizeof(buttonpressed));                          
      Serial.println(buttonpressed.text);
      digitalWrite(D0, LOW);

    • Na Linha 68 – Temos a função else if que faz a comparação, só que
      desta vez, é para o movimento oposto, ou seja se o botão foi
      solto, ele armazena os dados se LOW ou
      HIGH.
    • Na Linha 69 – Também temos a mesma variável bs de 8 bits que recebe o operador sizeof que retorna o tamanho da string buttonreleased. e armazena na varável bs.
    • Na Linha 70 – Também temos a função memcpy padrão que armazena todo
      conteúdo que está dentro dela na memória.
    • Na Linha 71 – Temos a função que envia o pacote de dados para
      ESP Salve que tenha o endereço MAC cadastrado no início do código, como já apresentado
      na 
      Linha 6. 
    • Na Linha 72 – Temos a já bastante conhecida função que imprime no serial
      monitor a string buttonreleased.
    • Na Linha 73 – Temos a também conhecida função que escreve na
      porta digital IO o estabelecido dentro da sua função
      com dois parâmetros (Porta, Estado).
    • Na Linha 75 – Temos a variável global prevstate recebendo uma nova atualização do ultimo estado da
      variável
      currentstate.

    68
     69
    70
    71
    72
    73
    75
    }else if(currentstate == LOW){                   
        uint8_t bs[sizeof(buttonreleased)];
        memcpy(bs, &buttonreleased, sizeof(buttonreleased));
        esp_now_send(NULL, bs, sizeof(buttonreleased));
      Serial.println(buttonreleased.text);
      digitalWrite(D0, HIGH);}
    }prevstate = currentstate;

    E aqui finalizamos a explicação básica do código
    ESP-NOW 
    Master.

    💻 Código ESP-NOW do “Slave”

    No Slave, iremos resumir, daremos explicações só
    nos parâmetros que não foram explicados no código
    do Master acima, para não ficar tão
    repetitivo.

    • Nas primeiras linhas – Assim como o Master iniciaremos o código
      chamando as bibliotecas que são específicas para
      ESP8266, com a diferença que temos a biblioteca
      user_interface.h
      para se incluir, essa biblioteca é necessária para acessar os
      Timer`s. do ESP8266.

    7
    8
    9
    10
    #include <ESP8266WiFi.h>                                      
    extern "C" {
    #include <espnow.h>
    #include <user_interface.h>

    • Na Linha 17,18,19 – Temos uma função void initVariant(),
      que seta o endereço MAC Access Point do ESP8266, pelo
      MAC que você determina na
      String mac.

    17
    18
    19
    void initVariant() {                          
      WiFi.mode(WIFI_AP);
      wifi_set_macaddr(SOFTAP_IF, &mac[0]);

    • Na Linha 45 – Temos a função que determinará o modo de trabalho do ESP8266, que no nosso caso, estamos
      colocando-a como Slave.
    • Na Linha 46 – Temos a função de registro do CallBack que é
      responsável por 
       registrar as informações vinda do Master, com o
      argumento da função que será 
      executada e está declarada dentro da função cb.

    45
    46
    esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);                             
    esp_now_register_recv_cb(receiveCallBackFunction);

    • Na Linha 55 – Temos a função que recebe os dados vindo do ESP Controle, e
      que será utilizado para fazer o disparo do LED.
    • Na Linha 56 – Também temos a função memcpy padrão que
      armazena todo conteúdo que está dentro dela na
      memória.
    • Na Linha 62 – Temos a função que faz um flip-flop do Led1, ou
      seja, ele faz a leitura do estado do Led1 e determina
      seu estado inverso ao estado dele mesmo. Ou seja: cada vez
      que entra na função receiveCallBackFunction ele
      escreve o estado do Led1 ao seu estado anterior…
      uma vez liga, outra vez desliga.

    55
    56
    62
    void receiveCallBackFunction(uint8_t *senderMac, uint8_t *incomingData, uint8_t len) {         
      memcpy(&myData, incomingData, sizeof(myData));;
     digitalWrite(Led1, !digitalRead(Led1));

    E aqui também termina as principais partes do código do
    Salve.

    📥 Download dos Códigos

    O código utilizado esta disponível para baixar no link direto logo abaixo, sinta-se à vontade para baixar e fazer suas próprias modificações.

    • Link Direto – Mega

    E por hoje é só, espero que tenhamos alcançado suas expectativas!

    Agradecemos por visitar o nosso blog e esperamos tê-lo(a) novamente por aqui em breve. Não deixe de conferir nossos outros conteúdos sobre tecnologia e assuntos variados.

    Se inscreva no nosso Blog! Clique Aqui — FVM Learning!

    Nos ajude a divulgar nosso trabalho, compartilha nas redes sociais, Facebook, Instagram, nos grupos de WhatsAppuma simples atitude sua, faz com que cresçamos juntos e melhoremos o nosso trabalho!

    Forte abraço!
    Deus vos Abençoe!
    Shalom.


    Compartilhar

    Deixe um comentário

    O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *