Controlando ESP32 via WiFi com validação por endereço MAC

macaddress

O macaddress é um endereço físico único em formato hexadecimal com 6 bytes, que é atribuído a todo hardware feito para comunicação em rede, e como a identificação é única, ela pode ser usada para fazer o controle de acesso em uma rede local, onde por exemplo, os roteadores permitem o bloqueio de endereços MAC específicos.

Neste tutorial vamos aplicar essa funcionalidade na ESP32, usando o Arduino IDE para programa-la no modo AP, e validar o acesso de dispositivos conectados através do endereço MAC. Somente após feita a validação será permitido ao usuário utilizar o sistema.

Importante informar que esse tutorial é de caráter didático, uma vez que, apesar do MAC ser único para cada dispositivo, é possível alterá-lo usando técnicas específicas, o que não garante segurança efetiva contra usuários não autorizados. O código completo usado nesse tutorial está disponível na minha conta do Github.

Instalando bibliotecas

Existe um complemento para o Arduino IDE afim de suportar as placas da ESP32, para fazer a instalação confira o tutorial para Windows do Gabriel Almeida. Para outros sistemas operacionais, siga as instruções na conta Github dos fornecedores do complemento.

Também iremos usar a biblioteca ESP_ClientMacaddress disponível no meu Github.

Configurando WiFi no modo AP (Access Point)

Um Access Point é uma Rede de Conexão Local Wireless (WLAN), por onde podemos conectar um dispositivo (client) a ESP (host) via WiFi.

Primeiro importamos a seguinte biblioteca para configurar a conexão WiFi na ESP.

#include <WiFi.h>

Escolha o SSID e a Senha que desejar, essa será a forma de identificar a rede na qual o usuário deverá conectar-se:

const char* ssid = "meu_ssid"; 
const char* senha = "minha_senha";

WiFi Server configurado na porta 80:

WiFiServer server(80);

Dentro do setup(), para setar a ESP no modo AP usamos este comando:

WiFi.softAP(ssid, senha);

E para iniciar o servidor:

server.begin();

Neste ponto seu código deve estar dessa forma:

#include <WiFi.h> //funcionalidades de conexão wifi, como AP e WebServer 
//Crendenciais do ponto de acesso 
const char *ssid = "meu_ssid"; 
const char *senha = "minha_senha"; 
WiFiServer server(80); //Porta padrão 80
void setup() { //Inicializa serial 
Serial.begin(115200); 
Serial.println(); //Configura ESP no modo 
APSerial.printf("Configurando ponto de acesso '%s'n", ssid); 
WiFi.softAP(ssid, senha); 
server.begin(); 
Serial.println("Configuração conluída"); }

void loop() { }

Agora grave o código na ESP, e então use um celular pra verificar se a rede WiFi aparece disponível, mas não conecte ainda.

Fig 1 – Redes Disponíveis

Enviando comandos através dos cabeçalhos HTTP do client 

Edite o loop() de acordo com o código a seguir. 

void loop() { 

    //Verifica se existe algum client na rede  
    WiFiClient client = server.available();  
    //Caso positivo, imprime "Novo Client" no monitor  
    if (client){ 
        Serial.println("Novo Client");  
        //Enquanto client conectado, verifica se existem bytes a serem lidos 
        //e concatena os bytes recebidos na String cabecalho; 
        while (client.connected()){  
           if (client.available()){  
              cabecalho += (char)client.read();  
              //Se receber nova linha em branco, encerrou leitura dos dados  
              if (cabecalho.endsWith("nrn")){  
                  Serial.println(cabecalho); //imprime cabeçalhos http recebidos 
                  //iniciamos a resposta http com o código OK(200), 
                  //o tipo de conteúdo a ser enviado e tipo de conexão. 
                  client.println("HTTP/1.1 200 OK"); 
                  client.println("Content-Type:text/html"); 
                  client.println("Connection: close"); 
                  client.println(); 
                  //INSIRA AQUI SUA APLICAÇÃO 

                  break; //sai do while loop  
              }  
           } 
        }  
        cabecalho = ""; //ao encerrar conexão, limpa variável cabecalho 
        client.flush(); client.stop(); 
        Serial.println("Client desconectado."); Serial.println(); 
    } 
} 

