Capítulo 9 — Análise do código completo do projeto

A seguir está o código completo do projeto utilizado neste ebook, exatamente como pode ser compilado para o ESP32. Ele está amplamente comentado para facilitar a compreensão linha a linha.


  #include <WiFi.h> // Inclui biblioteca WiFi.h

  
  // Dados para conexão Wi-Fi

  // Define uma variável constante do tipo const char* chamada ssid, que armazena o nome da rede Wi-Fi 
  //à qual o dispositivo deve se conectar. Neste caso, o nome da rede é "Emanuelly".
  const char* ssid = "seu usuario na rede wifi"; 

  //Define outra variável constante chamada password, que armazena a senha da rede Wi-Fi. Neste exemplo, a senha é "45231709"
  const char* password = "Senha da rede wifi"; // Inserir senha da rede
  
  /*WiFiServer: Este é um objeto da classe WiFiServer, que é responsável por criar um servidor que escuta conexões na rede Wi-Fi. 
  Essa classe é parte da biblioteca WiFi do Arduino.
  server: Este é o nome do objeto que você está criando. Você pode usar esse nome para referenciar o servidor em outras partes do seu código.
  (80): Este número especifica a porta na qual o servidor irá escutar por conexões de entrada. A porta 80 é a porta padrão para HTTP, 
  o que significa que este servidor será capaz de lidar com requisições web.*/
  WiFiServer server(80);
  
  // Dados para definição de IP Fixo

  //Esta linha define um endereço IP local para um dispositivo. O endereço IP 192.168.1.196 será atribuído ao dispositivo na rede local. 
  //Este endereço é típico para redes privadas.
  IPAddress local_IP(192, 168, 1, 196); 

  /*Aqui, é definido o endereço do gateway (roteador) da rede. O gateway 192.168.1.1 é comumente o endereço do roteador em 
  muitas configurações de redes locais.
  O gateway é utilizado para que o dispositivo possa se comunicar com redes externas (como a Internet).*/
  IPAddress gateway(192, 168, 1, 1);  

  //Esta linha define a máscara de sub-rede, que neste caso é 255.255.255.0. A máscara de sub-rede é usada para determinar 
  //quais endereços IP estão na mesma rede local e quais devem ser encaminhados para o gateway.  
  IPAddress subnet(255, 255, 255, 0);   

  //Esta linha cria um objeto chamado primaryDNS do tipo IPAddress e o inicializa com o endereço IP 8.8.8.8. 
  //Este é um dos servidores DNS públicos do Google, que é amplamente utilizado para resolução de nomes de domínio.
  IPAddress primaryDNS(8, 8, 8, 8);

  //Esta linha cria um objeto chamado secondaryDNS do tipo IPAddress e o inicializa com o endereço IP 8.8.4.4. 
  //Este é outro servidor DNS público do Google, geralmente usado como uma alternativa ao 8.8.8.8.
  IPAddress secondaryDNS(8, 8, 4, 4);
  
  //Aqui, está sendo declarada uma variável chamada header, que é do tipo String. 
  //No entanto, não está sendo inicializada com nenhum valor, então seu valor padrão será null.
  String header;
  
  // Estado inicial das luzes
  String cozinha = "Desligada";
  String sala = "Desligada";
  String garagem = "Desligada";
  String varanda = "Desligada";
  String quarto = "Desligada";
  String sotao = "Desligada";
  
  // Define os GPIOs utilizados pelo ESP32 para saídas digitais
  const int luzsala = 4;
  const int luzvaranda = 16;
  const int luzsotao = 17;
  const int luzgaragem = 18;
  const int luzcozinha = 19;
  const int luzquarto = 23;
  const int temperatura = 34;
  const int nivel = 35;
  
  // Define os GPIOs utilizados pelo ESP32 para entradas digitais
  const int portaSala = 36;
  const int portaCozinha = 39;
  const int portaoprincipal = 32;
  const int portaogaragem = 33;
  const int janelasala = 25;
  const int janelacozinha = 26;
  const int janelaquarto1 = 27;
  const int janelaquarto2 = 14;

  // Controle de tempo para timeout 

  //Esta linha obtém o tempo atual em milissegundos desde que o programa começou a ser executado.
  // A função millis() retorna o número de milissegundos desde que o microcontrolador foi iniciado.
  unsigned long currentTime = millis();

  //Esta variável é inicializada com zero e pode ser usada para armazenar um tempo anterior. 
  //Geralmente, isso é usado em um loop para verificar o tempo decorrido desde a última execução de um determinado bloco de código.
  unsigned long previousTime = 0;

  /*Aqui, uma constante chamada timeoutTime é definida com o valor de 2000 milissegundos (ou 2 segundos). 
  Essa constante pode ser usada para definir um tempo limite em uma operação, como aguardar uma 
  resposta ou executar uma ação após um determinado período.*/
  const long timeoutTime = 2000;

  //Semelhante à previousTime, esta variável pode ser usada para armazenar o último momento em que uma atualização ocorreu. 
  //Isso é útil para controlar quando certas ações devem ser realizadas.
  unsigned long lastUpdateTime = 0;

  //Esta linha define uma constante chamada updateInterval com o valor de 5000 milissegundos (ou 5 segundos). 
  //Isso pode ser usado para determinar a frequência com que uma atualização deve ocorrer, como a leitura de sensores ou a atualização de um display.
  const long updateInterval = 5000;
 
  void setup() {

  Serial.begin(9600);   // Define o baudrate utilizado para comunicação serial

  // Configura GPIOs de entrada para sensores de portas e janelas
  pinMode(portaSala, INPUT);
  pinMode(portaCozinha, INPUT);
  pinMode(portaoprincipal, INPUT);
  pinMode(portaogaragem, INPUT);
  pinMode(janelasala, INPUT);
  pinMode(janelacozinha, INPUT);
  pinMode(janelaquarto1, INPUT);
  pinMode(janelaquarto2, INPUT);
  
  // Define os GPIOs como saída de sinal
  pinMode(luzcozinha, OUTPUT);
  pinMode(luzsala, OUTPUT);
  pinMode(luzgaragem, OUTPUT);
  pinMode(luzvaranda, OUTPUT);
  pinMode(luzquarto, OUTPUT);
  pinMode(luzsotao, OUTPUT);
  pinMode(temperatura, INPUT);
  pinMode(nivel, INPUT);

  
  // Inicia os GPIOs em nível baixo (LOW)
  digitalWrite(luzcozinha, LOW);
  digitalWrite(luzsala, LOW);
  digitalWrite(luzgaragem, LOW);
  digitalWrite(luzvaranda, LOW);
  digitalWrite(luzquarto, LOW);
  digitalWrite(luzsotao, LOW);
 
  
  // Configuração do IP fixo
  if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
  Serial.println("STA Failed to configure");
  }
  
   // Conecta-se à rede Wi-Fi
  Serial.println("Conectando a ");
  Serial.println(ssid);
  
  //Conecta à Rede Wifi indicada anteriormente
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.print(".");
  }
  
  //Essa linha envia uma linha em branco para a saída serial. Isso pode ser usado para criar uma separação visual 
  //entre as mensagens no monitor serial, tornando a saída mais legível.
  Serial.println("");

  //Essa linha imprime a mensagem "WiFi conectado ..!" no monitor serial. Isso indica que o 
  //dispositivo conseguiu se conectar à rede Wi-Fi com sucesso.
  Serial.println("WiFi conectado ..!");

  //Essa linha imprime a mensagem "IP obtido: " no monitor serial, mas não adiciona uma nova linha no final. 
  //Isso permite que a próxima linha de código (que imprime o endereço IP) seja exibida na mesma linha.
  Serial.print("IP obtido: ");

  // Essa linha obtém o endereço IP local atribuído ao dispositivo pela rede Wi-Fi e o imprime no monitor serial. 
  //O uso de println() aqui adiciona uma nova linha após a impressão do endereço IP.
  Serial.println(WiFi.localIP());
  
  // Inicializa o servidor HTTP

  /*Esta linha inicia o servidor HTTP. Isso significa que o servidor começa a escutar requisições de clientes 
  (como navegadores da web) na porta padrão (geralmente a porta 80). 
  Quando um cliente se conecta, ele pode enviar requisições HTTP, e o servidor pode responder a essas 
  requisições com páginas HTML, dados JSON, ou outros tipos de resposta.*/
  server.begin();

  }
  
  //Esta é a função principal que se repete continuamente em um programa Arduino. Dentro dela, o código aguarda e gerencia as conexões de clientes.
  void loop() {

  //Aqui, o servidor verifica se há um cliente tentando se conectar. Se um cliente estiver disponível, ele cria um objeto client que representará essa conexão.
  WiFiClient client = server.available();  
  
  //Se um cliente se conectar, o código dentro deste bloco será executado.
  if (client) {

  //Essas linhas registram o tempo atual em milissegundos desde que o programa começou. Isso pode ser usado para gerenciar o tempo limite de conexão.  
  currentTime = millis();

  
  previousTime = currentTime;
  
  //Essa linha imprime uma mensagem no console serial para indicar que um novo cliente se conectou.
  Serial.println("New Client.");

  /*String currentLine = ""; cria uma string vazia chamada currentLine.

  Ela é usada para acumular os caracteres de cada linha da requisição HTTP.

  Quando o ESP32 detecta uma quebra de linha (\n), ele processa o conteúdo acumulado em currentLine.*/
  String currentLine = "";

  //Este loop continua enquanto o cliente estiver conectado e não tiver ultrapassado um tempo limite definido (timeoutTime).
  while (client.connected() && currentTime - previousTime <= timeoutTime) {
  currentTime = millis();
  
  //Dentro do loop, o código verifica se há dados disponíveis para serem lidos do cliente.
  if (client.available()) {

  //Se houver dados disponíveis, o código lê um caractere do cliente e o armazena na variável c.  
  char c = client.read();     

  //O caractere lido é enviado ao console serial, o que pode ser útil para depuração
  Serial.write(c);

  //Este caractere é adicionado a uma string chamada header, que provavelmente contém o cabeçalho da requisição HTTP do cliente.
  header += c;
  
  //Esta condição verifica se o caractere lido é uma nova linha, o que indica o final de uma linha no cabeçalho HTTP.
  if (c == '\n') {    
  
  //Aqui, o código verifica se a linha atual está vazia, o que significa que o cabeçalho HTTP foi completamente lido.
  if (currentLine.length() == 0) {
  

  //Se o cabeçalho for válido, o servidor envia uma resposta HTTP 200 OK, indicando que a requisição foi recebida e processada com sucesso.
  client.println("HTTP/1.1 200 OK");

  //O servidor especifica que o tipo de conteúdo da resposta será HTML.
  client.println("Content-type:text/html");

  //O servidor indica que a conexão será fechada após a resposta ser enviada.
  client.println("Connection: close");

  //Essa linha vazia é necessária para indicar o fim dos cabeçalhos HTTP
  client.println();

  /* Leitura do sensor analógico e conversão para porcentagem

    Esta linha lê um valor analógico de uma entrada específica (que deve estar conectada a um sensor ou outro dispositivo). 
   O valor lido é um número entre 0 e 4095 (considerando um ADC de 12 bits). */
 
// Leitura do sensor analógico e conversão para porcentagem
int leituraNivel = analogRead(nivel);
float porcentagemNivel = (leituraNivel / 4095.0) * 100;

// Defina um nível de alarme (ajuste conforme necessário)
const int nivelAlarme = 2000;

// Adicione uma variável para o estado do alarme
String alarmeNivel = "Nível Normal"; // Estado inicial

// Verifique se o nível da caixa d'água está abaixo do valor de alarme
if (leituraNivel < nivelAlarme) {
    alarmeNivel = "N&iacute;vel Baixo!"; // Atualiza o estado do alarme
} else {
    alarmeNivel = "N&iacute;vel Normal"; // Caso contrário, o nível está normal
}


// Leitura do sensor analógico e conversão para porcentagem
// Leitura do sensor analógico e conversão para porcentagem
int leituraTemperatura = analogRead(temperatura);
float porcentagemTemperatura = (leituraTemperatura / 4095.0) * 100;

// Defina níveis de alarme (ajuste conforme necessário)
const int temperaturaAlarmeBaixa = 2000;   // valor para alarme de temperatura baixa (ajuste depois)
const int temperaturaAlarmeAlta  = 3500;   // valor para alarme de temperatura alta (ajuste depois)

// Variável para o estado do alarme
String alarmeTemperatura = "Temperatura Normal"; // Estado inicial

// Verificações de alarme
if (leituraTemperatura < temperaturaAlarmeBaixa) {
    alarmeTemperatura = "Temperatura Baixa!";
}
else if (leituraTemperatura > temperaturaAlarmeAlta) {
    alarmeTemperatura = "Temperatura Alta!";
}
else {
    alarmeTemperatura = "Temperatura Normal";
}

  
  //Essas linhas lêem o estado digital (HIGH ou LOW) de várias portas e janelas
  int estadoPortaSala = digitalRead(portaSala);
  int estadoPortaCozinha = digitalRead(portaCozinha);
  int estadoportaoprincipal = digitalRead(portaoprincipal);
  int estadoportaogaragem = digitalRead(portaogaragem);
  int estadojanelasala = digitalRead(janelasala);
  int estadojanelacozinha = digitalRead(janelacozinha);
  int estadojanelaquarto1 = digitalRead(janelaquarto1);
  int estadojanelaquarto2 = digitalRead(janelaquarto2);

  // Verifique se alguma porta ou janela está aberta
  bool portaOuJanelaAberta = false;

  if (estadoPortaSala == 1 || estadoPortaCozinha == 1 || estadoportaoprincipal == 1 || 
    estadoportaogaragem == 1 || estadojanelasala == 1 || estadojanelacozinha == 1 || 
    estadojanelaquarto1 == 1 || estadojanelaquarto2 == 1) {
    portaOuJanelaAberta = true;
}

  
  // Controle de luzes baseado na requisição HTTP 

  /*O código verifica se a requisição HTTP recebida contém uma determinada string. O método indexOf é utilizado para encontrar a 
  posição de uma substring na string header. Se a substring não for encontrada, indexOf retorna -1.
  Se a requisição contém "GET /cozinha/ligado", significa que o usuário está tentando ligar a luz da cozinha. Nesse caso, 
  a variável cozinha é definida como "Ligado" e a função digitalWrite(luzcozinha, HIGH) é chamada, o que ativa (liga) a luz da cozinha.
  Se a requisição contém "GET /cozinha/desligado", o usuário está tentando desligar a luz. A variável cozinha é então definida 
  como "Desligado" e digitalWrite(luzcozinha, LOW) é chamado, o que desativa (desliga) a luz da cozinha.*/

  if (header.indexOf("GET /cozinha/ligado") >= 0) {
  cozinha = "Ligado";
  digitalWrite(luzcozinha, HIGH);
  }
  
  else if (header.indexOf("GET /cozinha/desligado") >= 0) {
  cozinha = "Desligado";
  digitalWrite(luzcozinha, LOW);
  }
  
  else if (header.indexOf("GET /sala/ligado") >= 0) {
  sala = "Ligado";
  digitalWrite(luzsala, HIGH);
  }
  
  else if (header.indexOf("GET /sala/desligado") >= 0) {
  sala = "Desligado";
  digitalWrite(luzsala, LOW);
  }
  
  else if (header.indexOf("GET /garagem/ligado") >= 0) {
  garagem = "Ligado";
  digitalWrite(luzgaragem, HIGH);
  }
  
  else if (header.indexOf("GET /garagem/desligado") >= 0) {
  garagem = "Desligado";
  digitalWrite(luzgaragem, LOW);
  }
  
  else if (header.indexOf("GET /varanda/ligado") >= 0) {
  varanda = "Ligado";
  digitalWrite(luzvaranda, HIGH);
  }
  
  else if (header.indexOf("GET /varanda/desligado") >= 0) {
  varanda = "Desligado";
  digitalWrite(luzvaranda, LOW);
  }
  
  else if (header.indexOf("GET /quarto/ligado") >= 0) {
  quarto = "Ligado";
  digitalWrite(luzquarto, HIGH);
  }
  
  else if (header.indexOf("GET /quarto/desligado") >= 0) {
  quarto = "Desligado";
  digitalWrite(luzquarto, LOW);
  }
  
  else if (header.indexOf("GET /sotao/ligado") >= 0) {
  sotao = "Ligado";
  digitalWrite(luzsotao, HIGH);
  }
  
  else if (header.indexOf("GET /sotao/desligado") >= 0) {
  sotao = "Desligado";
  digitalWrite(luzsotao, LOW);
  }
  
  //Define o tipo de documento como HTML5.
  client.println("<!DOCTYPE html>");    

  client.println("<html>");

  //Faz a página recarregar automaticamente a cada 5 segundos. 
  client.println("<head><meta http-equiv='refresh' content='5'/>");

  //configura a escala da página para dispositivos móveis, garantindo uma exibição responsiva.
  client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");   

   
  //Remove o ícone padrão da aba do navegador (favicon).
  client.println("<link rel=\"icon\" href=\"data:,\">");    

  //Começa o corpo da página e define a cor de fundo como azul claro.
  client.println("<html><body style='background-color:#f3f4f6; color:#111827; font-family:-apple-system, BlinkMacSystemFont, Segoe UI, sans-serif; margin:0; padding:0;'>");    

  //Adiciona um estilo CSS inline: Usa a fonte Helvetica, Define um layout inline e Centraliza o conteúdo horizontalmente.
  client.println("<style>html, body { font-family:-apple-system, BlinkMacSystemFont, Segoe UI, sans-serif; text-align:center; }</style>");

  // (Classe CSS para botões principais). Define a cor de fundo do botão como azul (DodgerBlue). Remove a borda do botão.
  // Define a cor do texto como branca. Adiciona espaçamento interno no botão (8px no topo e base, 20px nas
       
      client.println("<style>");
        client.println(".button {background-color: #1E90FF; color: white; border: none; padding: 10px 20px; font-size: 16px; cursor: pointer; border-radius: 20px; transition: background-color 0.3s;}");

        client.println(".button :hover {background-color: #1E90FF}");
     client.println("</style>"); 
                                   
    
    //Adiciona um título de nível 1 (<h1>) com o texto "CONTROLE PARA CASA".
  client.println("<body><h2>CONTROLE PARA CASA</h2>");

  //Insere uma linha horizontal (<hr>) para separar visualmente o conteúdo.
  client.println("<hr>");

  //Exibe o nome "ROBERTO VITOR VILELA" em um título de nível 3 (<h3>), que é menor que <h1>. A tag <font color='black'> define a cor do texto como preto.
  client.println("<h3><font color='black'>ROBERTO VITOR VILELA - ENGENHEIRO DE SOFTWARE</h3></font>");

  //Exibe o texto "ENGENHEIRO DE SOFTWARE" em um título de nível 4 (<h4>), menor que <h3>.
  
  //Insere uma linha horizontal (<hr>) para separar visualmente o conteúdo.
  client.println("<hr>");

  /*Exibe um título (h3) com o texto "Nível da caixa d'água".Usa entidades HTML (&iacute; para í e &aacute; para á) para garantir
    que caracteres acentuados sejam exibidos corretamente.
    Define a cor do texto como preto (color='black').*/
  client.println("<h3><font color='black'>N&iacute;vel da caixa d'&aacute;gua</font></h3>");

  //Exibe o nível da caixa d'água como uma porcentagem. String(porcentagem, 1) converte o valor da variável porcentagem para uma string,
  // mantendo uma casa decimal. O valor é concatenado com "%" para indicar a unidade percentual.
  client.println("<h3>N&iacute;vel : " + String(porcentagemNivel, 1) + "%</h3>");

  client.println("<h3><font color='red'>" + alarmeNivel + "</font></h3>");

  //Insere uma linha horizontal (<hr>) para separar visualmente o conteúdo.
  client.println("<hr>");

 
  /*Exibe um título (h3) com o texto "Nível da caixa d'água".Usa entidades HTML (&iacute; para í e &aacute; para á) para garantir
    que caracteres acentuados sejam exibidos corretamente.
    Define a cor do texto como preto (color='black').*/
  client.println("<h3><font color='black'>Temperatura </font></h3>");

  //Exibe o nível da caixa d'água como uma porcentagem. String(porcentagem, 1) converte o valor da variável porcentagem para uma string,
  // mantendo uma casa decimal. O valor é concatenado com "%" para indicar a unidade percentual.
  client.println("<h3>Temperatura : " + String(porcentagemTemperatura, 1) + "&deg;C</h3>");

  client.println("<h3><font color='red'>" + alarmeTemperatura + "</font></h3>");

  //Insere uma linha horizontal (<hr>) para separar visualmente o conteúdo.
  client.println("<hr>");

  
  //Inicia a seção de CSS inline, que será aplicada à página HTML.
  client.println("<style>");

  /*Definição da grade (grid). .grid-container: Define um container de grade (grid). display: grid; → Ativa o layout de grade. 
  grid-template-columns: 1fr 1fr; → Cria duas colunas de largura igual (1 fração cada).
  gap: 5px; → Define um espaçamento de 5 pixels entre os itens da grade.*/
  client.println(".grid-container { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px; padding:12px; max-width:900px; margin:0 auto; }"); 

  //client.println(".grid-container { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; width: 50px;  height: 30px; }");      /* Define a largura fixa e Define a altura fixa*/
    
  /*grid-item: Define o estilo dos itens dentro da grade. padding: 5px; → Adiciona espaçamento interno. 
  border: 1px solid black; → Adiciona uma borda preta ao redor do item.
  text-align: center; → Centraliza o conteúdo do item. background-color: white; → Define o fundo dos itens como branco.*/
  client.println(".grid-item { padding:16px; border-radius:12px; border:1px solid #e5e7eb; text-align:left; background-color:#ffffff; box-shadow:0 2px 6px rgba(15,23,42,0.08); }");

  /*button: Define o estilo do botão principal. background-color: #B84F4F; → Define a cor de fundo como vermelho escuro. 
  border: none; → Remove a borda padrão.
  color: white; → Define a cor do texto como branca. padding: 5px 10px; → Define espaçamento interno (altura e largura).
  cursor: pointer; → Transforma o mouse em um ícone de clique ao passar sobre o botão.*/
  
  client.println(".button {background-color: #B84F4F; color: white; border: none; padding: 10px 20px; font-size: 16px; cursor: pointer; border-radius: 20px; transition: background-color 0.3s;}");

  //.button2: Define um segundo estilo de botão. background-color: #4CAF50; → Define a cor de fundo como verde 
  //(tom similar ao "verde sucesso"). Esse botão herda os estilos do .button, mas muda apenas a cor de fundo.
  //client.println(".button2 {background-color: #4CAF50;}");

  client.println(".button2 {background-color: #4CAF50; color: white; border: none; padding: 10px 20px; font-size: 16px; cursor: pointer; border-radius: 20px; transition: background-color 0.3s;}");

  //Fecha a seção de estilos CSS.
  client.println("</style>");

  //Define um <div> com a classe grid-container, que será o container da grade onde os elementos ficarão organizados.
  client.println("<div class='grid-container'>");
  
  //Abre a seção de estilos CSS para definir a aparência da grade e dos botões.
  client.println("<style>");

  //.grid-container: display: grid; → Ativa o modelo de CSS Grid. grid-template-columns: 1fr 1fr; → Cria duas colunas de tamanho igual (50% cada).
  //gap: 5px; → Adiciona um espaço de 5px entre os itens.
  client.println(".grid-container { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }");

  //client.println(".grid-container { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; width: 50px;  height: 30px; justify-content: center;  }");

  //.grid-item: padding: 5px; → Adiciona um espaço interno de 5px. border: 1px solid black; → Adiciona uma borda preta ao redor do item.
  //text-align: center; → Centraliza o texto dentro do item. background-color: #E0FFFF; → Define o fundo do item com um tom azul claro (Light Cyan)
  client.println(".grid-item { padding: 5px; border: 1px solid black; text-align: center; background-color: #E0FFFF; }");

  /*.button: background-color: #B84F4F; → Fundo vermelho escuro. border: none; → Remove a borda do botão. color: white; → Texto branco.
     padding: 5px 10px; → Adiciona espaçamento interno. cursor: pointer; → Muda o cursor para uma mãozinha ao passar por cima.
     client.println(".button { background-color: #B84F4F; border: none; color: white; padding: 5px 10px; cursor: pointer;}");*/

  client.println(".button {background-color: #B84F4F; color: white; border: none; padding: 10px 20px; font-size: 16px; cursor: pointer; border-radius: 20px; transition: background-color 0.3s;}");

  //.button2: background-color: #4CAF50; → Define um botão verde.
  //client.println(".button2 {background-color: #4CAF50;}");

  client.println(".button2 {background-color: #4CAF50; color: white; border: none; padding: 10px 20px; font-size: 16px; cursor: pointer; border-radius: 20px; transition: background-color 0.3s;}");

  //Fecha a seção de estilos CSS.
  client.println("</style>");


  // Primeira Coluna (Cozinha, Sala, Garagem)

  //Cria uma div com a classe grid-item (provavelmente usada no CSS para organização em grade). Exibe um título <h3> mostrando
  // o estado atual da luz da cozinha. O valor da variável cozinha é inserido dinamicamente, podendo ser "Ligado" ou "Desligado".
  client.println("<div class='grid-item'><h3>💡 Luz Cozinha - " + cozinha + "</h3>");
  if (cozinha == "Ligado") {

  /*Exibe um botão que permite desligar a luz. O botão contém um link (<a href='/cozinha/desligado'>), que ao ser clicado, envia um 
  pedido HTTP para a rota /cozinha/desligado.
  Isso provavelmente ativa uma lógica no servidor que desliga a luz da cozinha. Se a luz estiver desligada (cozinha == "Desligado")*/
    client.println("<p><a href='/cozinha/desligado'><button class='button'>DESLIGAR</button></a></p>");
  } else {

    //Exibe um botão que permite ligar a luz. O botão agora aponta para a rota /cozinha/ligado.
    client.println("<p><a href='/cozinha/ligado'><button class='button button2'>LIGAR</button></a></p>");
  }

  //Fecha a div que engloba toda a estrutura.
  client.println("</div>");

  client.println("<div class='grid-item'><h3>💡 Luz Sala - " + sala + "</h3>");
  if (sala == "Ligado") {
    client.println("<p><a href='/sala/desligado'><button class='button'>DESLIGAR</button></a></p>");
  } else {
    client.println("<p><a href='/sala/ligado'><button class='button button2'>LIGAR</button></a></p>");
  }
  client.println("</div>");

  client.println("<div class='grid-item'><h3>💡 Luz Garagem - " + garagem + "</h3>");
  if (garagem == "Ligado") {
    client.println("<p><a href='/garagem/desligado'><button class='button'>DESLIGAR</button></a></p>");
  } else {
    client.println("<p><a href='/garagem/ligado'><button class='button button2'>LIGAR</button></a></p>");
  }
  client.println("</div>");

  // Segunda Coluna (Varanda, Quarto, Sótão)
  client.println("<div class='grid-item'><h3>Luz Varanda - " + varanda + "</h3>");
  if (varanda == "Ligado") {
    client.println("<p><a href='/varanda/desligado'><button class='button'>DESLIGAR</button></a></p>");
  } else {
    client.println("<p><a href='/varanda/ligado'><button class='button button2'>LIGAR</button></a></p>");
  }
  client.println("</div>");

  client.println("<div class='grid-item'><h3>Luz Quarto - " + quarto + "</h3>");
  if (quarto == "Ligado") {
    client.println("<p><a href='/quarto/desligado'><button class='button'>DESLIGAR</button></a></p>");
  } else {
    client.println("<p><a href='/quarto/ligado'><button class='button button2'>LIGAR</button></a></p>");
  }
  client.println("</div>");

  client.println("<div class='grid-item'><h3>Luz do Sot&atilde;o - " + sotao + "</h3>");
  if (sotao == "Ligado") {
    client.println("<p><a href='/sotao/desligado'><button class='button'>DESLIGAR</button></a></p>");
  } else {
    client.println("<p><a href='/sotao/ligado'><button class='button button2'>LIGAR</button></a></p>");
  }
  client.println("</div>");

  client.println("</div>"); // Fecha o Grid

  client.println("<hr>");

  //Inicia uma seção <style> para definir regras de CSS.
  client.println("<style>");

  //Define uma classe chamada .status: Define uma largura (width) e altura (height) de 50px. Usa display: inline-block;
  //permitindo que os elementos apareçam lado a lado. Adiciona uma borda preta de 2px ao redor do elemento.
  
  client.println(".status { width: 40px; height: 40px; display: inline-block; border-radius: 20px; }");

  //Define a classe .verde, que pinta o fundo do elemento de verde.
  client.println(".verde { background-color: green; }");

  //Define a classe .vermelho, que pinta o fundo do elemento de vermelho.
  client.println(".vermelho { background-color: red; }");

  //Fecha a seção de estilos.
  client.println("</style>");

  //Fecha a tag <head>, indicando que a parte de metadados e estilos foi concluída.
  client.println("</head>");

  //Começa a parte visível da página (<body>) e exibe um título de nível 1 (<h1>) com o texto "Monitoramento de Portas".
  client.println("<body><h2>Monitoramento de Portas e Janelas</h2>");

    if (portaOuJanelaAberta) {
  client.println("<h2><font color='red'>ALERTA: UMA PORTA OU JANELA ABERTA</h2></font>"); //client.println("<h3><font color='black'>ROBERTO VITOR VILELA</h3></font>");
  }
  

  //Inicia a seção de estilos CSS.
  client.println("<style>");

  // Começa a parte visível da página (<body>) e exibe um título de nível 1 (<h1>) com o texto "Monitoramento de Portas".
  client.println("<body><h3>Monitoramento de Portas e Janelas</h3>");

  //Define um container de grade (grid) com duas colunas de tamanho igual. Adiciona um espaçamento de 10px entre os elementos da grade.
  client.println(".grid-container { display: grid; grid-template-columns: 10fr 10fr; gap: 30px; }");

  //Define o estilo dos itens dentro do grid: Adiciona um preenchimento interno (padding) de 10px. Cria uma borda preta ao redor do item.
  //Centraliza o texto. Define o fundo branco.
  client.println(".grid-item { padding: 20px 40px; border: 1px solid black; text-align: center; background-color: white; }");

  /*Estiliza um botão padrão: Cor de fundo vermelho escuro (#B84F4F). Sem borda.
  Texto branco. Adiciona preenchimento de 10px verticalmente e 20px horizontalmente. Altera o cursor para uma mãozinha 
  ao passar o mouse (indicando que é clicável).*/
  //client.println(".button { background-color: #B84F4F; border: none; color: white; padding: 10px 20px; cursor: pointer;}");

  client.println(".button {background-color: #B84F4F; color: white; border: none; padding: 10px 20px; font-size: 16px; cursor: pointer; border-radius: 20px; transition: background-color 0.3s;}");

  //Modifica a classe button2, que herda os estilos de .button, mas muda a cor de fundo para verde (#4CAF50).
  //client.println(".button2 {background-color: #4CAF50;}");

  client.println(".button2 {background-color: #4CAF50; color: white; border: none; padding: 10px 20px; font-size: 16px; cursor: pointer; border-radius: 20px; transition: background-color 0.3s;}");

  //Fecha a seção de estilos.
  client.println("</style>");

  //Inicia uma <div> com a classe grid-container, que será usada para estruturar o layout com CSS Grid.
  client.println("<div class='grid-container'>"); 

    
  // Primeira Coluna 
  
  //Cria um <div> com a classe grid-item, 
  client.println("<div class='grid-item'><h3>🚪 Porta da Sala</h3>");

  //Adiciona outro <div> com a classe status e outra classe adicional dinâmica: Se estadoPortaSala == 0, adiciona a classe "verde".
  //Se estadoPortaSala != 0, adiciona a classe "vermelho". Muda a cor visual do status (verde para fechada, vermelho para aberta).
  client.println("<div class='status " + String(estadoPortaSala == 0 ? "verde" : "vermelho") + "'></div>");

  //Exibe um parágrafo <p> com o texto "Status: Fechada" ou "Status: Aberta", dependendo do estado da porta.
  client.println("<p>Status: " + String(estadoPortaSala == 0 ? "Fechada" : "Aberta") + "</p>");

  //Fecha o <div> que engloba toda a seção.
  client.println("</div>");

  client.println("<div class='grid-item'><h3>Port&atilde;o Principal</h3>");
  client.println("<div class='status " + String(estadoportaoprincipal == 0 ? "verde" : "vermelho") + "'></div>");
  client.println("<p>Status: " + String(estadoportaoprincipal == 0 ? "Fechada" : "Aberta") + "</p>");
  client.println("</div>");

  client.println("<div class='grid-item'><h3>🪟 Janela da Sala</h3>");
  client.println("<div class='status " + String(estadojanelasala == 0 ? "verde" : "vermelho") + "'></div>");
  client.println("<p>Status: " + String(estadojanelasala == 0 ? "Fechada" : "Aberta") + "</p>");
  client.println("</div>");

  client.println("<div class='grid-item'><h3>🪟 Janela Quarto 1</h3>");
  client.println("<div class='status " + String(estadojanelaquarto1 == 0 ? "verde" : "vermelho") + "'></div>");
  client.println("<p>Status: " + String(estadojanelaquarto1 == 0 ? "Fechada" : "Aberta") + "</p>");
  client.println("</div>");

  // Segunda Coluna (Porta da Cozinha)

  client.println("<div class='grid-item'><h3>🚪 Porta da Cozinha</h3>");
  client.println("<div class='status " + String(estadoPortaCozinha == 0 ? "verde" : "vermelho") + "'></div>");
  client.println("<p>Status: " + String(estadoPortaCozinha == 0 ? "Fechada" : "Aberta") + "</p>");
  client.println("</div>");

  client.println("<div class='grid-item'><h3>Port&atilde;o Garagem</h3>");
  client.println("<div class='status " + String(estadoportaogaragem == 0 ? "verde" : "vermelho") + "'></div>");
  client.println("<p>Status: " + String(estadoportaogaragem == 0 ? "Fechada" : "Aberta") + "</p>");
  client.println("</div>");

  client.println("<div class='grid-item'><h3>🪟 Janela da Cozinha</h3>");
  client.println("<div class='status " + String(estadojanelacozinha == 0 ? "verde" : "vermelho") + "'></div>");
  client.println("<p>Status: " + String(estadojanelacozinha == 0 ? "Fechada" : "Aberta") + "</p>");
  client.println("</div>");

  client.println("<div class='grid-item'><h3>🪟 Janela Quarto 2</h3>");
  client.println("<div class='status " + String(estadojanelaquarto2 == 0 ? "verde" : "vermelho") + "'></div>");
  client.println("<p>Status: " + String(estadojanelaquarto2 == 0 ? "Fechada" : "Aberta") + "</p>");
  client.println("</div>");
  
  //Fecha as tags HTML abertas anteriormente, finalizando a estrutura da página.
  client.println("</body></html>");
  
  //Envia uma linha em branco ao cliente.
  client.println();
  break;      //Sai do loop quando uma condição específica for atendida.
  } else {    
  currentLine = "";   //Se a linha atual estiver vazia (\n indica fim de cabeçalho HTTP), reseta a variável currentLine.
  }

  //Se o caractere lido (c) não for um retorno de carro (\r), ele é adicionado à string currentLine, que armazena a linha atual da requisição HTTP.
  } else if (c != '\r') {   
  currentLine += c;
  }
  }
  }
  
  header = "";    // Limpa a variável header, que provavelmente contém os dados da requisição HTTP recebida.
  
  client.stop();    // Encerra a conexão com o cliente (o navegador ou outro dispositivo que fez a requisição).
  Serial.println("Client disconnected.");   //Exibe no monitor serial que o cliente foi desconectado.
  Serial.println("");  //Adiciona uma linha em branco no monitor serial para melhor legibilidade.
  }
  

  }
  

Ao estudar este código, tente identificar os blocos principais:

  • Configuração de rede Wi‑Fi.
  • Configuração dos pinos de entrada e saída.
  • Criação do servidor web.
  • Tratamento das requisições HTTP (por exemplo, quando você clica em um botão na página).
  • Atualização dos estados das saídas e leitura das entradas.
Exercício sugerido: depois de entender o código original, crie uma cópia com um novo nome e tente adicionar um novo ponto de iluminação ou um novo sensor, seguindo o mesmo padrão de programação.