Ambiente Docker para validar a comunicação MQTT. Composto por três containers:
- mosquitto — broker MQTT (Eclipse Mosquitto) que recebe as mensagens.
- subscriber — aplicação Node.js que assina os tópicos e exibe no console (
console.log) tudo que chega. - dashboard — aplicação Node.js (Express + EJS) que renderiza no servidor (SSR) um dashboard de qualidade do ar com a telemetria do ESP32 (MQ135 + PM2.5), classifica se o ar está adequado e atualiza a exibição a cada 30 s via SSE. Exposto em http://localhost:3000.
┌─▶ subscriber ──▶ console.log()
ESP32 ──▶ Mosquitto ──▶┤
└─▶ dashboard ──▶ SSR (HTML) + SSE ──▶ navegador
.
├── docker-compose.yml
├── mosquitto/
│ └── config/
│ └── mosquitto.conf # listener 1883, acesso anônimo (apenas DEV)
├── subscriber/
│ ├── Dockerfile
│ ├── package.json # dependência: mqtt
│ └── index.js # assina os tópicos e faz console.log
├── dashboard/ # dashboard SSR (Express + EJS) — porta 3000
│ ├── Dockerfile
│ ├── package.json # dependências: express, ejs, mqtt
│ ├── server.js # assina MQTT, mantém estado e renderiza (SSR) + SSE
│ ├── views/dashboard.ejs # template renderizado no servidor
│ └── public/ # style.css + app.js (gráfico canvas + cliente SSE)
└── esp32/ # firmware para o simulador Wokwi
├── sketch.ino # conecta no WiFi + MQTT e publica telemetria
├── diagram.json # diagrama do Wokwi (placa ESP32 DevKit C v4)
└── libraries.txt # dependência: PubSubClient
# Sobe os três containers (broker + subscriber + dashboard)
docker compose up --build
# Para ver os logs do subscriber em outra janela
docker compose logs -f subscriberCom o ambiente no ar, abra o dashboard em http://localhost:3000.
Os serviços compartilham a rede Docker mqtt-net. O subscriber e o dashboard
resolvem o broker pelo nome do serviço (mosquitto), definido em
MQTT_BROKER_URL.
Variáveis de ambiente (definidas em docker-compose.yml):
| Variável | Padrão | Descrição |
|---|---|---|
MQTT_BROKER_URL |
mqtt://mosquitto:1883 |
URL do broker |
MQTT_TOPICS |
# |
Tópicos a assinar, separados por vírgula |
MQTT_CLIENT_ID |
node-subscriber |
Identificador do cliente MQTT |
#é um wildcard que assina todos os tópicos. Para tópicos específicos, use por exemploMQTT_TOPICS: "sensores/temperatura,sensores/umidade".
A aplicação em dashboard/ é um servidor Node.js (Express + EJS) que renderiza
o painel no servidor (Server Side Rendering): ao abrir a página, o HTML já chega
pronto com os últimos dados. As novas leituras chegam em tempo real via SSE
(Server-Sent Events), sem recarregar a página. Não há Nginx — o próprio Express
abre a porta 3000.
Fluxo: o servidor assina esp32/telemetria e esp32/status, guarda o último estado
e um histórico recente em memória, e faz broadcast para os navegadores conectados.
| Rota | Descrição |
|---|---|
GET / |
Dashboard renderizado no servidor (cards, gráfico e tabela) |
GET /events |
Stream SSE com as novas leituras (telemetry / status) |
GET /api/state |
Estado atual em JSON (último valor + histórico) |
GET /health |
Healthcheck ({ ok, mqttConnected, clients }) |
Variáveis de ambiente (em docker-compose.yml):
| Variável | Padrão | Descrição |
|---|---|---|
PORT |
3000 |
Porta HTTP do dashboard |
MQTT_BROKER_URL |
mqtt://mosquitto:1883 |
URL do broker |
MQTT_TOPIC_TELEMETRY |
esp32/telemetria |
Tópico da telemetria (JSON) |
MQTT_TOPIC_STATUS |
esp32/status |
Tópico de status (online/offline) |
HISTORY_SIZE |
60 |
Nº de leituras guardadas para o gráfico |
DISPLAY_INTERVAL_MS |
30000 |
Cadência de atualização da exibição (ms) |
A exibição dos dados é atualizada a cada 30 s: a telemetria que chega via SSE fica num buffer e o navegador renderiza os novos valores ao fim de cada ciclo (o status online/offline continua imediato).
O veredito exibido é a pior das duas classificações abaixo:
| Nível | MQ135 (ppm, CO₂-eq) | PM2.5 (µg/m³) |
|---|---|---|
| Adequada | ≤ 800 | ≤ 12 |
| Moderada | 801 – 1200 | 12 – 35 |
| Inadequada | 1201 – 2000 | 35 – 55 |
| Muito inadequada | > 2000 | > 55 |
Com o ambiente no ar, publique uma mensagem de teste. Algumas opções:
1. Usando o próprio container do Mosquitto:
docker compose exec mosquitto mosquitto_pub -h localhost -t "teste/topico" -m "Ola MQTT"2. A partir da máquina host (porta 1883 exposta), com mosquitto-clients instalado:
mosquitto_pub -h localhost -t "teste/topico" -m "Ola MQTT"A mensagem deve aparecer no console do subscriber:
[2026-06-06T12:00:00.000Z] 📨 [teste/topico] Ola MQTT
O firmware em esp32/ (sketch.ino) é um monitor de qualidade do ar:
conecta no WiFi e no broker MQTT e simula por software dois sensores —
MQ135 (gases / CO₂ equivalente, em ppm) e PM2.5 (material particulado
fino, em µg/m³).
Cadências (conforme requisito):
- Leitura do sensor a cada 1 s (atualiza e acumula os valores).
- Envio para a nuvem a cada 30 s, publicando a média das leituras do
período (~30 amostras) em JSON no tópico
esp32/telemetria.
Como o subscriber assina # e o dashboard assina esp32/telemetria, essas
mensagens aparecem automaticamente no console do Node.js e no dashboard.
- Acesse wokwi.com, crie um novo projeto ESP32.
- Cole o conteúdo de
esp32/sketch.inono editor. - Substitua o
diagram.jsonpelo deesp32/diagram.json. - Em Library Manager, adicione
PubSubClient(ou useesp32/libraries.txt). - Ajuste
MQTT_SERVER/MQTT_PORTno topo do sketch (veja abaixo) e dê Play.
O Wokwi roda na nuvem (no navegador) e não enxerga o localhost da sua
máquina. O WiFi do Wokwi é sempre Wokwi-GUEST (sem senha). Para o ESP32
simulado alcançar o seu broker local, escolha uma das opções:
| Opção | Como | MQTT_SERVER / MQTT_PORT |
|---|---|---|
| 1. ngrok (recomendada — mantém o Docker) | Na máquina: ngrok tcp 1883. Copie o host/porta gerados. |
0.tcp.sa.ngrok.io / 17654 (exemplo) |
| 2. Broker público (teste rápido, sem Docker) | Aponte também o subscriber Node ao mesmo broker. | broker.emqx.io / 1883 |
| 3. Wokwi for VS Code + Private IoT Gateway | Dá ao ESP32 acesso à sua rede local. | IP do host / 1883 |
A Opção 1 é a que integra o ESP32 do Wokwi ao ambiente Docker deste repositório sem mudar nada no
docker-compose.yml: ongroktunela a porta1883do Mosquitto local para um endereço público que o Wokwi alcança, e o subscriber continua conectado ao broker local.
| Tópico | Direção | Conteúdo |
|---|---|---|
esp32/telemetria |
ESP32 → broker | JSON: {device, count, mq135, pm25, samples, uptime} |
esp32/status |
ESP32 → broker | online / offline (retido, com Last Will) |
esp32/comando |
broker → ESP32 | Comandos recebidos (exibidos no Serial Monitor) |
mq135em ppm (CO₂ equivalente),pm25em µg/m³ esamples= número de leituras de 1 s que entraram na média daquele envio.
Para enviar um comando ao ESP32 a partir do broker:
docker compose exec mosquitto mosquitto_pub -t "esp32/comando" -m "liga"docker compose down # para os containers
docker compose down -v # para e remove também os volumes (data/log)O broker está configurado com allow_anonymous true (sem usuário/senha) para
simplificar os testes. Não use esta configuração em produção. Para produção,
configure autenticação (password_file), ACLs e, idealmente, TLS.