Introdução
Neste artigo, mostraremos como criar um Web Server de tempo real utilizando a placa de desenvolvimento ESP32-C6 DevKitC-1. Vamos criar um servidor web que hospeda uma interface HTML e utiliza WebSocket para comunicação bidirecional, permitindo, por exemplo, controle de LEDs, leitura de sensores e resposta imediata sem a necessidade de atualizá-la manualmente.
Para conhecer mais a placa de desenvolvimento consulte nosso artigo Introdução à Placa ESP32-C6-DevKitC-1: Ideal para IoT
Características do Websocket
- Usa o protocolo WebSocket de comunicação bidirecional
- Ideal para dados de tempo real
- A conexão persistente entre cliente e servidor
- Ideal para tarefas como: ler sensores, enviar e receber dados externos
- Permite que o servidor envie dados para o cliente (diferente do HTTP, onde o cliente sempre inicia a requisição).
Como o Websocket mantém uma conexão aberta e bidirecional entre cliente e servidor, é eficiente para atualizações em tempo real. Ou seja, trabalha de forma assíncrona, permitindo que tanto o cliente quanto o servidor enviem dados a qualquer momento, sem a necessidade de polling.
Materiais Necessários
Para desenvolver nossa aplicação os materiais utilizados foram:
- Placa ESP23-C6 DevKitC-1
- Cabo USB-C
- LED
- Resistor 330 ohms
- Botão
- Jumpers
- Arduino IDE
Para configurar o ambiente e instalar o suporte a ESP32-C6 veja o artigo ESP32-C6 na Prática: Seu Primeiro “Hello World”
Circuito
O circuito utilizado para este artigo será a placa ESP32-C6 DevKitC-1 para gerir o Web Server, o LED para sinalizar as ações do Web Server e o botão para alterar o estado do LED.
Como o ESP32-C6 possui resistores internos de pull-up, não utilizaremos um resistor externo para o botão.
Código
No projeto proposto, o ESP23-C6 DevKitC-1 é conectado à rede local para gerir o Websocket. Assim, é necessário conectar a placa à rede utilizando as credenciais do Wi-Fi.
Também precisamos instalar as bibliotecas ESPAsyncWebServer e AsyncTCP pelo gerenciador de bibliotecas da Arduino IDE por ESP32Async.
Em seguida, copie o endereço IP apresentado no monitor serial (Figura 2) e cole-o no navegador de sua preferência (Figura 3).
Para acompanhar o funcionamento do projeto, abra o monitor serial e verifique as etapas de criação do servidor. Abaixo, você encontrará o endereço IP da placa conectada.
Para modularizar o código e separar responsabilidades, foi criado um arquivo de biblioteca, html_page.h, responsável por separar o código html do código de desenvolvimento da placa.
Todo o código desenvolvido está disponível para consulta em download.
Com a página HTML disponibilizada no IP do navegador. O Websocket se conecta ao servidor (ESP32-C6-DevKit-C) e o servidor retorna as informações para a página.
<script>
let websocket = new WebSocket(`ws://${window.location.hostname}/ws`);
websocket.onopen = () => console.log("Connection established");
websocket.onclose = () => console.log("Connection died");
websocket.onerror = (error) => console.log("error");
websocket.onmessage = (event) => {
console.log("Message received: " + event.data);
atualizarEstado(event.data);
};
function toggleLed(element) {
if (websocket && websocket.readyState === WebSocket.OPEN) {
const comando = element.checked ? "on" : "off";
websocket.send(comando);
console.log("Comando enviado via WebSocket: " + comando);
} else {
console.warn("WebSocket não conectado");
}
}
function atualizarEstado(estado) {
const estadoLED = document.getElementById("estadoLED18");
const iconLED = document.getElementById("iconLED18");
estadoLED.innerText = estado == "on" ? "ON" : "OFF";
iconLED.classList.remove("ledOff", "ledOn");
iconLED.classList.add(estado === "on" ? "ledOn" : "ledOff");
document.getElementById("led18").checked = estado === "on";
}
</script>Conforme o código acima, quando a conexão é aberta, a função websocket.onopen() confirma a conexão.
Quando o botão na interface Web é acionado, a função toggleLed() envia “on” ou “off” via websocket.send().
O servidor ESP32 recebe essa mensagem e responde de volta com o estado atualizado, acionando websocket.onmessage(), que atualiza o HTML.
Abaixo podemos ver a função disparada com recebe a informação de websocket.send(). A partir dela iremos definir o estado do LED e notificar os clientes.
// Função para lidar com eventos do WebSocket
void onWebSocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%lu connected from %s\n", client->id(), client->remoteIP().toString().c_str());
client->text(String(statusLED ? "on" : "off"));
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA: {
String msg = "";
for (size_t i = 0; i < len; i++) {
msg += (char)data[i];
}
Serial.println("Mensagem recebida via WebSocket: " + msg);
if (msg == "on") {
setLED(true);
} else if (msg == "off") {
setLED(false);
}
break;
}
default:
break;
}
}
// Função para definir o estado do LED e notificar os clientes
void setLED(bool state) {
statusLED = state;
digitalWrite(LED_PIN, statusLED ? HIGH : LOW);
notifyClients();
}
// Função para notificar todos os clientes conectados com o estado atual
void notifyClients() {
ws.textAll(statusLED ? "on" : "off");
}
Agora lidamos com o pressionamento do botão e conseguimos notificar os clientes que o estado mudou. Resolvendo o problema que obtivemos com a limitação do Web Server do artigo anterior. Criando um Web Server com ESP32-C6 DevKitC-1: Um Guia Prático
// Função para lidar com o pressionamento do botão
void handleButtonPress() {
statusLED = !statusLED;
setLED(statusLED);
Serial.println("Botão pressionado, LED " + String(statusLED ? "ligado" : "desligado"));
}
void loop() {
btn.update(); // Atualiza o estado do botão
if (btn.wasPressed()) {
handleButtonPress(); // Chama a função para lidar com o pressionamento do botão
}
// Limpa conexões WebSocket desconectadas
ws.cleanupClients();
delay(10); // Pequena pausa para evitar sobrecarga do loop
}
Resultados
Ao inspecionar a página, podemos ver no console do navegador as mensagens disparadas que foram chamadas ao interagir com a página. Além das informações respondidas no monitor serial.

