Implementando Formulários Web para Controle no ESP32

Introdução🔗

O ESP32 é uma poderosa plataforma que combina conectividade Wi-Fi e Bluetooth com um microcontrolador de alto desempenho. Isso o torna ideal para uma variedade de projetos de IoT e automação residencial. Uma das funcionalidades mais interessantes do ESP32 é a capacidade de hospedar um servidor web, permitindo que você controle e monitore dispositivos remotamente através de uma interface web.

Neste artigo, vamos explorar como implementar formulários web no ESP32 para controlar dispositivos. Vamos construir um servidor web que apresenta um formulário ao usuário, processa os dados enviados e executa ações com base nesses dados.

Por que Utilizar Formulários Web no ESP32?🔗

Formulários web são uma forma intuitiva e acessível de interagir com sistemas eletrônicos. Ao implementar formulários no ESP32, você pode:

  • Controlar dispositivos remotamente: Ligar/desligar LEDs, motores, relés, etc.
  • Receber inputs do usuário: Ajustar configurações, selecionar modos de operação e muito mais.
  • Criar interfaces amigáveis: Facilitar a interação mesmo para usuários com pouca experiência técnica.

Utilizar formulários web elimina a necessidade de aplicações móveis ou interfaces físicas complicadas. Tudo o que você precisa é de um navegador web, tornando o acesso ao seu dispositivo simples e universal.

Preparando o Ambiente🔗

Antes de começarmos, certifique-se de ter o seguinte:

  • Placa ESP32: Pode ser qualquer modelo compatível.
  • Cabo USB: Para programar a placa.
  • Arduino IDE: Ambiente de desenvolvimento configurado para o ESP32.
  • Conexão Wi-Fi: Para conectar o ESP32 à rede.

Configurando o Arduino IDE

Se você ainda não configurou o ESP32 na Arduino IDE, siga estes passos:

1. Abra a Arduino IDE.

2. Vá em Arquivo > Preferências.

3. No campo URLs Adicionais para Gerenciadores de Placas, adicione:

https://dl.espressif.com/dl/package_esp32_index.json

4. Clique em OK.

5. Vá em Ferramentas > Placa > Gerenciador de Placas.

6. Pesquise por ESP32 e instale a opção "esp32" by Espressif Systems.

Conectando o ESP32 à Rede Wi-Fi🔗

Para que o ESP32 possa hospedar um servidor web acessível pela rede, ele precisa estar conectado ao Wi-Fi.

#include <WiFi.h>
const char* ssid = "NOME_DA_SUA_REDE";
const char* password = "SENHA_DA_SUA_REDE";
void setup()
{
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.print("Conectando ao Wi-Fi");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConectado com sucesso!");
  Serial.print("Endereço IP: ");
  Serial.println(WiFi.localIP());
}
void loop()
{
  // Código principal
}
Explicação:
  • Inclusão da biblioteca WiFi: Necessária para as funcionalidades Wi-Fi.
  • Credenciais da rede: Substitua "NOME_DA_SUA_REDE" e "SENHA_DA_SUA_REDE" pelas suas credenciais.
  • Conectando ao Wi-Fi: O ESP32 tenta se conectar e exibe o endereço IP obtido.

Criando um Servidor Web Simples🔗

Vamos agora configurar um servidor web básico que servirá uma página ao ser acessado.

#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "NOME_DA_SUA_REDE";
const char* password = "SENHA_DA_SUA_REDE";
WebServer server(80);
void setup()
{
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  // Aguarda conexão
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConectado ao Wi-Fi.");
  Serial.print("Endereço IP: ");
  Serial.println(WiFi.localIP());
  // Define a rota raiz
  server.on("/", handleRoot);
  // Inicia o servidor
  server.begin();
  Serial.println("Servidor HTTP iniciado.");
}
void loop()
{
  server.handleClient();
}
void handleRoot()
{
  server.send(200, "text/plain", "Bem-vindo ao servidor web do ESP32!");
}
Explicação:
  • Configuração do servidor: Usamos a biblioteca WebServer para criar um servidor na porta 80.
  • Definição da rota: A função handleRoot() será chamada quando a raiz ("/") for acessada.
  • Resposta ao cliente: Enviamos uma mensagem simples de texto.

Implementando um Formulário Web🔗

Agora, vamos criar um formulário web que permita ao usuário controlar um LED conectado ao ESP32.

Montagem do Circuito

Para este exemplo, usaremos o LED embutido da placa (geralmente no pino GPIO 2). Se a sua placa não tiver um LED embutido, você pode conectar um LED externo ao GPIO 2 através de um resistor de 220Ω.

Atualizando o Código

Variáveis Globais e Configuração

const int ledPin = 2; // Pino do LED
void setup()
{
  // ... código anterior ...
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW); // Inicialmente desligado
  // Define as rotas
  server.on("/", handleRoot);
  server.on("/led", HTTP_POST, handleLED);
  // Inicia o servidor
  server.begin();
}

Função handleRoot()

Vamos servir uma página HTML com um formulário.