Assim durante a execução do loop(), a ESP estará sempre verificando se foi feita alguma conexão. Uma vez recebida uma solicitação do client, iremos salvar os dados recebidos na String cabeçalho, e com o comando client.println() respondemos com o status OK(código 200) para sinalizar ao client que recebemos os dados com sucesso. Mais adiante, o campo comentando “INSIRA AQUI SUA APLICACAO” será o local onde iremos programar as funcionalidades de controle. 

Grave o código, e com um celular conecte-se a rede WiFi que você nomeou, e então no navegador digite o endereço IP 192.168.4.1 do nosso host(ESP), fazendo isso, no monitor do Arduino IDE teremos o output com os cabeçalhos HTTP recebidos com as informações do dispositivo. 

Fig 2 – Resposta no Monitor Serial do Arduino IDE

Experimente digitar no seu navegador o IP da ESP seguido de qualquer texto, por exemplo digite 192.168.4.1/teste, e verá que o conteúdo da url digitada também é capturado, logo, através da url podemos determinar comandos a serem enviados para a ESP. 

Fig 3 – Comando recebido através dos cabeçalhos HTTP

Vamos usar essa estratégia para enviar comandos a ESP através do navegador. Neste caso enviaremos comandos para alternar o estado do LED embarcado no módulo da ESP32, que está conectado ao pino 2 da placa. 

No início do setup(),  adicione um comando para configurar o pino que controla o LED como sda. 

void setup(){ 
    //Configura o pino conectado ao LED como saída 
    pinMode(2, OUTPUT); 
    ....... 
} 

Dentro do loop(), abaixo do comentário “INSIRA AQUI SUA APLICAÇÃO”, vamos projetar o sistema para fazer a leitura dos comandos LED_ON e LED_OFF, assim podendo controlar pelo navegador o estado do LED, da seguinte maneira:

... 
//INSIRA AQUI SUA APLICAÇÃO 
if(cabecalho.indexOf("GET /LED_ON")>= 0){ 
    digitalWrite(2, true); //Acende o LED 
}else if(cabecalho.indexOf("GET /LED_OFF")>= 0){ 
    digitalWrite(2, false); //Apaga o LED 
} 
... 

Grave o código, conecte-se a rede WiFi da ESP, e no navegador digite 192.168.4.1/LED_ON para acender o LED, ou 192.168.4.1/LED_OFF para apagar o LED. 

 

Controlando ESP32 através de uma página web com HTML 

 

Agora temos que criar nossa página web, para isso criamos a função run_html()que receberá como parâmetro o próprio client. 

void run_html(WiFiClient client) { 
} 

Então começamos o código html com as seguintes tags usadas para iniciar um documento html.

<!DOCTYPE html><html>

Os seguintes comandos CSS do <head > na nossa página alinham o conteúdo de acordo com o tamanho da tela do dispositivo. 

<head><style media='screen' type='text/css'> 
    html{display:inline-block;margin:10px auto;text-align:center;} 
</style></head>

Em seguida fazemos o corpo da nossa página que é redigida entre as tags <body></body>, e no corpo inserimos um cabeçalho com o título ‘ACIONAMENTO LED’ usando as tags <h1></h1>.

<h1 style='font-size:80px'>ACIONAMENTO LED</h1> 

Ainda no corpo da página, inserimos um botão entre as tags <button></button> com o título ‘ON’ e comprimento de 200px e tamanho da fonte de 80px.

<button style='width:200px;font-size:80px'>ON</button>

Anteriormente para acender o LED, tivemos que digitar no navegador o endereço IP mais o comando LED_ON, desta vez vamos atribuir essa função ao botão que acabamos de criar. 

Para isso colocamos a linha de código do botão entre as tags <a></a> com o link de redirecionamento, e usamos a tag <p> para posicionar os botões verticalmente. 

<p><a href=‘/LED_ON’> 
    <button style='width:200px;font-size:80px'>ON</button> 
</a></p> 

E de forma semelhante fazemos mais um botão para desligar o LED. 

<p><a href=‘/LED_OFF’> 
    <button style='width:200px;font-size:80px'>OFF</button> 
</a></p> 

Finalmente encerramos o documento html com a tag </html>. 

