← Mundo bit Byte

Sistemas Embarcados e IoT

Professor Ronaldo Lavestein
1. Fundamentos 2. Entrada/Saída 3. Sensores 4. Atuadores/Automação 5. Programação Aplicada 6. Conectividade 7. Internet das Coisas 8. RTOS e Protocolos 9. Proteção e Segurança 10. Projeto IoT 99. Exercícios
10

Projeto IoT — Ambiente Inteligente MbB

Chegou a hora de juntar o percurso. O sistema vai perceber a luminosidade do ambiente, decidir quando a iluminação deve ser acionada, permitir controle pela rede e apresentar o estado em uma aplicação Web. O objetivo não é adicionar tecnologias por quantidade, mas integrar corretamente o que já foi aprendido.

Sensor
→
ESP32
→
Decisão
→
Atuador
→
Rede
→
Aplicação
EntenderComeçar por um problema e transformar a necessidade em requisitos observáveis.
Experimentar e programarValidar sensor e atuador antes de adicionar Wi-Fi e aplicação.
AplicarIntegrar controle, monitoramento, segurança, testes e documentação.

Como executar o projeto

O núcleo é o mesmo, mas a forma de testar a página Web muda conforme o ambiente.

AmbienteSensor e LEDWi-FiPágina Web
ESP32 física✓ Completo✓ Rede 2,4 GHz compatível✓ Completo na mesma rede local
Wokwi com gateway público✓ Completo, usando o módulo de fotoresistor✓ Wokwi-GUEST△ O servidor executa, mas o navegador não consegue iniciar uma conexão de entrada
Wokwi com Private IoT Gateway✓ Completo✓ Wokwi-GUEST✓ Completo em http://localhost:9080/
10.1

Problema e requisitos — O que o sistema precisa resolver?

Um projeto começa pela necessidade, não pelo componente.

Agora tudo precisa ter um motivo. Não vamos adicionar LDR, Wi-Fi e página Web só porque já estudamos essas tecnologias. O problema é reduzir iluminação desnecessária e, ao mesmo tempo, permitir acompanhamento e controle local. Cada parte do projeto deve responder a essa necessidade.

1. Situação

Em uma sala pequena, a iluminação pode permanecer acesa mesmo quando há claridade suficiente. Também pode ser útil acompanhar o nível de luz e, quando necessário, assumir o controle manual pelo celular ou notebook conectado à mesma rede.

2. Entrada

Um LDR percebe a luminosidade e gera um valor analógico para o ESP32.

3. Saída

Um LED representa a lâmpada do projeto. Não usaremos rede elétrica nesta atividade.

4. Automação

No modo automático, o ESP32 decide o estado da iluminação a partir da leitura do LDR e de um limiar calibrado.

5. Aplicação

Uma página Web mostra a leitura, o modo e o estado da iluminação e permite escolher Ligar, Desligar ou Automático.

6. Critérios de sucesso

MonitorarA leitura de luminosidade aparece no Monitor Serial e na página.
ControlarO usuário consegue ligar e desligar o LED pela rede local.
AutomatizarNo modo automático, a iluminação responde à condição de claridade.
ExplicarVocê consegue descrever o caminho sensor → processamento → rede → aplicação → atuador.

7. Estratégia de execução

Primeiro faremos cada parte funcionar sozinha. Só depois integraremos tudo. Se sensor, LED e rede forem testados ao mesmo tempo, fica mais difícil descobrir onde está um erro.

10.2

Arquitetura e montagem — Antes do código, desenhe o caminho

A arquitetura mostra o papel de cada parte do sistema.

Antes de integrar, separe as responsabilidades. O LDR mede, o ESP32 decide, o LED representa a iluminação e a página Web permite observar e comandar. Quando cada parte tem um papel claro, fica muito mais fácil descobrir onde está um erro.