Franzininho WiFi LAB01
Para executarmos o mesmo exemplo na Franzininho WiFi LAB01, vamos aproveitar o sensor de temperatura e umidade (DHT11), LDR e PWM para controlar todas as interfaces disponíveis no código HTML e explorar os benefícios do websocket.

Quer aprender a desenvolver projetos profissionais para ESP32 usando o Arduino? Confira o curso: Domine o ESP32 com Arduino: Da Base aos Projetos Avançados, Um Curso completo de ESP32 com Arduino: programação, conectividade e projetos.
Conclusão
Neste artigo, mostramos como criar um servidor local utilizando a placa ESP32-C6 DevKitC-1 para controlar dispositivos via navegador. A interface HTML foi integrada ao firmware, permitindo comunicação em tempo real com o hardware.
Para leitores que não estão familiarizados com HTML e JavaScript, pode haver certa dificuldade inicial, mas existem diversas ferramentas e recursos online que podem auxiliar nesse processo em HTML Basic Examples
Diferente da abordagem tradicional com Web Server, em que é necessário solicitar o status periodicamente, neste projeto aplicamos WebSocket em conjunto com a biblioteca AsyncWebServer. Com isso, conseguimos atualizações em tempo real sem a necessidade de recarregar a página, melhorando a experiência do usuário e a eficiência da comunicação.
Convidamos você a explorar outros recursos da biblioteca ESPAsyncWebServer, como transmissão de sensores, gráficos em tempo real, controle múltiplo de dispositivos, e a compartilhar seus resultados com a comunidade por meio de artigos, vídeos ou repositórios abertos.
Referências
- HTML Basic Examples
- Introdução à Placa ESP32-C6-DevKitC-1: Ideal para IoT
- ESP32-C6 na Prática: Seu Primeiro “Hello World”
- https://github.com/guilhermefernandesk/ESP32-C6/tree/main/websocket
- https://github.com/FBSeletronica/Programe-o-ESP32-com-Arduino/blob/main/WiFi/WiFi_WebSocket/WiFi_WebSocket.ino
- LED Control (LEDC) – – — Arduino ESP32 latest documentation