Dentro da função run_html(), vamos armazenar o conteúdo HTML na String html_content, e usar o comando client.println() afim de a ESP enviar o código html para o client, assim a função fica dessa forma:

void run_html(WiFiClient client){ 
    String html_content = \ 
    "<!DOCTYPE html><html>" \ 
        "<head><style media='screen' type='text/css'>" \  
            "html{display:inline-block;margin:10px auto;text-align:center;}" \  
        "</style></head>" \   
        "<body>" \ 
            "<h1 style='font-size:40px'>Acionamento LED</h1>" \  
            "<p><a href='/LED_ON'>" \ 
                "<button style='width:200px;font-size:80px'>ON</button>" \  
            "</a></p>" \ 
            "<p><a href='/LED_OFF'>" \ 
                "<button style='width:200px;font-size:80px'>OFF</button>" \  
            </a></p>" \ 
        "</body>" \ 
    "</html>"; 

    client.println(html_content); 
} 

Agora que nossa página web está pronta, voltaremos ao loop(), e no campo “INSIRA AQUI SUA APLICAÇÃO” adicionamos uma chamada pra função run_html(). 

//INSIRA AQUI SUA APLICAÇÃO HTML 
run_html(client); 
if(cabecalho.indexOf("GET /LED_ON")>= 0){ 
    digitalWrite(2, true); //Acende o LED 
}else if(cabecalho.indexOf("GET /LED_OFF")>= 0){ 
    digitalWrite(2, false); //Apaga o LED 
} 
... 

Grave o código na ESP e conecte-se a rede WiFi com seu celular ou computador, e no navegador digite o IP 192.168.4.1 para carregar a página html. Agora, ao invés de digitar os comandos LED_ON ou LED_OFF no seu navegador para acionar o LED, você poderá fazer isso simplesmente acionando os botões da página, e a solicitação http será enviada do client (seu navegador) para o host (ESP). 

Fig 4 – Página web para controle do LED

Validando acesso por WiFi macaddress 

 

Importe a biblioteca ESP_ClientMacaddress. 

#include <ESP_ClientMacaddress.h> 

Acesse as configurações WiFi do seu celular e procure pelo endereço MAC (macaddress), no link você tem acesso a instruções de como visualizar o macaddress para Android, iOS, Windows Phone e PC. 

Fig 5 – Endereço MAC de um celular com Android

De volta ao código, crie um array para armazenar os bytes do endereço MAC de quaisquer dispositivos que deseje autorizar o acesso. 

Neste exemplo vou usar 3 macaddress fictícios, onde também deve-se definir a quantidade de dispositivos. 

#define NUM_DISPOSITIVOS 3 

uint8_t macList[NUM_DISPOSITIVOS][6] = { 
    {0xA7,0x16,0xD0,0xA6,0x45,0x3B}, 
    {0xB8,0x17,0xE0,0xA7,0x55,0x3C},  
    {0xC9,0x18,0xD0,0xA8,0x65,0x3D}  
}; 

Crie a váriavel booleana mac_conhecido. 

bool mac_conhecido; 

Agora instanciamos a classe ClientMacaddress, passando como parâmetro a lista de endereços MAC e a quantidade de dispositivos autorizados. 

ClientMacaddress clientMac(macList, NUM_DISPOSITIVOS); 

Altere o código do campo “INSIRA AQUI SUA APLICAÇÃO” como demonstrado a seguir: 

... 
//INSIRA AQUI SUA APLICAÇÃO HTML 

//Variável 'm' aponta para o endereço MAC do client 
uint8_t *m = clientMac.getAddr(client); 
Serial.printf("Macaddress:%.2X:%.2X:%.2X:%.2X:%.2X:%.2Xn", 
                           m[0],m[1],m[2],m[3],m[4],m[5]); 
 
//determina se o endereço MAC do client é conhecido 
mac_conhecido = clientMac.isKnown(m); 

run_html(client); //envia ao client conteúdo HTML 

//Se client possui MAC conhecido, libera acesso para controlar o LED 
if(mac_conhecido){ 
    Serial.println("mac ok"); 
    if(cabecalho.indexOf("GET /LED_ON")>= 0){ 
        digitalWrite(2, true); //Acende o LED 
    }else if(cabecalho.indexOf("GET /LED_OFF")>= 0){ 
        digitalWrite(2, false); //Apaga o LED 
    } 
}else{ 
    Serial.println("mac não autorizado");  
} 
... 

