Laboratório 05 (sem-dht22)
Checklist — DHT22, temporizador e MQTT com Node-RED
-
platformio.inicom DHT, Unified Sensor e PubSubClient;diagram.jsoncom DHT22 no GPIO15 (T1) - Leituras periódicas via
Ticker+ flagvolatile,NaNdescartado (T2) - Conexão Wi-Fi com reconexão no
loop()(T3) - JSON publicado em
elt85b/lab05/grupo-X/dhta cada 5 s, client ID único (T4) - Node-RED:
mqtt in(JSON) →debug, fluxo exportado (T5) - LWT
offline+onlineretidos em.../status, visíveis no Node-RED (T6) - (ESP32 físico sem DHT22)
USAR_DHT22 0, sensor virtual e toque no GPIO4 funcionando - Previsões P1–P4 respondidas no
README.md - Nenhum
push --force; cada tarefa num commitTn:
T1…T6 = 100 pts (esta aula não tem desafios): T1 10 · T2 20 · T3 15 · T4 20 · T5 15 ·
T6 20. O autograder normaliza para 0–10. Vale o commit Tn: mais recente de cada tarefa.
Confira o ambiente (faça a configuração uma vez por máquina; a verificação, a cada aula):
- Instalar as ferramentas — git, GitHub CLI e VS Code
- Configurar o git — nome, e-mail e editor padrão (uma vez)
- Verificar git, gh e VS Code — deve mostrar as versões e
Logged in to github.com
Verificação rápida de versão instalada:
git -v && gh --version && code -v && pio --version && wokwi-cli -V && wsl --version && docker --version
Verificação rápida de autenticação:
git config --get-regexp ^user\. && gh auth status && code --list-extensions --profile "ESP32IO"
Configuração do ambiente de desenvolvimento
- Git SCM
- GitHub CLI
- VS Code
- Wokwi
- PlatformIO
- Drivers
- Docker
O Git é a ferramenta de gerenciamento de código-fonte mais utilizada por desenvolvedores profissionais.
- O Git é um sistema de controle de versão distribuído gratuito e de código aberto, projetado para lidar com tudo, desde projetos pequenos até muito grandes, com rapidez e eficiência.
winget install --id Git.Git -e --source winget
Configurações do git:
git config --list --show-origin
O GitHub CLI traz o GitHub para o seu terminal.
- O GitHub CLI é uma ferramenta de linha de comando que permite interagir com o GitHub diretamente pelo terminal. Está disponível para Windows, macOS e Linux.
winget install --id GitHub.cli -e --source winget
Status de login do GitHub CLI:
gh auth status
Visual Studio Code: IDE e Editor de Código para Desenvolvimento de Software.
- O VS Code é um editor de código-fonte gratuito criado pela Microsoft para Windows, Linux e macOS. Inclui suporte para depuração, controle Git integrado, realce de sintaxe, conclusão inteligente de código, snippets e refatoração de código.
winget install --id Microsoft.VisualStudioCode -e --source winget
Extensões instaladas do Visual Studio Code para o perfil ESP32IO:
code --list-extensions --profile "ESP32IO"
Configurar o terminal do VS Code. No arquivo .vscode/settings.json
{
"terminal.integrated.defaultProfile.windows": "Command Prompt"
}
Wokwi para VSCode: Simulador de sistemas embarcados e IoT com suporte para ESP32.
- Wokwi para VSCode executa a simulação dentro do VS Code, utilizando os binários compilados pelo PlatformIO.
code --install-extension wokwi.wokwi-vscode --profile "ESP32IO"
- Wokwi CLI: Instale via PowerShell.
iwr https://wokwi.com/ci/install.ps1 -useb | iex
wokwi-cli -h
- Obtenha seu token em https://wokwi.com/dashboard/ci
setx WOKWI_CLI_TOKEN "wok_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
PlatformIO IDE para VSCode: Sua porta de entrada para a excelência no desenvolvimento de software embarcado.
- PlatformIO IDE para VSCode Desbloqueie o verdadeiro potencial do desenvolvimento de software embarcado com o ecossistema colaborativo do PlatformIO, adotando princípios declarativos, metodologias orientadas a testes e toolchains modernas para um sucesso incomparável.code --install-extension platformio.platformio-ide --profile "ESP32IO"
Instale a plataforma espressif32:
pio platform install espressif32Você precisa editar a variável de ambiente do sistema chamada Path e adicionar o caminho %USERPROFILE%\.platformio\penv\Scripts\ no início da lista.
Inicie o projeto no PlatformIO:
pio project init -b esp32dev -O "framework=arduino" -O "monitor_speed=115200" --ide vscode --sample-code
- Conecte o ESP32 ao computador via USB.
- Abra o Gerenciador de Dispositivos (clique com o botão direito no Menu Iniciar → Gerenciador de Dispositivos).
- Expanda a seção Portas (COM e LPT).
- Procure por um dispositivo similar a:
- Silicon Labs CP210x USB to UART Bridge (COMx)
- Driver Windows CH340/CH341 USB para porta serial
- FTDI ou “Dispositivo Serial USB (COMx)”
Anote o número da porta (ex: COM4, COM6, COM12). Se não aparecer nenhuma porta nova, o driver não está instalado. Baixe o driver correspondente (CP210x ou CH340) no site do fabricante da placa.
pip install esptool
esptool chip-id
Docker Desktop & WSL 2: O Docker Desktop no Windows 11 utiliza a arquitetura do WSL 2 para executar containers Linux nativamente com alta performance.
Habilitação e Atualização do WSL 2:
wsl --installwsl --update && wsl --set-default-version 2Instalação do Docker Desktop via Winget:
winget install --id Docker.DockerDesktop -eConfirme no terminal integrado do VS Code:
wsl --version && docker --version && docker compose versionTeste rápido com a imagem oficial do Nginx:
docker run --rm -d -p 8080:80 --name teste-nginx nginxAcesse no navegador:http://localhost:8080
Pare o container:
docker stop teste-nginx
Nesta aula o ESP32 vira um nó de telemetria: um temporizador dispara leituras periódicas do DHT22, o firmware publica cada leitura em JSON via MQTT, e o Node-RED assina o tópico e mostra as mensagens no painel debug. No projeto integrador o nó passa a anunciar se está online ou offline usando LWT.
No Lab 06 o mesmo firmware é reaproveitado: o Node-RED passa a gravar as leituras em SQLite e a mudar o intervalo do ESP32 remotamente.
Objetivos
- Ler temperatura e umidade do DHT22 e tratar leituras inválidas (
NaN). - Usar um temporizador (
Ticker) para disparar ações periódicas semdelay()e sem bloquear oloop(). - Conectar o ESP32 ao Wi-Fi e a um broker MQTT, publicando leituras em JSON.
- No Node-RED, assinar o tópico, receber o JSON já convertido em objeto e inspecionar os campos no debug.
- (Integrador) Publicar o status do nó com LWT (Last Will and Testament).
Material
- VS Code + PlatformIO + extensão Wokwi (ESP32 simulado — sem placa física).
- Alternativa: ESP32 físico sem DHT22 — veja ESP32 físico sem DHT22.
- Stack Docker do curso (Mosquitto + Node-RED + MQTT Explorer) — nesta aula usamos o Node-RED e o MQTT Explorer.
- Bibliotecas (baixadas pelo PlatformIO):
adafruit/DHT sensor library,adafruit/Adafruit Unified Sensor,knolleary/PubSubClient. OTickerjá vem com o core Arduino do ESP32.
Conferindo a matriz de simulação: GPIO (o DHT22 usa um único pino digital) e Wi-Fi são ✔️ no ESP32 clássico — então a aula roda inteira no Wokwi. O mesmo firmware funciona numa placa física trocando só SSID/senha e o endereço do broker (veja a aba "Placa física" na T3). Tem o ESP32 mas não tem o DHT22? Veja a alternativa com sensor virtual.
Clonar o repositório do grupo
- A
- B
- C
- D
- E
- F
- G
- H
- I
- J
- K
- L
- M
- P
- N
- Grupo: Grupo-A (slug:
grupo-a) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-a
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-a/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-a
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-a.git && cd lab05-grupo-a
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-B (slug:
grupo-b) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-b
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-b/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-b
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-b.git && cd lab05-grupo-b
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-C (slug:
grupo-c) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-c
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-c/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-c
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-c.git && cd lab05-grupo-c
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-D (slug:
grupo-d) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-d
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-d/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-d
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-d.git && cd lab05-grupo-d
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-E (slug:
grupo-e) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-e
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-e/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-e
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-e.git && cd lab05-grupo-e
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-F (slug:
grupo-f) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-f
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-f/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-f
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-f.git && cd lab05-grupo-f
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-G (slug:
grupo-g) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-g
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-g/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-g
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-g.git && cd lab05-grupo-g
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-H (slug:
grupo-h) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-h
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-h/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-h
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-h.git && cd lab05-grupo-h
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-I (slug:
grupo-i) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-i
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-i/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-i
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-i.git && cd lab05-grupo-i
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-J (slug:
grupo-j) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-j
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-j/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-j
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-j.git && cd lab05-grupo-j
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-K (slug:
grupo-k) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-k
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-k/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-k
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-k.git && cd lab05-grupo-k
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-L (slug:
grupo-l) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-l
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-l/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-l
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-l.git && cd lab05-grupo-l
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-M (slug:
grupo-m) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-m
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-m/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-m
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-m.git && cd lab05-grupo-m
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-P (slug:
grupo-p) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-p
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-p/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-p
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-p.git && cd lab05-grupo-p
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
- Grupo: Grupo-N (slug:
grupo-n) - Repositório: https://github.com/ELT85B-N21-2026-2/lab05-grupo-n
- Commits: https://github.com/ELT85B-N21-2026-2/lab05-grupo-n/commits/main/
- Time: https://github.com/orgs/ELT85B-N21-2026-2/teams/grupo-n
1. Crie e entre na pasta-mãe da disciplina:
mkdir "%USERPROFILE%\ELT85BN21" & cd /d "%USERPROFILE%\ELT85BN21"
2. Clone e entre no repositório do laboratório:
git clone https://github.com/ELT85B-N21-2026-2/lab05-grupo-n.git && cd lab05-grupo-n
3. Verifique status e abra o conteúdo do repositório no perfil ESP32IO do VS Code :
git status && code . --profile "ESP32IO"
Envie o link do repositório do seu grupo no Moodle:
- A
- B
- C
- D
- E
- F
- G
- H
- I
- J
- K
- L
- M
- P
- N
Repositório do Grupo A para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo B para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo C para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo D para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo E para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo F para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo G para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo H para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo I para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo J para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo K para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo L para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo M para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo P para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Repositório do Grupo N para Laboratório 05:
- Copie o link do repositório acima.
- Abra a página de envio da atividade no Moodle (botão abaixo).
- Clique em Adicionar envio.
- Cole o link no campo Texto online.
- Clique em Salvar mudanças.
- Confira se o status mudou para Enviado para avaliação.
Cada cartão Ponto de commit é uma tarefa: faça-a, copie o comando do cartão e rode. A mensagem começa com o código (T1:, T2:…) — é como a correção identifica sua entrega. Um commit por tarefa; pode refazer (vale o mais recente); e não esqueça o git push. Detalhes em Como funciona a avaliação.
Mapa de tarefas — 6 tarefas · 100 pts
- T1 — Dependencias e circuito do DHT22 · 10 pts
- T2 — Leitura do DHT22 com temporizador · 20 pts
- T3 — Conexao Wi-Fi · 15 pts
- T4 — Publicacao MQTT periodica em JSON · 20 pts
- T5 — Node-RED recebendo as leituras no debug · 15 pts
- T6 — Status do no com LWT · 20 pts
O repositório do grupo nasce do lab05-template:
- ├── 🔧platformio.ini👈 Edite Aqui
- ├── 📂src
- └── 📄main.cpp👈 Edite Aqui
- ├── 🔧diagram.json👈 Edite Aqui
- ├── 🔧wokwi.toml👈 Verificar
- ├── 📄.gitignore👈 Verificar
- ├── 📂.vscode
- └── 🔧extensions.json👈 Verificar
- ├── 📂nodered
- └── 🔧flows-lab05.json👈 Criar Aqui
- ├── 📂evidencias
- ├── 📄t2-serial.txt👈 Criar Aqui
- ├── 📄t3-wifi.txt👈 Criar Aqui
- ├── 📄t4-mqtt.txt👈 Criar Aqui
- ├── 📄t5-debug.txt👈 Criar Aqui
- └── 📄t6-status.txt👈 Criar Aqui
- └── 📝README.md👈 Edite Aqui
setup()— o que acontece uma vez: iniciar Serial e DHT, conectar Wi-Fi e MQTT, armar o temporizador.loop()— o comportamento contínuo: manter Wi-Fi/MQTT vivos (mqtt.loop()), e consumir a flag do temporizador (ler + publicar).- callback do temporizador — não é nem um nem outro: roda em outro contexto
(a tarefa do
esp_timer). Por isso ele só fazleituraPendente = truee mais nada.
Parte 1 — Circuito e dependências
1.1 Circuito no Wokwi
O DHT22 do Wokwi tem 4 pinos: VCC, SDA (dados), NC e GND. Ligue VCC → 3V3,
GND → GND e SDA → GPIO15. O template já traz o ESP32; acrescente o sensor no
diagram.json:
{
"version": 1,
"author": "ELT85B - Lab 05",
"editor": "wokwi",
"parts": [
{
"type": "board-esp32-devkit-c-v4",
"id": "esp",
"top": 0,
"left": 0,
"attrs": {}
},
{
"type": "wokwi-dht22",
"id": "dht1",
"top": -76.5,
"left": 157.8,
"attrs": { "temperature": "24.5", "humidity": "55" }
}
],
"connections": [
["esp:TX", "$serialMonitor:RX", "", []],
["esp:RX", "$serialMonitor:TX", "", []],
["dht1:VCC", "esp:3V3", "red", []],
["dht1:GND", "esp:GND.2", "black", []],
["dht1:SDA", "esp:15", "green", []]
],
"dependencies": {}
}
Com o simulador rodando, clique no DHT22: aparecem sliders de temperatura e umidade. É assim que você vai "esquentar" o sensor e ver os números mudarem no Node-RED.
1.2 Bibliotecas no platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
adafruit/DHT sensor library@^1.4.6
adafruit/Adafruit Unified Sensor@^1.1.14
knolleary/PubSubClient@^2.8
O wokwi.toml do template já aponta para .pio/build/esp32dev/firmware.bin e .elf —
por isso o nome do ambiente precisa continuar esp32dev.
Dependencias e circuito do DHT22
git add platformio.ini diagram.json && git commit -m "T1: Dependencias e circuito do DHT22" && git push
Alternativa — ESP32 físico sem DHT22
Para quem vai gravar o firmware num ESP32 de verdade mas não tem o DHT22. Se você só não tem o sensor, também pode simplesmente seguir a aula no Wokwi — lá o DHT22 é virtual.
A ideia é trocar o sensor por um sensor virtual dentro do próprio firmware. O resto da
aula — temporizador, Wi-Fi, MQTT, JSON, Node-RED e LWT — fica idêntico, porque o resto do
código não sabe de onde vêm t e h: ele só chama lerSensor(t, h).
| Wokwi (DHT22) | ESP32 físico sem DHT22 | |
|---|---|---|
| Origem dos dados | DHT22 no GPIO15 | sensor virtual no firmware |
| "Esquentar" o sensor | slider do DHT22 no Wokwi | encostar o dedo no GPIO4 (touch T0) |
| Leituras inválidas | NaN do DHT22 | cerca de 3% de NaN sorteados |
| Executar | Wokwi: Start Simulator | PlatformIO: Upload + Serial Monitor |
| Evidências | copiar do terminal do Wokwi | copiar do Serial Monitor (115200) |
| Wi-Fi | Wokwi-GUEST | rede do laboratório (aba "Placa física" da T3) |
O ESP32 clássico tem temperatureRead(), mas ele usa um sensor não documentado que foi
retirado das revisões mais novas do chip: na maioria das placas a leitura fica parada em
53,3 °C. Não serve para a aula.
Circuito
Nenhum. Opcional: prenda um jumper no GPIO4 e use a ponta metálica como "botão de
toque" maior. Não encoste no pino durante o boot — a referência do toque é medida no setup().
platformio.ini e diagram.json
Faça a T1 igual aos demais grupos: o lib_deps do DHT continua (o código compila nas duas
opções) e o diagram.json continua com o DHT22 — ele só é usado no Wokwi, mas faz parte da T1.
Código da T2
#include <Arduino.h>
#include <Ticker.h>
#include <DHT.h>
// 1 = DHT22 (Wokwi ou placa com sensor) | 0 = ESP32 fisico sem DHT22
#define USAR_DHT22 0
#define DHT_PIN 15
#define DHT_TIPO DHT22
#define TOQUE_PIN T0 // GPIO4: encoste o dedo para "esquentar" o sensor virtual
DHT dht(DHT_PIN, DHT_TIPO);
Ticker temporizador;
volatile bool leituraPendente = false; // setada pelo temporizador
const float INTERVALO_S = 5.0; // DHT22: minimo 2 s entre leituras
uint32_t seq = 0;
#if !USAR_DHT22
float tVirtual = 24.5, hVirtual = 55.0;
uint32_t toqueBase = 0;
#endif
// Roda no contexto do temporizador: NADA de Serial/DHT/MQTT aqui
void aoEstourarTemporizador() {
leituraPendente = true;
}
void iniciarSensor() {
#if USAR_DHT22
dht.begin();
#else
randomSeed(esp_random());
toqueBase = touchRead(TOQUE_PIN); // medido SEM o dedo no pino
Serial.printf("[SIM] sensor virtual, toque base = %lu\n", (unsigned long)toqueBase);
#endif
}
// Preenche t e h; devolve false se a leitura falhou (NaN)
bool lerSensor(float &t, float &h) {
#if USAR_DHT22
t = dht.readTemperature();
h = dht.readHumidity();
#else
bool tocando = touchRead(TOQUE_PIN) < toqueBase * 6 / 10;
float alvoT = tocando ? 34.0f : 24.5f; // dedo no pino = "aquece"
float alvoH = tocando ? 70.0f : 55.0f; // ... e "umedece"
tVirtual += 0.3f * (alvoT - tVirtual) + random(-20, 21) / 100.0f;
hVirtual += 0.3f * (alvoH - hVirtual) + random(-50, 51) / 100.0f;
hVirtual = constrain(hVirtual, 0.0f, 100.0f);
t = tVirtual;
h = hVirtual;
if (random(100) < 3) t = NAN; // ~3% de falhas, como um sensor real
#endif
return !(isnan(t) || isnan(h));
}
void setup() {
Serial.begin(115200);
delay(200);
Serial.println("\n=== Lab 05 - T2: DHT22 + temporizador ===");
iniciarSensor();
temporizador.attach(INTERVALO_S, aoEstourarTemporizador);
}
void loop() {
if (leituraPendente) {
leituraPendente = false;
float t, h;
if (!lerSensor(t, h)) {
Serial.println("[DHT] falha na leitura (NaN) - descartada");
return;
}
seq++;
Serial.printf("[DHT] seq=%lu t=%.1f C h=%.1f %% (%lu ms)\n",
(unsigned long)seq, t, h, (unsigned long)millis());
}
}
#if USAR_DHT22— seleção em tempo de compilação: o pré-processador descarta o ramo não usado, e o mesmo arquivo serve para as duas opções. ComUSAR_DHT22 1o comportamento é idêntico ao da T2 principal.lerSensor()isola a origem dos dados (uma "camada de hardware" mínima): trocar o sensor não mexe no temporizador, no Wi-Fi nem no MQTT.- O sensor virtual se aproxima de um alvo (24,5 °C sem toque, 34 °C com toque) 30% a cada leitura, mais um ruído pequeno — imita a inércia térmica de um sensor real.
- No ESP32 clássico o
touchRead()cai quando você encosta (ex.: ~70 → ~20). A referência é medida nosetup(), e "tocando" é qualquer valor abaixo de 60% dela. touchRead()é chamado noloop()(vialerSensor()), nunca no callback doTicker.
Saída esperada no Serial Monitor (dedo no GPIO4 entre seq=6 e seq=10):
=== Lab 05 - T2: DHT22 + temporizador ===
[SIM] sensor virtual, toque base = 72
[DHT] seq=1 t=24.4 C h=55.2 % (5203 ms)
[DHT] seq=2 t=24.4 C h=55.2 % (10203 ms)
[DHT] seq=3 t=24.5 C h=54.8 % (15203 ms)
[DHT] seq=4 t=24.3 C h=54.6 % (20203 ms)
[DHT] seq=5 t=24.4 C h=54.4 % (25203 ms)
[DHT] seq=6 t=27.2 C h=59.2 % (30203 ms)
[DHT] seq=7 t=29.5 C h=62.7 % (35203 ms)
[DHT] seq=8 t=31.0 C h=64.9 % (40203 ms)
[DHT] falha na leitura (NaN) - descartada
[DHT] seq=9 t=32.3 C h=67.9 % (50203 ms)
[DHT] seq=10 t=29.9 C h=63.7 % (55203 ms)
Os números exatos variam (ruído e valor do toque dependem da placa e do dedo).
Segure o dedo no GPIO4 por três leituras e solte. A temperatura salta para 34 °C de uma
vez, ou sobe aos poucos? Quantas leituras leva para voltar a ~24,5 °C? Relacione com a linha
tVirtual += 0.3f * ....
Da T3 em diante
A partir da T3, use o código principal da aula com quatro mudanças:
-
Copie para o topo os
#defineUSAR_DHT22eTOQUE_PINe as variáveis do bloco#if !USAR_DHT22 ... #endif. -
Copie as funções
iniciarSensor()elerSensor()para antes delerEPublicar(). -
Em
setup(), troquedht.begin();poriniciarSensor();. -
Em
lerEPublicar(), troque as três linhas da leitura por:src/main.cpp (lerEPublicar)float t, h;if (!lerSensor(t, h)) {
E use o SSID/senha do laboratório (aba "Placa física" da T3).
src/main.cpp completo da T4 — ESP32 físico sem DHT22
#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <DHT.h>
#define GRUPO "a" // troque pela letra do seu grupo
// 1 = DHT22 (Wokwi ou placa com sensor) | 0 = ESP32 fisico sem DHT22
#define USAR_DHT22 0
#define DHT_PIN 15
#define DHT_TIPO DHT22
#define TOQUE_PIN T0 // GPIO4: encoste o dedo para "esquentar" o sensor virtual
const char* WIFI_SSID = "IoT-Broker";
const char* WIFI_PASS = "ESP32IoTLab";
// MQTT: broker publico; se a rede bloquear a 1883, use o IP do PC com o Mosquitto da stack
const char *MQTT_HOST = "broker.hivemq.com";
const uint16_t MQTT_PORTA = 1883;
const char *TOPICO_DADOS = "elt85b/lab05/grupo-" GRUPO "/dht";
DHT dht(DHT_PIN, DHT_TIPO);
WiFiClient wifiClient;
PubSubClient mqtt(wifiClient);
Ticker temporizador;
volatile bool leituraPendente = false;
const float INTERVALO_S = 5.0;
uint32_t seq = 0;
char clientId[32];
#if !USAR_DHT22
float tVirtual = 24.5, hVirtual = 55.0;
uint32_t toqueBase = 0;
#endif
void aoEstourarTemporizador() {
leituraPendente = true;
}
void conectarWiFi() {
Serial.printf("[WiFi] conectando a %s", WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_SENHA); // rede real: sem fixar canal
while (WiFi.status() != WL_CONNECTED) {
delay(250);
Serial.print('.');
}
Serial.printf("\n[WiFi] conectado, IP %s\n", WiFi.localIP().toString().c_str());
}
void conectarMQTT() {
while (!mqtt.connected()) {
Serial.printf("[MQTT] conectando a %s como %s ... ", MQTT_HOST, clientId);
if (mqtt.connect(clientId)) {
Serial.println("ok");
} else {
Serial.printf("falhou (rc=%d), nova tentativa em 2 s\n", mqtt.state());
delay(2000);
}
}
}
void iniciarSensor() {
#if USAR_DHT22
dht.begin();
#else
randomSeed(esp_random());
toqueBase = touchRead(TOQUE_PIN); // medido SEM o dedo no pino
Serial.printf("[SIM] sensor virtual, toque base = %lu\n", (unsigned long)toqueBase);
#endif
}
// Preenche t e h; devolve false se a leitura falhou (NaN)
bool lerSensor(float &t, float &h) {
#if USAR_DHT22
t = dht.readTemperature();
h = dht.readHumidity();
#else
bool tocando = touchRead(TOQUE_PIN) < toqueBase * 6 / 10;
float alvoT = tocando ? 34.0f : 24.5f; // dedo no pino = "aquece"
float alvoH = tocando ? 70.0f : 55.0f; // ... e "umedece"
tVirtual += 0.3f * (alvoT - tVirtual) + random(-20, 21) / 100.0f;
hVirtual += 0.3f * (alvoH - hVirtual) + random(-50, 51) / 100.0f;
hVirtual = constrain(hVirtual, 0.0f, 100.0f);
t = tVirtual;
h = hVirtual;
if (random(100) < 3) t = NAN; // ~3% de falhas, como um sensor real
#endif
return !(isnan(t) || isnan(h));
}
void lerEPublicar() {
float t, h;
if (!lerSensor(t, h)) {
Serial.println("[DHT] falha na leitura (NaN) - descartada");
return;
}
seq++;
char payload[128];
snprintf(payload, sizeof(payload),
"{\"grupo\":\"%s\",\"seq\":%lu,\"t\":%.1f,\"h\":%.1f,\"uptime_ms\":%lu}",
GRUPO, (unsigned long)seq, t, h, (unsigned long)millis());
bool ok = mqtt.publish(TOPICO_DADOS, payload);
Serial.printf("[PUB] %s %s -> %s\n", ok ? "ok" : "ERRO", TOPICO_DADOS, payload);
}
void setup() {
Serial.begin(115200);
delay(200);
Serial.println("\n=== Lab 05 - T4: sensor + MQTT ===");
iniciarSensor();
uint64_t mac = ESP.getEfuseMac();
snprintf(clientId, sizeof(clientId), "lab05-%s-%04X", GRUPO, (uint16_t)(mac >> 32));
conectarWiFi();
mqtt.setServer(MQTT_HOST, MQTT_PORTA);
conectarMQTT();
temporizador.attach(INTERVALO_S, aoEstourarTemporizador);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) conectarWiFi();
if (!mqtt.connected()) conectarMQTT();
mqtt.loop();
if (leituraPendente) {
leituraPendente = false;
lerEPublicar();
}
}
O ESP32 físico pode usar o mesmo broker.hivemq.com, desde que a rede libere a porta 1883
de saída. Se o log repetir [MQTT] ... falhou (rc=-2), a conexão não sai: use o Mosquitto
da stack com MQTT_HOST = IP do computador na mesma rede (não localhost — para o
ESP32, localhost é ele mesmo). Nesse caso aponte também o mqtt in do Node-RED e os
comandos mosquitto_sub (-h IP-DO-PC) para esse broker.
LWT na placa física (T6)
Onde a aula diz "pare a simulação", você tem duas formas de derrubar o nó:
- Tirar o cabo USB — a placa some sem fechar o TCP; o broker só percebe pelo keepalive
(1,5 × 15 s ≈ 22 s) e então publica
offline. - Apertar EN/RST — a placa reinicia e reconecta em poucos segundos com o mesmo client ID;
o broker derruba a sessão antiga, e o normal é ver
offlineseguido logo deonline.
Experimente as duas e use a diferença para responder a P4.
Parte 2 — DHT22 com temporizador
2.1 Por que um temporizador?
O jeito ingênuo é ler(); delay(5000);. Funciona até você precisar fazer outra coisa
no loop() — como manter a conexão MQTT viva, que exige chamar mqtt.loop() várias vezes
por segundo. Com delay(5000) o cliente fica 5 s "surdo".
A solução é deixar um temporizador marcar o tempo e o loop() só reagir:
Tickeré o temporizador de software do core ESP32 (baseado noesp_timer, com resolução de microssegundos).attach(segundos, funcao)chamafuncaoperiodicamente.- A flag é
volatile boolporque é escrita num contexto (timer) e lida em outro (loop()):volatileimpede o compilador de "cachear" o valor num registrador. - No ESP32,
boolocupa 1 byte e a escrita é atômica — não precisamos de mutex para uma flag.
O DHT22 faz no máximo uma leitura a cada 2 s. A biblioteca da Adafruit respeita isso: se você pedir antes, ela devolve o último valor em cache.
2.2 Código
#include <Arduino.h>
#include <Ticker.h>
#include <DHT.h>
#define DHT_PIN 15
#define DHT_TIPO DHT22
DHT dht(DHT_PIN, DHT_TIPO);
Ticker temporizador;
volatile bool leituraPendente = false; // setada pelo temporizador
const float INTERVALO_S = 5.0; // DHT22: minimo 2 s entre leituras
uint32_t seq = 0;
// Roda no contexto do temporizador: NADA de Serial/DHT/MQTT aqui
void aoEstourarTemporizador() {
leituraPendente = true;
}
void setup() {
Serial.begin(115200);
delay(200);
Serial.println("\n=== Lab 05 - T2: DHT22 + temporizador ===");
dht.begin();
temporizador.attach(INTERVALO_S, aoEstourarTemporizador);
}
void loop() {
if (leituraPendente) {
leituraPendente = false;
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t) || isnan(h)) {
Serial.println("[DHT] falha na leitura (NaN) - descartada");
return;
}
seq++;
Serial.printf("[DHT] seq=%lu t=%.1f C h=%.1f %% (%lu ms)\n",
(unsigned long)seq, t, h, (unsigned long)millis());
}
}
Compile (PlatformIO: Build) e rode Wokwi: Start Simulator.
Use o código da T2 com sensor virtual e grave na placa (PlatformIO: Upload).
Saída esperada (os ms variam um pouco):
=== Lab 05 - T2: DHT22 + temporizador ===
[DHT] seq=1 t=24.5 C h=55.0 % (5204 ms)
[DHT] seq=2 t=24.5 C h=55.0 % (10204 ms)
[DHT] seq=3 t=24.5 C h=55.0 % (15204 ms)
- P1: troque
INTERVALO_Spara1.0e mude o slider do sensor entre duas leituras. Os valores acompanham o slider a cada linha? Por quê? - P2: e se você colocasse o
Serial.printfdentro deaoEstourarTemporizador()? Pense em quem mais depende da tarefa doesp_timere no tempo que umprintfa 115200 baud leva.
Anote as previsões e o que observou no README.md. Depois volte o intervalo para 5 s.
Salve pelo menos 3 leituras do monitor serial (copie do terminal do Wokwi) em
evidencias/t2-serial.txt, incluindo a linha === Lab 05.
Leitura do DHT22 com temporizador
git add src/main.cpp evidencias/t2-serial.txt && git commit -m "T2: Leitura do DHT22 com temporizador" && git push
Parte 3 — Wi-Fi
Acrescente o Wi-Fi ao programa da T2. No Wokwi a rede é Wokwi-GUEST, sem senha; passar
o canal 6 no begin() pula a varredura e conecta mais rápido.
- Wokwi (padrão)
- Placa física
#include <WiFi.h>
const char *WIFI_SSID = "Wokwi-GUEST";
const char *WIFI_SENHA = "";
void conectarWiFi() {
Serial.printf("[WiFi] conectando a %s", WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_SENHA, 6); // canal 6 acelera no Wokwi
while (WiFi.status() != WL_CONNECTED) {
delay(250);
Serial.print('.');
}
Serial.printf("\n[WiFi] conectado, IP %s\n", WiFi.localIP().toString().c_str());
}
// em setup(), depois de dht.begin():
// conectarWiFi();
// no inicio de loop():
// if (WiFi.status() != WL_CONNECTED) conectarWiFi();
Troque só as constantes (o resto é idêntico). O begin() sem o canal, porque a rede
real pode estar em qualquer canal:
const char *WIFI_SSID = "SSID-DO-LAB";
const char *WIFI_SENHA = "senha-do-lab";
// ...
WiFi.begin(WIFI_SSID, WIFI_SENHA);
Saída esperada:
=== Lab 05 ===
[WiFi] conectando a Wokwi-GUEST.....
[WiFi] conectado, IP 10.13.37.2
[DHT] seq=1 t=24.5 C h=55.0 % (6120 ms)
Enquanto não há Wi-Fi não há o que publicar, então bloquear na (re)conexão é aceitável nesta aula. Em produção você trocaria por uma máquina de estados não bloqueante.
Salve a saída (com a linha [WiFi] conectado) em evidencias/t3-wifi.txt.
Conexao Wi-Fi
git add src/main.cpp evidencias/t3-wifi.txt && git commit -m "T3: Conexao Wi-Fi" && git push
Parte 4 — Publicação MQTT periódica
4.1 Tópico e payload
Cada grupo publica no seu tópico (troque a pela letra do grupo):
| Uso | Tópico | Exemplo de payload |
|---|---|---|
| Leituras | elt85b/lab05/grupo-a/dht | {"grupo":"a","seq":7,"t":24.5,"h":55.0,"uptime_ms":35210} |
| Status (T6) | elt85b/lab05/grupo-a/status | online / offline (retido) |
seqé um contador: se chegaremseq7, 8, 10, a mensagem 9 se perdeu.uptime_ms(demillis()) mostra o instante da leitura do ponto de vista do ESP32.
No Wokwi o ESP32 só alcança a internet, por isso usamos broker.hivemq.com:1883 —
um broker público e sem senha: qualquer pessoa pode ler e publicar nesses tópicos.
Não publique nada sensível. (Broker local no Wokwi exige o IoT Gateway do Wokwi Club.)
4.2 Código completo até aqui
#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <DHT.h>
#define GRUPO "a" // troque pela letra do seu grupo
#define DHT_PIN 15
#define DHT_TIPO DHT22
const char *WIFI_SSID = "Wokwi-GUEST";
const char *WIFI_SENHA = "";
const char *MQTT_HOST = "broker.hivemq.com";
const uint16_t MQTT_PORTA = 1883;
const char *TOPICO_DADOS = "elt85b/lab05/grupo-" GRUPO "/dht";
DHT dht(DHT_PIN, DHT_TIPO);
WiFiClient wifiClient;
PubSubClient mqtt(wifiClient);
Ticker temporizador;
volatile bool leituraPendente = false;
const float INTERVALO_S = 5.0;
uint32_t seq = 0;
char clientId[32];
void aoEstourarTemporizador() {
leituraPendente = true;
}
void conectarWiFi() {
Serial.printf("[WiFi] conectando a %s", WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_SENHA, 6); // canal 6 acelera no Wokwi
while (WiFi.status() != WL_CONNECTED) {
delay(250);
Serial.print('.');
}
Serial.printf("\n[WiFi] conectado, IP %s\n", WiFi.localIP().toString().c_str());
}
void conectarMQTT() {
while (!mqtt.connected()) {
Serial.printf("[MQTT] conectando a %s como %s ... ", MQTT_HOST, clientId);
if (mqtt.connect(clientId)) {
Serial.println("ok");
} else {
Serial.printf("falhou (rc=%d), nova tentativa em 2 s\n", mqtt.state());
delay(2000);
}
}
}
void lerEPublicar() {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t) || isnan(h)) {
Serial.println("[DHT] falha na leitura (NaN) - descartada");
return;
}
seq++;
char payload[128];
snprintf(payload, sizeof(payload),
"{\"grupo\":\"%s\",\"seq\":%lu,\"t\":%.1f,\"h\":%.1f,\"uptime_ms\":%lu}",
GRUPO, (unsigned long)seq, t, h, (unsigned long)millis());
bool ok = mqtt.publish(TOPICO_DADOS, payload);
Serial.printf("[PUB] %s %s -> %s\n", ok ? "ok" : "ERRO", TOPICO_DADOS, payload);
}
void setup() {
Serial.begin(115200);
delay(200);
Serial.println("\n=== Lab 05 - T4: DHT22 + MQTT ===");
dht.begin();
uint64_t mac = ESP.getEfuseMac();
snprintf(clientId, sizeof(clientId), "lab05-%s-%04X", GRUPO, (uint16_t)(mac >> 32));
conectarWiFi();
mqtt.setServer(MQTT_HOST, MQTT_PORTA);
conectarMQTT();
temporizador.attach(INTERVALO_S, aoEstourarTemporizador);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) conectarWiFi();
if (!mqtt.connected()) conectarMQTT();
mqtt.loop();
if (leituraPendente) {
leituraPendente = false;
lerEPublicar();
}
}
Pontos que valem a atenção:
"elt85b/lab05/grupo-" GRUPO "/dht"— literais de string adjacentes são concatenados pelo compilador; comoGRUPOé um#definede string, o tópico é montado em tempo de compilação.- Client ID único: dois clientes com o mesmo ID no mesmo broker se derrubam mutuamente. Por isso o ID leva parte do MAC do chip.
%lu+ cast paraunsigned long: no ESP32uint32_teunsigned longtêm ambos 4 bytes, mas são tipos diferentes para oprintf— o cast deixa o formato correto e sem warnings.- O
PubSubClienttem buffer padrão de 256 bytes (cabeçalho + tópico + payload). Nosso payload tem ~70 bytes; se um dia passar do limite,publish()devolvefalse(e o log mostraERRO) — aí usemqtt.setBufferSize(...).
Aplique as quatro mudanças da alternativa a este código, ou use o arquivo completo da T4 que está lá.
4.3 Verificando no broker
Enquanto a simulação roda, assine o tópico. Use o MQTT Explorer da stack (conexão
broker.hivemq.com, porta 1883) ou, pelo terminal, um mosquitto_sub descartável em Docker:
docker run --rm eclipse-mosquitto:2 mosquitto_sub -h broker.hivemq.com \
-t 'elt85b/lab05/grupo-a/#' -v -C 5 | tee evidencias/t4-mqtt.txt
-C 5 encerra depois de 5 mensagens. Saída esperada:
elt85b/lab05/grupo-a/dht {"grupo":"a","seq":3,"t":24.5,"h":55.0,"uptime_ms":16288}
elt85b/lab05/grupo-a/dht {"grupo":"a","seq":4,"t":24.5,"h":55.0,"uptime_ms":21288}
elt85b/lab05/grupo-a/dht {"grupo":"a","seq":5,"t":31.2,"h":48.0,"uptime_ms":26288}
elt85b/lab05/grupo-a/dht {"grupo":"a","seq":6,"t":31.2,"h":48.0,"uptime_ms":31288}
elt85b/lab05/grupo-a/dht {"grupo":"a","seq":7,"t":31.2,"h":48.0,"uptime_ms":36288}
P3: o que aparece se você assinar elt85b/lab05/+/dht (com + no lugar do grupo)?
E o que aconteceria se dois grupos esquecessem de trocar o GRUPO e ficassem ambos com a?
Publicacao MQTT periodica em JSON
git add src/main.cpp evidencias/t4-mqtt.txt && git commit -m "T4: Publicacao MQTT periodica em JSON" && git push
Parte 5 — Node-RED: receber e visualizar
Suba a stack Docker do curso e abra o Node-RED em http://localhost:1880. Crie uma aba
nova chamada Lab 05 e monte:
- mqtt in "leituras DHT22"
- Server: novo broker
broker.hivemq.com, porta1883(o mesmo em que o ESP32 publica — não o Mosquitto local, que o Wokwi não alcança). - Topic:
elt85b/lab05/grupo-a/dht(seu grupo) · QoS0. - Output: a parsed JSON object — o texto do payload vira um objeto JavaScript.
- Server: novo broker
- debug "payload" → Output:
msg.payload. - debug "temperatura" → Output:
msg.payload.te marque node status (o valor aparece embaixo do nó, no próprio editor). - Deploy. Com o Wokwi rodando, o nó
mqtt indeve mostrar connected (verde) e o painel debug (ícone de inseto, à direita) recebe uma mensagem a cada 5 s.
Saída esperada no painel debug (uma mensagem, expandida):
29/09/2026, 18:40:12 node: payload
elt85b/lab05/grupo-a/dht : msg.payload : Object
▼ object
grupo: "a"
seq: 7
t: 24.5
h: 55
uptime_ms: 36288
Troque temporariamente o Output do mqtt in para a String e faça Deploy: o debug
passa a mostrar o payload entre aspas e o debug "temperatura" exibe undefined. Por quê?
(Volte para a parsed JSON object antes de continuar.)
Evidências:
-
No debug "payload", passe o mouse sobre 3 mensagens → ícone Copy value e cole cada uma numa linha de
evidencias/t5-debug.txt:evidencias/t5-debug.txt{"grupo":"a","seq":7,"t":24.5,"h":55,"uptime_ms":36288}{"grupo":"a","seq":8,"t":24.5,"h":55,"uptime_ms":41288}{"grupo":"a","seq":9,"t":31.2,"h":48,"uptime_ms":46288} -
Selecione a aba Lab 05 → menu (☰) → Export → Current flow → JSON formatado → Download. Salve como
nodered/flows-lab05.json.
Node-RED recebendo as leituras no debug
git add nodered/flows-lab05.json evidencias/t5-debug.txt && git commit -m "T5: Node-RED recebendo as leituras no debug" && git push
Projeto integrador — status do nó com LWT
Quem olha o Node-RED não tem como saber se o ESP32 caiu ou só está entre duas leituras.
O MQTT resolve isso com o LWT (Last Will and Testament): ao conectar, o cliente deixa
com o broker uma mensagem-testamento; se a conexão cair sem um DISCONNECT educado, o
broker publica essa mensagem por ele.
Requisitos
- Firmware
- Novo tópico
elt85b/lab05/grupo-X/status. - Conectar com LWT: mensagem
offline, QoS 1, retida. - Logo após conectar, publicar
onlineretido no mesmo tópico.
- Novo tópico
- Node-RED
- Segundo mqtt in em
.../status(Output: a String) → debug com node status ligado — o nó mostraonline/offlineno editor. - Exporte o fluxo de novo por cima de
nodered/flows-lab05.json.
- Segundo mqtt in em
- Evidência — deixe um
mosquitto_subescutando o status, inicie a simulação, espere oonline, pare a simulação e espere ooffline; aí encerre com Ctrl+C. (Placa física: tire o cabo USB ou aperte EN — veja LWT na placa física.)
docker run --rm eclipse-mosquitto:2 mosquitto_sub -h broker.hivemq.com \
-t 'elt85b/lab05/grupo-a/status' -v | tee evidencias/t6-status.txt
Dicas de API
const char *TOPICO_STATUS = "elt85b/lab05/grupo-" GRUPO "/status";
// connect com LWT: (id, willTopic, willQos, willRetain, willMessage)
if (mqtt.connect(clientId, TOPICO_STATUS, 1, true, "offline")) {
mqtt.publish(TOPICO_STATUS, "online", true); // true = retida
}
Saída esperada:
elt85b/lab05/grupo-a/status offline
elt85b/lab05/grupo-a/status online
elt85b/lab05/grupo-a/status offline
A primeira linha pode ser offline ou online (ou nem aparecer): é a mensagem retida de
uma execução anterior, entregue assim que alguém assina o tópico.
P4: depois de parar a simulação, quanto tempo leva para aparecer offline? Há dois
caminhos: se a conexão TCP é fechada, o broker publica o testamento na hora; se ela só
fica muda (ex.: cabo/Wi-Fi caiu), ele espera 1,5 × keepalive — e o keepalive padrão do
PubSubClient é 15 s. Qual dos dois o Wokwi provocou? E o que muda se o firmware chamasse
mqtt.disconnect() antes de parar?
Status do no com LWT
git add src/main.cpp nodered/flows-lab05.json evidencias/t6-status.txt && git commit -m "T6: Status do no com LWT" && git push
Antes de sair, faça logout para não deixar sua conta do GitHub ativa na máquina (limpa a credencial salva do git e encerra a sessão do gh).