ÍNDICE DE CONTEÚDO
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.
1 |
#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:
1 2 |
const char* ssid = "meu_ssid"; const char* senha = "minha_senha"; |
WiFi Server configurado na porta 80:
1 |
WiFiServer server(80); |
Dentro do setup(), para setar a ESP no modo AP usamos este comando:
1 |
WiFi.softAP(ssid, senha); |
E para iniciar o servidor:
1 |
server.begin(); |
Neste ponto seu código deve estar dessa forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#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.
Enviando comandos através dos cabeçalhos HTTP do client
Edite o loop() de acordo com o código a seguir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
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.
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.
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 saída.
1 2 3 4 5 |
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:
1 2 3 4 5 6 7 8 |
... //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.
1 2 |
void run_html(WiFiClient client) { } |
Então começamos o código html com as seguintes tags usadas para iniciar um documento html.
1 |
<!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.
1 2 3 |
<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>.
1 |
<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.
1 |
<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.
1 2 3 |
<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.
1 2 3 |
<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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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().
1 2 3 4 5 6 7 8 |
//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).
Validando acesso por WiFi macaddress
Importe a biblioteca ESP_ClientMacaddress.
1 |
#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.
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.
1 2 3 4 5 6 7 |
#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.
1 |
bool mac_conhecido; |
Agora instanciamos a classe ClientMacaddress, passando como parâmetro a lista de endereços MAC e a quantidade de dispositivos autorizados.
1 |
ClientMacaddress clientMac(macList, NUM_DISPOSITIVOS); |
Altere o código do campo “INSIRA AQUI SUA APLICAÇÃO” como demonstrado a seguir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
... //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”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
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.
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.
WIFI_AcessPoint:31:15: error: ‘cabecalho’ was not declared in this scope
cabecalho += (char)client.read();
Tive esse mesmo erro, a espera da solução
Basta vc colocar String cabecalho antes do while(client.connected())
Tive o mesmo erro
Oi Guliver, a solução do Thiago Thavares resolveria o problema, faltou declarar a String cabecalho. Na imagem em anexo está destacado a solução, e também no link vc pode baixar o código completo funcionando.
https://github.com/moschiel/ESP_ClientMacaddress/blob/master/examples/access_control/access_control.ino
o meu nao carrega nada na web quando entro com 192.168.4.1
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.
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?
Oi vinicius, eu tive esse problema quando a senha era muito curta, tente deixar a senha com pelo menos 8 caracteres
Bom dia! Você tá de parabéns….escreve de forma concisa e objetiva.
Muito bom artigo.
Value @Mario C G Moura , esse é meu primeiro artigo e é muito legal receber esse feedback.
Ja estou redigindo mais conteúdo.
Muito obrigado !!!