Placa deste projeto: continue usando a ESP32 DevKit baseada no ESP32 original / ESP32-WROOM-32 adotada desde o módulo 6. No Wokwi, escolha ESP32 DevKit v1. GPIO 34 e as observações de ADC desta etapa se referem a essa família.

Circuito físico do projeto integrador

Diagrama do projeto físico: divisor de tensão com LDR no GPIO 34 e LED com resistor no GPIO 23, com GND comum.
Na montagem física, o LDR e o resistor de 10 kΩ formam o divisor ligado ao GPIO 34. O LED e o resistor de 220 Ω ficam em série entre GPIO 23 e GND.

1. Visão do sistema

LDR→GPIO 34→ESP32→Wi-Fi→Página Web↔Comando→GPIO 23 + LED

2. Componentes do núcleo

ComponenteFunçãoLigação-base
ESP32Processamento, Wi-Fi e servidor HTTP.Placa central do projeto.
LDRPerceber a luminosidade.Divisor de tensão ligado ao GPIO 34.
Resistor 10 kΩCompletar o divisor de tensão do LDR.Entre o ponto de leitura e GND.
LED + resistor 220 ΩRepresentar a iluminação.GPIO 23 → resistor → LED → GND.

3. Divisor do LDR

3,3 V→LDR→ponto de leitura / GPIO 34→10 kΩ→GND

Com essa orientação, a leitura tende a aumentar com mais luz e diminuir no escuro. O valor exato depende do LDR, do resistor e do ambiente; por isso o limiar será calibrado, não tratado como número universal.

Segurança elétrica: este projeto trabalha somente com baixa tensão do ESP32. O LED representa uma lâmpada. Não conecte relé, tomada ou rede elétrica de 127/220 V nesta atividade.

4. Por que GPIO 34?

No ESP32 clássico, o GPIO 34 é uma entrada do ADC1 e é somente entrada. Isso combina com o LDR e traz outra vantagem importante: os canais ADC2 possuem restrições quando o Wi-Fi está em uso, enquanto o ADC1 evita esse conflito neste projeto.

5. Por que manter GPIO 23?

É o mesmo pino do LED usado no percurso com ESP32. Reutilizar a montagem reduz mudanças desnecessárias e facilita a comparação com os blocos anteriores.

6. Montagem equivalente no Wokwi

Abra um projeto ESP32 DevKit v1 no Wokwi. O simulador não precisa reproduzir o divisor com componentes passivos discretos: use o componente Photoresistor (LDR) Sensor, que já possui LDR e resistor interno.

Pino do sensor WokwiESP32
VCC3V3
GNDGND
AOGPIO 34

O circuito do LED permanece o mesmo. No simulador, altere o controle de luminosidade do fotoresistor para produzir leituras claras e escuras.

Uma diferença importante: no divisor físico desenhado acima, a leitura tende a aumentar com mais luz. No módulo de fotoresistor do Wokwi, a leitura tende a aumentar no escuro. O código abaixo possui uma configuração explícita para lidar com essa diferença sem esconder o que está acontecendo.

7. Próximo passo

Antes de Wi-Fi, navegador ou página Web, precisamos responder algo mais simples: o ESP32 consegue medir a luz e controlar o LED corretamente?

10.3

Teste local — Sensor e atuador primeiro

Uma etapa pequena produz evidência antes da integração.

Se a automação local não funciona, a rede só esconde o problema. Nesta etapa você prova duas coisas sem Wi-Fi: a leitura muda quando a luz muda e o LED responde ao critério escolhido.

1. Primeiro teste

Carregue o código abaixo e altere a iluminação sobre o sensor. Na ESP32 física, abra o Monitor Serial em 115200; no Wokwi, o Monitor Serial acompanha automaticamente a velocidade configurada pelo programa. Observe primeiro uma leitura claramente iluminada e outra claramente escura. Depois escolha LIMIAR entre esses dois valores.

