Pular para o conteúdo principal

Aula de Laboratório — Logging no ESP32

Ferramentas: VS Code + PlatformIO + Wokwi Biblioteca: esp32-hal-log.h (camada Arduino do Arduino-ESP32) Duração estimada: 2 h


Objetivos de aprendizagem​

Ao final desta aula você será capaz de:

  • Explicar a diferença entre depurar com Serial.print() e usar um sistema de log com níveis.
  • Configurar o nível de log em tempo de compilação no PlatformIO (CORE_DEBUG_LEVEL).
  • Usar as macros log_e, log_w, log_i, log_d, log_v com formatação estilo printf.
  • Interpretar o formato da saída de log (timestamp, nível, arquivo, linha, função).
  • Simular o firmware no Wokwi diretamente pelo VS Code, sem placa física.

Pré-requisitos e instalação​

  1. VS Code instalado.
  2. Extensão PlatformIO IDE (procure por "PlatformIO IDE" na aba de extensões).
  3. Extensão Wokwi for VS Code (procure por "Wokwi"). Na primeira simulação ela pede um login/licença gratuita — basta seguir o link que aparece.
  4. Conexão com a internet na primeira compilação (o PlatformIO baixa o toolchain do ESP32).
Sem placa física

Tudo nesta aula roda no simulador Wokwi. Você não precisa de um ESP32 real.


Fundamentos: por que usar log em vez de Serial.print()?​

Muita gente depura o ESP32 assim:

Serial.print("valor = ");
Serial.println(valor);

Funciona, mas tem problemas quando o projeto cresce:

  • Não tem níveis. Um erro grave e uma mensagem de curiosidade têm a mesma aparência.
  • Fica no binário para sempre. Você precisa comentar/apagar os print na versão final, e isso é fácil de esquecer.
  • Não diz de onde veio. Em um projeto com 20 arquivos, "valor = 5" não ajuda a localizar a origem.

O sistema de log do Arduino-ESP32 resolve isso. Ele oferece cinco níveis de severidade e cada mensagem sai automaticamente com timestamp, nível, arquivo, linha e função de origem.

Os cinco níveis (do mais grave ao mais verboso)​

MacroNívelValorQuando usar
log_e()Error1Falhas que impedem a operação (sensor não responde).
log_w()Warning2Algo estranho, mas o programa continua (valor fora da faixa).
log_i()Info3Marcos normais de funcionamento ("WiFi conectado").
log_d()Debug4Detalhes úteis durante o desenvolvimento.
log_v()Verbose5Tudo, inclusive laços internos e valores brutos.

O valor 0 (NONE) desliga todos os logs.

A ideia-chave: o nível é decidido na compilação​

Existe uma macro chamada CORE_DEBUG_LEVEL. Cada macro de log só gera código se o seu nível for menor ou igual a CORE_DEBUG_LEVEL. Ou seja:

  • Se você compilar com CORE_DEBUG_LEVEL=3 (Info), então log_d() e log_v() desaparecem do binário — não ocupam memória nem gastam tempo de CPU.
  • Para gerar a versão "de produção", basta recompilar com CORE_DEBUG_LEVEL=1 (só erros) ou 0 (nenhum log). Você não apaga uma linha sequer do código.
A grande vantagem

As mensagens de debug ficam no código-fonte, documentando o programa, mas somem do produto final com uma única troca de configuração.


A API do esp32-hal-log.h​

Formatação estilo printf​

As macros aceitam os mesmos especificadores do printf do C:

int temp = 25;
float tensao = 3.31;
const char* estado = "OK";

log_i("Temperatura: %d C", temp);
log_i("Tensao: %.2f V", tensao);
log_i("Estado do sensor: %s", estado);
log_d("temp=%d tensao=%.2f estado=%s", temp, tensao, estado);

Principais especificadores: %d (inteiro), %u (inteiro sem sinal), %.2f (float com 2 casas), %s (string C), %c (caractere), %x (hexadecimal), %p (ponteiro), %% (o próprio símbolo de porcentagem).

Formato da saída no monitor serial​

Uma chamada como log_i("Sistema iniciado") dentro de setup() produz algo assim:

[ 342][I][main.cpp:15] setup(): Sistema iniciado

Lendo da esquerda para a direita:

  • [ 342] — timestamp em milissegundos desde o boot.
  • [I] — o nível (E, W, I, D ou V).
  • [main.cpp:15] — arquivo e linha exatos de onde a mensagem saiu.
  • setup(): — a função que a chamou.
  • Sistema iniciado — a sua mensagem.

Você não precisa escrever nada disso: o prefixo é montado automaticamente pela macro.

Dump de memória em hexadecimal​

Para inspecionar buffers (ex.: pacotes de rede, leitura de sensor I2C), existem as variantes log_buf_*:

uint8_t pacote[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02};
log_buf_i(pacote, sizeof(pacote));

Isso imprime os bytes formatados em hexadecimal, útil para depurar protocolos.


Montando o projeto no PlatformIO​

Criar o projeto​

  1. Abra o VS Code → ícone do PlatformIO (cabeça de formiga) na barra lateral → PIO Home → New Project.
  2. Preencha:
    • Name: lab-log-esp32
    • Board: Espressif ESP32 Dev Module (ou DOIT ESP32 DEVKIT V1)
    • Framework: Arduino
  3. Clique em Finish e aguarde o download do toolchain.

Configurar o platformio.ini​

Este é o passo mais importante da aula. Abra o platformio.ini na raiz do projeto e deixe-o assim:

platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino

; Velocidade do monitor serial. Precisa bater com o Serial.begin() do codigo.
monitor_speed = 115200

; CORE_DEBUG_LEVEL define ate que nivel de log sera COMPILADO:
; 0 = NONE | 1 = ERROR | 2 = WARN | 3 = INFO | 4 = DEBUG | 5 = VERBOSE
build_flags =
-DCORE_DEBUG_LEVEL=5
Erro nº 1 dos iniciantes

Se você esquecer o -DCORE_DEBUG_LEVEL, o valor padrão costuma ser 0 (NONE) e nada aparece, mesmo com o código correto. Se seus logs sumiram, comece a investigação por aqui.

O código-base (src/main.cpp)​

src/main.cpp
#include <Arduino.h>

void setup() {
Serial.begin(115200);
delay(1000); // da tempo do monitor serial abrir e nao perder as 1as linhas

log_i("===== Laboratorio de Log ESP32 =====");
log_i("Sistema iniciado com sucesso");
}

void loop() {
// veremos o loop nos exercicios
}

Observe que usamos Serial.begin() normalmente. O sistema de log escreve no mesmo periférico serial; o Serial.begin continua sendo o que inicializa a UART e define a velocidade.


Configurando o Wokwi​

O Wokwi simula o ESP32 usando o firmware já compilado pelo PlatformIO. Precisamos de dois arquivos na raiz do projeto.

O "circuito". Para começar, só a placa é suficiente:

diagram.json
{
"version": 1,
"author": "Aluno",
"editor": "wokwi",
"parts": [
{
"type": "board-esp32-devkit-c-v4",
"id": "esp",
"top": 0,
"left": 0,
"attrs": {}
}
],
"connections": [
["esp:TX0", "$serialMonitor:RX", "", []],
["esp:RX0", "$serialMonitor:TX", "", []]
]
}

As duas conexões ligam a UART do ESP32 ao monitor serial do simulador — é o que faz os logs aparecerem na tela do Wokwi.

O fluxo de trabalho​

  1. Compile: ícone do PlatformIO na barra inferior (✓ "Build"), ou Ctrl+Alt+B. Isso gera o firmware.bin/.elf.
  2. Simule: abra a paleta de comandos (Ctrl+Shift+P) → Wokwi: Start Simulator.
  3. Uma aba com a placa e o monitor serial do Wokwi aparece. Seus logs surgem ali.
Regra de ouro

O Wokwi só roda o que já foi compilado. Se você mudar o código, compile de novo antes de reiniciar o simulador, senão vai ver o firmware antigo.


Roteiro de laboratório (prática guiada)​

Exercício 1 — Os cinco níveis de uma vez​

Substitua o setup() por:

src/main.cpp
void setup() {
Serial.begin(115200);
delay(1000);

log_e("Isto e um ERRO (log_e)");
log_w("Isto e um AVISO (log_w)");
log_i("Isto e uma INFO (log_i)");
log_d("Isto e DEBUG (log_d)");
log_v("Isto e VERBOSE (log_v)");
}

Compile com CORE_DEBUG_LEVEL=5 e simule. Anote: você deve ver as cinco linhas, cada uma com seu prefixo de nível.

Exercício 2 — Filtrando por nível de compilação​

Sem mudar o código do Exercício 1, edite o platformio.ini e troque para:

platformio.ini
build_flags =
-DCORE_DEBUG_LEVEL=2