void handleRoot()
{
  String html = "<!DOCTYPE html><html>";
  html += "<head><title>Controle de LED</title></head>";
  html += "<body>";
  html += "<h1>Controle de LED</h1>";
  html += "<form action=\"/led\" method=\"POST\">";
  html += "<label for=\"estado\">Estado do LED:</label><br><br>";
  html += "<input type=\"radio\" id=\"ligar\" name=\"estado\" value=\"ligar\">";
  html += "<label for=\"ligar\">Ligar</label><br>";
  html += "<input type=\"radio\" id=\"desligar\" name=\"estado\" value=\"desligar\">";
  html += "<label for=\"desligar\">Desligar</label><br><br>";
  html += "<input type=\"submit\" value=\"Enviar\">";
  html += "</form>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}
Explicação:
  • Construção da página HTML: Utilizamos uma String para concatenar o conteúdo HTML.
  • Formulário: O formulário envia uma requisição POST para a rota /led.

Função handleLED()

Esta função processa os dados enviados pelo formulário.

void handleLED()
{
  if (server.hasArg("estado"))
  {
    String estado = server.arg("estado");
    if (estado == "ligar")
    {
      digitalWrite(ledPin, HIGH);
    }
    else if (estado == "desligar")
    {
      digitalWrite(ledPin, LOW);
    }
  }
  // Redireciona de volta para a página inicial
  server.sendHeader("Location", "/");
  server.send(303);
}
Explicação:
  • Verificação dos argumentos: Utilizamos server.hasArg() para verificar se o parâmetro estado foi enviado.
  • Leitura do valor: server.arg("estado") retorna o valor selecionado pelo usuário.
  • Controle do LED: Dependendo do valor, ligamos ou desligamos o LED.
  • Redirecionamento: Após processar o formulário, redirecionamos o usuário de volta para a página inicial.

Testando a Aplicação🔗

1. Carregue o código no ESP32.

2. Abra o Monitor Serial para verificar o endereço IP atribuído.

3. Acesse o endereço IP do ESP32 pelo navegador (por exemplo, http://192.168.1.100).

4. Utilize o formulário para ligar ou desligar o LED.

Aprimorando a Interface Web🔗

Vamos melhorar a experiência do usuário exibindo o estado atual do LED na página.

Atualizando handleRoot()

void handleRoot()
{
  String estadoLED = digitalRead(ledPin) ? "Ligado" : "Desligado";
  String html = "<!DOCTYPE html><html>";
  html += "<head><title>Controle de LED</title></head>";
  html += "<body>";
  html += "<h1>Controle de LED</h1>";
  html += "<p>O LED está atualmente: <strong>" + estadoLED + "</strong></p>";
  html += "<form action=\"/led\" method=\"POST\">";
  html += "<label for=\"estado\">Alterar estado:</label><br><br>";
  html += "<input type=\"radio\" id=\"ligar\" name=\"estado\" value=\"ligar\">";
  html += "<label for=\"ligar\">Ligar</label><br>";
  html += "<input type=\"radio\" id=\"desligar\" name=\"estado\" value=\"desligar\">";
  html += "<label for=\"desligar\">Desligar</label><br><br>";
  html += "<input type=\"submit\" value=\"Enviar\">";
  html += "</form>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}
Explicação:
  • Estado atual do LED: Lemos o estado do pino ledPin e exibimos na página.
  • Melhoria da interface: Adicionamos informações úteis para o usuário.

Implementando Validação no Formulário🔗

É importante validar os dados enviados pelo usuário para evitar comportamentos inesperados.

Atualizando handleLED()

void handleLED()
{
  if (server.hasArg("estado"))
  {
    String estado = server.arg("estado");
    if (estado == "ligar")
    {
      digitalWrite(ledPin, HIGH);
    }
    else if (estado == "desligar")
    {
      digitalWrite(ledPin, LOW);
    }
    else
    {
      server.send(400, "text/plain", "Valor inválido.");
      return;
    }
  }
  else
  {
    server.send(400, "text/plain", "Parâmetro 'estado' não encontrado.");
    return;
  }
  // Redireciona de volta para a página inicial
  server.sendHeader("Location", "/");
  server.send(303);
}
Explicação:
  • Validação do valor: Verificamos se o valor de estado é válido.
  • Respostas de erro: Enviamos uma resposta HTTP 400 (Bad Request) em caso de erro.

Melhorando a Segurança🔗

Para evitar que qualquer pessoa na rede controle o seu dispositivo, podemos adicionar uma autenticação simples.

Adicionando um Campo de Senha

Atualize o formulário para incluir um campo de senha.

void handleRoot()
{
  // ... código anterior ...
  html += "<label for=\"senha\">Senha:</label><br>";
  html += "<input type=\"password\" id=\"senha\" name=\"senha\"><br><br>";
  html += "<input type=\"submit\" value=\"Enviar\">";
  html += "</form>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

Atualizando handleLED()

const String senhaCorreta = "123456";
void handleLED()
{
  if (server.hasArg("senha"))
  {
    String senha = server.arg("senha");
    if (senha != senhaCorreta)
    {
      server.send(401, "text/plain", "Senha incorreta.");
      return;
    }
  }
  else
  {
    server.send(400, "text/plain", "Parâmetro 'senha' não encontrado.");
    return;
  }
  // ... código anterior de validação e controle do LED ...
  // Redireciona de volta para a página inicial
  server.sendHeader("Location", "/");
  server.send(303);
}
Explicação:
  • Senha fixa: Definimos senhaCorreta como uma constante.
  • Verificação da senha: Antes de processar o estado do LED, validamos a senha fornecida.
  • Respostas adequadas: Enviamos os códigos de status HTTP apropriados em caso de erro.

Estilos CSS para Melhorar a Aparência🔗

Vamos adicionar estilos simples para tornar a página mais agradável.

void handleRoot()
{
  // ... código anterior ...
  String html = "<!DOCTYPE html><html>";
  html += "<head>";
  html += "<title>Controle de LED</title>";
  html += "<style>";
  html += "body { font-family: Arial, sans-serif; text-align: center; }";
  html += "h1 { color: #333; }";
  html += "form { display: inline-block; margin-top: 20px; }";
  html += "input[type=submit] { padding: 10px 20px; }";
  html += "</style>";
  html += "</head>";
  // ... restante do código ...
}
Explicação:
  • Estilos embutidos: Utilizamos a tag