Montagem física do diagrama: mantenha LEITURA_MAIOR_NO_ESCURO = false. Wokwi com Photoresistor Sensor: use LEITURA_MAIOR_NO_ESCURO = true. Assim, o restante da lógica permanece igual nos dois ambientes.

Código completo — teste local

const int LDR = 34;
const int LED = 23;
const int LIMIAR = 2000; // ajuste depois de observar claro e escuro

// Física do diagrama: false
// Wokwi Photoresistor Sensor: true
const bool LEITURA_MAIOR_NO_ESCURO = false;

bool ambienteEscuro(int leitura) {
  if (LEITURA_MAIOR_NO_ESCURO) {
    return leitura > LIMIAR;
  }

  return leitura < LIMIAR;
}

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
}

void loop() {
  int luminosidade = analogRead(LDR);
  bool escuro = ambienteEscuro(luminosidade);

  digitalWrite(LED, escuro ? HIGH : LOW);

  Serial.print("Luminosidade: ");
  Serial.print(luminosidade);
  Serial.print(" | Ambiente: ");
  Serial.println(escuro ? "escuro" : "claro");

  delay(500);
}

2. Evidência esperada

Ao mudar a luminosidade, a leitura deve variar de forma perceptível. Quando o código classificar o ambiente como escuro, o LED deve acender; quando classificar como claro, deve apagar.

3. Se o comportamento estiver invertido

Primeiro confira LEITURA_MAIOR_NO_ESCURO. Na montagem física do diagrama ela deve ser false; no sensor do Wokwi, true. Se a montagem física estiver diferente do diagrama, observe as leituras e ajuste conscientemente essa configuração.

Checkpoint: não avance enquanto não houver duas evidências simples: o valor do sensor muda com a luz e o LED responde ao limiar. Só então a rede entra no projeto.

4. Próxima necessidade

Localmente o sistema já percebe e age. Agora queremos ver o estado e controlar o modo a partir de outro dispositivo da rede.

10.4

Aplicação Web — Monitorar e comandar pela rede local

O navegador deixa de ser apenas teste de HTTP e passa a ser a interface do projeto.

Agora a conectividade ganha uma finalidade. O navegador não serve apenas para provar que HTTP funciona: ele vira a interface pela qual uma pessoa consulta a luminosidade, vê o estado da iluminação e escolhe entre controle manual e automático.

1. O que já sabemos

No Bloco 6, o ESP32 entrou no Wi-Fi e funcionou como servidor HTTP. Aqui reutilizamos esse conhecimento com uma finalidade maior: a página mostra luminosidade, estado da iluminação e modo de operação.

2. Cliente

Celular ou notebook abre a página e envia comandos.

3. Servidor

O ESP32 recebe as requisições, monta a página e altera o estado do projeto.

4. Rotas que a aplicação terá

RotaAção
/Mostra o painel atual.
/ligarSeleciona modo manual e liga o LED.
/desligarSeleciona modo manual e desliga o LED.
/autoAtiva a decisão automática pelo LDR.

5. Rede local primeiro

Na ESP32 física, celular/notebook e placa devem estar em uma rede que permita comunicação entre os dispositivos. Não precisamos expor o protótipo à Internet para provar a integração.

6. E no Wokwi?

AmbienteComo testar
Gateway públicoUse Wokwi-GUEST e senha vazia. Sensor, LED, automação e conexão Wi-Fi funcionam, mas o navegador não consegue entrar no servidor HTTP simulado.
Private IoT GatewayEm conta compatível com esse recurso, use Wokwi-GUEST, ative o gateway privado e abra http://localhost:9080/ no Chrome, Firefox ou Edge.

Não confunda limitação do simulador com erro no código. Se o gateway público estiver sendo usado, não conseguir abrir a página é o comportamento esperado.

7. Agora sim: integrar

Sensor, decisão, atuador e HTTP já foram estudados. A próxima etapa junta essas partes em um único programa cumulativo.

10.5

Integração final — Ambiente Inteligente MbB funcionando como sistema

O código final não introduz outra tecnologia: ele integra peças já compreendidas.