Com essa alteração, o comando getAddr() armazena na variável m o endereço MAC do client, em seguida o comando isKnown() seta a variável mac_conhecido como true se o MAC for conhecido, ou false caso seja desconhecida, dessa forma impedindo que dispositivos não autorizados tenham acesso ao controle do LED. 

E pra finalizar, alteramos a função run_html(), de forma que a página web só libere acesso aos botões ON e OFF se o client tiver um endereço MAC conhecido, caso contrário carregamos a mensagem de alerta “DISPOSITIVO NÃO AUTORIZADO”. 

void run_html(WiFiClient client){ 
    String html_content = \ 
    "<!DOCTYPE html><html>" \  
       "<head><style media='screen' type='text/css'>" \ 
            "html{display:inline-block;margin:10px auto;text-align:center;}" \ 
       "</style></head>" \  
       "<body>" \  
       "<h1 style='font-size:40px'>Acionamento LED</h1>"; \ 
       if(mac_conhecido){ 
          html_content += \ 
          "<p><a href='/LED_ON'>" \ 
              "<button style='width:200px;font-size:80px'>ON</button>" \ 
          "</a></p>" \ 
          "<p><a href='/LED_OFF'>" \ 
              "<buttonstyle='width:200px;font-size:80px'>OFF</button>" \ 
          "</a></p>"; 
       }else{ 
          html_content += \ 
          "<p style='color:red;font-size:40px'>DISPOSITIVO NAO AUTORIZADO</p>"; 
       } 
       html_content += \ 
       "</body>" \ 
    "</html>"; 

    client.println(html_content);  
} 

Grave o código, e desta vez, usando um dispositivo qualquer que você NÃO tenha cadastrado o endereço MAC, conecte-se a rede WiFi da ESP e digite o IP 192.168.4.1 no seu navegador. Assim o usuário será notificado que o dispositivo não é autorizado a acessar o sistema. 

Fig 6 – Página web com mensagem de alerta

Acabamos! 

Neste tutorial você aprendeu a como construir um Access Point com um módulo ESP32, usando a biblioteca ESP_ClientMacaddress para realizar a validação do Endereço MAC do dispositivo conectado. 

Vimos um exemplo simples de como controlar um LED usando como interface uma página web, agora você pode trabalhar com base neste exemplo substituindo o LED para acionar um relé ou qualquer outro dispositivo, e também customizar a página web. 

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
12 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Guliver Watchson
Guliver Watchson
14/08/2019 17:41

WIFI_AcessPoint:31:15: error: ‘cabecalho’ was not declared in this scope

cabecalho += (char)client.read();

Felipe Jorge
Felipe Jorge
Reply to  Guliver Watchson
06/09/2019 16:56

Tive esse mesmo erro, a espera da solução

Thiago Tavares
Thiago Tavares
Reply to  Felipe Jorge
16/09/2019 19:04

Basta vc colocar String cabecalho antes do while(client.connected())

Thiago Tavares
Thiago Tavares
Reply to  Guliver Watchson
16/09/2019 15:25

Tive o mesmo erro

LUCAS RUSSIGNOLI PEIXOTO
LUCAS RUSSIGNOLI PEIXOTO
30/10/2021 18:38

o meu nao carrega nada na web quando entro com 192.168.4.1

Rogerio
Rogerio
05/02/2020 01:23

Olá Roger.
Muito bom artigo.
Parabéns !
Gostaria de saber se há como passar um numero pela url.
De preferência usando um formulário.
Obrigado.

Roger
Roger
Reply to  Rogerio
12/08/2022 13:34

Olá, é possível enviar sim através de formulário, fica a cargo de vc parsear esse dado na ESP

Vinicius Arpino
Vinicius Arpino
05/06/2019 14:29

Boa tarde, logo lá no início na criação da rede, eu jogo o programa na placa e ela não gera a rede. O que pode ser?

Mario C G Moura
Mario C G Moura
19/03/2019 05:44

Bom dia! Você tá de parabéns….escreve de forma concisa e objetiva.
Muito bom artigo.

Home » Internet Das Coisas » Controlando ESP32 via WiFi com validação por endereço MAC

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: