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ível Baixo!"; // Atualiza o estado do alarme
} else {
alarmeNivel = "Ní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 (í para í e á 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ível da caixa d'á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í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 (í para í e á 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) + "°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ã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ã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ã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.