A integração é onde aparecem conflitos reais. O modo manual precisa parar de obedecer ao sensor; o modo automático precisa retomar a decisão pelo LDR; e uma falha de Wi-Fi não deve impedir a automação local. O programa final organiza exatamente essas responsabilidades.

1. Antes de carregar

ESP32 física: troque NOME_DA_REDE e SENHA_DA_REDE pela rede de laboratório e mantenha LEITURA_MAIOR_NO_ESCURO = false para a montagem do diagrama. Wokwi: use Wokwi-GUEST, senha vazia e LEITURA_MAIOR_NO_ESCURO = true. Nos dois casos, ajuste LIMIAR com base nas leituras obtidas no teste local.

Código completo — projeto integrado

#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "NOME_DA_REDE";
const char* senha = "SENHA_DA_REDE";

const int LDR = 34;
const int LED = 23;
const int LIMIAR = 2000; // calibre no teste local

// Física do diagrama: false
// Wokwi Photoresistor Sensor: true
const bool LEITURA_MAIOR_NO_ESCURO = false;

const unsigned long TEMPO_MAX_WIFI = 10000;

WebServer servidor(80);

enum Modo { MANUAL, AUTOMATICO };
Modo modo = AUTOMATICO;
bool ledLigado = false;
bool servidorDisponivel = false;

bool ambienteEscuro(int leitura) {
  if (LEITURA_MAIOR_NO_ESCURO) {
    return leitura > LIMIAR;
  }

  return leitura < LIMIAR;
}

void definirLed(bool estado) {
  ledLigado = estado;
  digitalWrite(LED, estado ? HIGH : LOW);
}

void atualizarAutomacao() {
  if (modo != AUTOMATICO) return;

  int luminosidade = analogRead(LDR);
  definirLed(ambienteEscuro(luminosidade));
}

String montarPagina() {
  int luminosidade = analogRead(LDR);

  String pagina = "<!DOCTYPE html><html><head>";
  pagina += "<meta charset='utf-8'>";
  pagina += "<meta name='viewport' content='width=device-width,initial-scale=1'>";
  pagina += "<meta http-equiv='refresh' content='2'>";
  pagina += "<title>Ambiente MbB</title>";
  pagina += "<style>body{font-family:Arial;max-width:520px;margin:30px auto;padding:16px}";
  pagina += "a{display:inline-block;margin:6px;padding:12px 16px;background:#07515f;color:white;text-decoration:none;border-radius:8px}";
  pagina += ".painel{padding:16px;border:1px solid #ccc;border-radius:12px}</style>";
  pagina += "</head><body><div class='painel'>";
  pagina += "<h1>Ambiente MbB</h1>";
  pagina += "<p>Luminosidade: " + String(luminosidade) + "</p>";
  pagina += "<p>Iluminacao: " + String(ledLigado ? "LIGADA" : "DESLIGADA") + "</p>";
  pagina += "<p>Modo: " + String(modo == AUTOMATICO ? "AUTOMATICO" : "MANUAL") + "</p>";
  pagina += "<a href='/ligar'>Ligar</a>";
  pagina += "<a href='/desligar'>Desligar</a>";
  pagina += "<a href='/auto'>Automatico</a>";
  pagina += "</div></body></html>";

  return pagina;
}

void voltarParaInicio() {
  servidor.sendHeader("Location", "/");
  servidor.send(303, "text/plain", "");
}

void configurarServidor() {
  servidor.on("/", []() {
    servidor.send(200, "text/html", montarPagina());
  });

  servidor.on("/ligar", []() {
    modo = MANUAL;
    definirLed(true);
    voltarParaInicio();
  });

  servidor.on("/desligar", []() {
    modo = MANUAL;
    definirLed(false);
    voltarParaInicio();
  });

  servidor.on("/auto", []() {
    modo = AUTOMATICO;
    atualizarAutomacao();
    voltarParaInicio();
  });
}

void conectarWiFiSemBloquearParaSempre() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, senha);

  Serial.print("Conectando ao Wi-Fi");
  unsigned long inicio = millis();

  while (WiFi.status() != WL_CONNECTED &&
         millis() - inicio < TEMPO_MAX_WIFI) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();

  if (WiFi.status() == WL_CONNECTED) {
    servidor.begin();
    servidorDisponivel = true;
    Serial.print("Abra no navegador: http://");
    Serial.println(WiFi.localIP());
  } else {
    servidorDisponivel = false;
    Serial.println("Wi-Fi indisponivel.");
    Serial.println("A automacao local continuara funcionando.");
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
  definirLed(false);

  configurarServidor();
  conectarWiFiSemBloquearParaSempre();
}

void loop() {
  if (servidorDisponivel && WiFi.status() == WL_CONNECTED) {
    servidor.handleClient();
  }

  atualizarAutomacao();
  delay(20);
}

2. Teste manual

ESP32 física: abra o IP mostrado no Monitor Serial a partir de um dispositivo da mesma rede. Wokwi com Private IoT Gateway: abra http://localhost:9080/. Use Ligar e Desligar; o modo deve mudar para MANUAL e o LED deve obedecer ao comando. No gateway público do Wokwi, esta prova pelo navegador não está disponível.

3. Teste automático

Escolha Automático e altere a luminosidade. A página deve atualizar a leitura e o LED deve apagar em condição clara e acender em condição escura, de acordo com o limiar calibrado e com a direção de leitura configurada para o seu ambiente.

4. Falha de rede não deve congelar a automação

O programa espera a conexão Wi-Fi por no máximo 10 segundos. Se a rede estiver indisponível, a página Web não inicia, mas o ESP32 continua lendo o sensor e controlando o LED no modo automático.

Se a placa iniciar sem rede e a rede aparecer depois, reinicie o protótipo nesta versão do projeto para abrir o servidor. O ponto principal é separar uma função local de uma função de conectividade.

Checkpoint da integração: retire a rede ou use credenciais inválidas e confirme que, depois da tentativa de conexão, a variação de luz ainda controla o LED no modo automático.

5. O que foi integrado

SensoriamentoLDR mede uma condição física.
ProcessamentoESP32 lê, compara e decide.
AtuaçãoLED representa a iluminação controlada.
ConectividadeESP32 participa da rede Wi-Fi.
AplicaçãoNavegador monitora e envia comandos HTTP.
IntegraçãoManual e automático convivem no mesmo sistema.

6. O que não entrou só para aumentar o projeto

RTOS, CAN, RS-232, BLE e LCD I2C foram estudados porque são importantes no percurso, mas não precisam aparecer obrigatoriamente no projeto final. Uma integração boa usa apenas o que resolve o problema. O LCD I2C pode ser acrescentado depois como extensão local, após validar eletricamente o módulo disponível.

10.6

Segurança e dados — Revisar antes de chamar o projeto de concluído

O Bloco 9 agora deixa de ser teoria e vira critério de projeto.

Funcionar não basta. Antes da entrega, vamos perguntar o que está exposto, quais dados existem, onde estão as credenciais e quem consegue comandar o sistema. O objetivo é reconhecer os limites do protótipo, sem tratar um servidor de laboratório como produto pronto para uso real.

1. Quais dados existem?

O núcleo do Ambiente MbB trabalha com valor de luminosidade, modo de operação e estado do LED. Ele não precisa de nome, localização de pessoa, biometria ou histórico de usuários para cumprir sua finalidade.

2. Necessidade

Não crie cadastro de pessoas ou logs pessoais se eles não forem necessários para o objetivo do projeto.

3. Credenciais

A senha do Wi-Fi é usada no código apenas como simplificação de laboratório. Não publique o arquivo com uma senha real nem mostre a credencial em capturas de tela.

4. Exposição

Para o projeto-base, mantenha o servidor na rede local. Um túnel público só deve ser usado quando houver uma necessidade definida e controles compatíveis com a exposição.

5. Autenticação e autorização

O servidor deste protótipo não implementa login nem permissões. Portanto, qualquer dispositivo que consiga alcançar o ESP32 pode tentar acessar as rotas. HTTPS/TLS protegeria o transporte, mas ainda seria necessário decidir quem pode comandar o sistema.

Limite do protótipo: este código é adequado para aprendizagem em rede controlada. Ele não deve ser tratado como solução pronta para controlar fechaduras, portões, equipamentos críticos ou cargas elétricas reais.

6. Registro de decisão

Antes da entrega, complete esta frase no relatório: “O projeto coleta apenas __________ porque sua finalidade é __________. Ele fica acessível somente __________. A principal limitação de segurança é __________.”

7. Última etapa

Um projeto não termina quando “funciona uma vez”. Precisamos de testes reproduzíveis e evidências de que cada requisito foi atendido.

10.7

Testes e entrega — Provar que o sistema funciona

A entrega final é pequena, objetiva e baseada em evidências.

Um projeto não está pronto porque funcionou uma vez. Agora cada requisito precisa produzir uma evidência repetível: sensor, modo manual, modo automático, rede e comportamento quando a conectividade falha.

1. Roteiro de testes

TesteAçãoResultado esperado
T1 — SensorAlterar a luz sobre o LDR.Leitura muda de forma perceptível.
T2 — Manual ligarAbrir /ligar pelo painel.Modo MANUAL e LED ligado.
T3 — Manual desligarAbrir /desligar.Modo MANUAL e LED desligado.
T4 — Automático claroAtivar Automático e aumentar a luminosidade.O sistema classifica a condição como clara e o LED fica apagado.
T5 — Automático escuroReduzir a luz sobre o LDR.Ao cruzar o limiar, o LED acende.
T6 — RedeNa placa física, acessar o IP por outro dispositivo da mesma rede. No Wokwi com Private Gateway, abrir http://localhost:9080/.Painel abre e os comandos chegam ao ESP32.
T7 — Falha de redeCom o modo automático ativo, interromper a rede e variar a luminosidade.A página fica indisponível, mas a decisão local sobre o LED continua funcionando.

2. Entrega mínima

1

Diagrama: mostrar sensor, ESP32, rede, aplicação e atuador.

2

Código: entregar a versão final sem expor senha real de Wi-Fi.

3

Evidência: registrar o painel funcionando e pelo menos quatro testes da tabela, incluindo o T7 de falha de rede.

4

Explicação: descrever em poucas linhas o que é automático, o que é comandado pelo usuário e como os dados percorrem o sistema.

5

Segurança: registrar a decisão de dados e a principal limitação do protótipo.

6

Ambiente de execução: registrar se a camada Web foi validada na ESP32 física ou no Wokwi com Private IoT Gateway. O gateway público do Wokwi não permite comprovar conexões de entrada no servidor.

3. Extensões opcionais — Só depois do núcleo

Quem concluir o projeto-base pode escolher uma evolução que tenha propósito: exibir estado em LCD I2C, acrescentar outro sensor, representar uma abertura com servo ou reorganizar tarefas com RTOS. A extensão deve responder a uma necessidade clara e ser testada separadamente antes de entrar no sistema.

4. Fechamento do percurso

Ao concluir este projeto, você não apenas “montou um circuito”. Você passou por entrada e saída, sensores, atuadores, programação, conectividade, IoT, protocolos, proteção e segurança e usou esse conhecimento para construir e justificar um sistema integrado.

Entender→Experimentar→Programar→Aplicar
Projeto-base concluído: o núcleo cobre monitoramento e controle de iluminação com sistema embarcado integrado a uma aplicação em rede. Se houver tempo para evoluir, escolha uma extensão com finalidade clara, como um servo representando uma abertura ou um LCD exibindo o estado localmente.