Compile de novo e simule. Observe: agora só aparecem log_e e log_w. As linhas de Info, Debug e Verbose foram removidas do binário na compilação — não é um filtro em tempo de execução, elas literalmente não existem mais no firmware.

Para o relatório

Por que isso é melhor do que um if (nivel <= X) dentro do código?

Exercício 3 — Log com dados formatados​

Volte para CORE_DEBUG_LEVEL=5 e use um loop() que simula a leitura de um sensor:

src/main.cpp
void loop() {
static int contador = 0;
float temperatura = 20.0 + (contador % 15); // valor fake que varia

log_d("Ciclo #%d iniciado", contador);
log_i("Leitura de temperatura: %.1f C", temperatura);

if (temperatura > 30.0) {
log_w("Temperatura alta: %.1f C (limite 30)", temperatura);
}

contador++;
delay(1000);
}

Simule e acompanhe o timestamp crescendo de ~1000 ms em ~1000 ms, e o aviso aparecendo só quando o valor passa de 30.

Exercício 4 — Simulando um erro real​

Vamos fingir que um sensor falhou:

src/main.cpp
bool lerSensor(float* saida) {
static int tentativa = 0;
tentativa++;

if (tentativa % 4 == 0) { // a cada 4 leituras, "falha"
log_e("Falha ao ler sensor na tentativa %d", tentativa);
return false;
}

*saida = 25.5;
log_v("Sensor respondeu OK na tentativa %d", tentativa);
return true;
}

void loop() {
float t;
if (lerSensor(&t)) {
log_i("Temperatura valida: %.1f C", t);
} else {
log_w("Usando ultimo valor conhecido (leitura ignorada)");
}
delay(1000);
}

Objetivo pedagógico: perceber como os níveis contam uma história — o log_e marca a falha exata (com número da tentativa e linha do arquivo), o log_w mostra a recuperação, e o log_v só aparece se você quiser o detalhe fino.


Exercícios propostos (para entregar)​

  1. Contador de erros. Modifique o Exercício 4 para contar quantas falhas ocorreram e, a cada 10 ciclos, emitir um log_i com a taxa de falhas em porcentagem (%.1f%%).
  2. Nível de produção. Compile o projeto com CORE_DEBUG_LEVEL=1 e descreva no relatório o que muda na saída. Explique por que essa seria a configuração para um produto entregue ao cliente.
  3. Hexdump. Crie um uint8_t buffer[8] preenchido com valores à sua escolha e imprima-o com log_buf_i(). Cole a saída no relatório.
  4. Desafio. Ligue um LED no diagrama do Wokwi (GPIO 2) e faça-o piscar, emitindo um log_d a cada troca de estado. Anexe o diagram.json modificado.

Referência rápida​

MacroAparece quando CORE_DEBUG_LEVEL ≥Uso típico
log_e("...", ...)1Erro
log_w("...", ...)2Aviso
log_i("...", ...)3Informação
log_d("...", ...)4Debug
log_v("...", ...)5Verbose
log_buf_i(buf, tam)3Dump hexadecimal

Em platformio.ini: build_flags = -DCORE_DEBUG_LEVEL=<0..5>


Solução de problemas (troubleshooting)​

SintomaCausa provávelSolução
Nenhum log apareceCORE_DEBUG_LEVEL não definido ou 0Adicione -DCORE_DEBUG_LEVEL=5 em build_flags e recompile
Só aparecem erros e avisosNível de compilação baixo (1 ou 2)Suba o CORE_DEBUG_LEVEL
Caracteres estranhosVelocidade erradamonitor_speed deve bater com Serial.begin() (115200)
As primeiras linhas somemMonitor abriu depois do bootAdicione delay(1000) após Serial.begin()
Wokwi mostra código antigoSimulou sem recompilarFaça Build antes de Start Simulator
Wokwi não acha o firmwareCaminho errado no wokwi.tomlConfira o nome do env em .pio/build/<env>/
log_i "não existe"Faltou #include <Arduino.h>O header de log já vem junto do core Arduino; garanta o include

Apêndice — Relação com o ESP-IDF​

O esp32-hal-log.h é a camada Arduino. Por baixo, ele usa o sistema de log do ESP-IDF, cujas macros exigem uma TAG (um texto que identifica o módulo).

// Sem TAG — mais simples
log_i("Leitura = %.1f", valor);

Para esta aula ficamos na camada Arduino (log_i e amigas), que é mais simples e não exige TAG. Quando você migrar para projetos ESP-IDF puros, a lógica de níveis e o CORE_DEBUG_LEVEL continuam valendo — muda só a forma de escrever a macro.