Painel de água que acha o vazamento de madrugada
Um sensor no cano conta cada litro que passa e outro, na tampa da caixa d'água, mede o nível. O ESP32 mostra no celular quantos litros a casa gastou hoje e avisa quando a água corre às 3 h da manhã, hora em que ninguém usa. Serve para vizinhos, condomínios e sítios com caixa d'água.
Como funciona
Conta litros, mede a caixa, avisa
O sensor de vazão tem uma hélice com um ímã: cada volta gera um pulso, e o YF-S201 dá cerca de 450 pulsos por litro. O ESP32 conta os pulsos e calcula os litros do dia e a vazão em litros por minuto. Na tampa, o sensor ultrassônico mede a distância até a água como um morcego: manda um som e cronometra o eco. Água vazia = distância grande. De madrugada quase ninguém abre torneira, então água correndo por muito tempo nessa hora quase sempre é descarga ou cano vazando.
Peças
Lista de compras
| Peça | Para que serve | Preço aprox. |
|---|---|---|
| ESP32 DevKit V1 (30 pinos) | O cérebro, com Wi-Fi | R$ 30–40 |
| Sensor de vazão YF-S201 (rosca 1/2") | Conta os litros que passam no cano | R$ 25–35 |
| Sensor ultrassônico HC-SR04 | Mede a distância até a água. Bom para o teste na bancada | R$ 8–12 |
| Resistores 10 kΩ e 20 kΩ (2 de cada) | Dois divisores que baixam o sinal de 5 V para 3,3 V. Sem 20 kΩ, use dois de 10 kΩ em série | R$ 1–3 |
| Adaptadores de rosca 1/2" e fita veda-rosca | Encaixam o sensor de vazão no cano | R$ 5–10 |
| Caixa plástica com tampa | Protege o ESP32 da umidade | R$ 8–15 |
| Fonte 5 V (carregador de celular serve) + cabo USB | Alimenta o ESP32 e os sensores | R$ 0–15 |
| Protoboard e jumpers | Ligações sem solda | R$ 10–15 |
| Total | R$ 80–140 | |
| Opcional: JSN-SR04T | Ultrassônico à prova d'água, para ficar na caixa de vez. Troca o HC-SR04, mesmos pinos | R$ 35–55 |
Preços aproximados de loja online brasileira em outubro de 2026, a conferir antes de comprar. Não inclui cano, conexões extras nem o trabalho de encanador.
Ligação
O circuito, pino por pino
| Componente | Pino do componente | Liga no ESP32 |
|---|---|---|
| YF-S201 | Vermelho · preto · amarelo | VIN (5 V) · GND · 10 kΩ → nó → GPIO 27; do nó, 20 kΩ ao GND |
| Ultrassônico (HC-SR04 ou JSN-SR04T) | VCC · GND · TRIG · ECHO | VIN (5 V) · GND · GPIO 19 · 10 kΩ → nó → GPIO 18; do nó, 20 kΩ ao GND |
Passo a passo
Da bancada à caixa d'água
- Prepare a Arduino IDE. Instale a Arduino IDE 2 e, no Gerenciador de Placas, "esp32" (Espressif). Este projeto não precisa de biblioteca extra.
- Teste a placa sozinha. Ligue o ESP32 no USB, escolha "ESP32 Dev Module" e a porta, e grave o exemplo Blink. Se não gravar, segure o botão BOOT quando aparecer "Connecting...".
- Monte os divisores na protoboard. Siga a tabela. Antes de ligar no pino, meça com multímetro: no nó tem que dar perto de 3,3 V quando o sinal está em 5 V.
- Teste o nível na bancada. Grave o código, abra o Monitor Serial (115200) e aponte o ultrassônico para a mesa a 30 cm e a 60 cm. A distância tem que acompanhar.
- Calibre o sensor de vazão com um balde. Ligue o sensor numa mangueira, respeitando a seta do corpo (sentido da água). Encha um balde de 10 litros e compare com os litros do painel. Se der 9 litros, ajuste
PULSOS_LITROna mesma proporção. - Instale na casa, com um adulto. O lugar certo é a saída da caixa d'água, antes de chegar nas torneiras. Feche o registro, corte o cano ou use uma conexão pronta, rosqueie o sensor com veda-rosca e a seta no sentido da água. Abra o registro e procure vazamento na rosca.
- Coloque o ultrassônico na tampa da caixa, virado para baixo, longe da boia e da entrada de água. Meça com trena a distância da tampa até a água com a caixa cheia e anote em
ALTURA_CHEIA; até o fundo, emALTURA_VAZIA. - Abra o painel. O Monitor Serial mostra o IP (ex.: 192.168.0.50). Digite no navegador do celular, na mesma rede Wi-Fi.
Código
Arduino IDE para ESP32
Troque o nome e a senha da rede, as alturas da sua caixa e grave. O relógio vem da internet (NTP), no horário de Brasília, para o ESP32 saber o que é madrugada.
// Painel de água — ESP32, Arduino IDE
// Sem biblioteca extra: WiFi, WebServer
// e time.h já vêm com a placa ESP32
#include <WiFi.h>
#include <WebServer.h>
#include <time.h>
const char* REDE = "NOME_DA_REDE";
const char* SENHA = "SENHA_DA_REDE";
// GPIO 27: sinal do YF-S201 (pelo divisor)
const int PINO_VAZAO = 27;
// GPIO 19: TRIG do ultrassônico
const int PINO_TRIG = 19;
// GPIO 18: ECHO do ultrassônico (divisor)
const int PINO_ECHO = 18;
// YF-S201: cerca de 450 pulsos por litro.
// Ajuste depois do teste do balde.
float PULSOS_LITRO = 450.0;
// Distância da tampa até a água, em cm,
// com a caixa vazia e com a caixa cheia
const float ALTURA_VAZIA = 120.0;
const float ALTURA_CHEIA = 20.0;
// Vazão de madrugada que conta como
// vazamento (L/min) e por quanto tempo (s)
const float LIMITE_LMIN = 0.2;
const int TEMPO_VAZAMENTO = 600;
// Caixa baixa abaixo de 20%
const int NIVEL_BAIXO = 20;
volatile unsigned long pulsos = 0;
unsigned long pulsosAntes = 0;
unsigned long ultimoSegundo = 0;
float litrosHoje = 0, vazao = 0;
int nivel = 0, segundosCorrendo = 0;
int diaAtual = -1;
bool vazamento = false, caixaBaixa = false;
WebServer servidor(80);
// Roda sozinha a cada pulso da hélice.
// IRAM_ATTR deixa a função na memória rápida.
void IRAM_ATTR contaPulso() {
pulsos++;
}
// Mede a distância até a água, em cm
float medirDistancia() {
digitalWrite(PINO_TRIG, LOW);
delayMicroseconds(2);
digitalWrite(PINO_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(PINO_TRIG, LOW);
// espera o eco por até 30 ms
unsigned long us = pulseIn(PINO_ECHO, HIGH, 30000);
if (us == 0) return -1;
// som: 0,0343 cm por microssegundo, ida e volta
return us * 0.0343 / 2;
}
void medirNivel() {
float d = medirDistancia();
if (d < 0) return;
float faixa = ALTURA_VAZIA - ALTURA_CHEIA;
float pct = (ALTURA_VAZIA - d) / faixa * 100;
nivel = constrain((int)pct, 0, 100);
caixaBaixa = nivel < NIVEL_BAIXO;
}
void medirVazao() {
// copia o contador sem a interrupção mexer
noInterrupts();
unsigned long p = pulsos;
interrupts();
unsigned long novos = p - pulsosAntes;
pulsosAntes = p;
float litros = novos / PULSOS_LITRO;
litrosHoje += litros;
// litros em 1 s × 60 = litros por minuto
vazao = litros * 60;
}
void conferirHora() {
struct tm t;
if (!getLocalTime(&t, 10)) return;
// virou o dia: zera os litros
if (t.tm_mday != diaAtual) {
diaAtual = t.tm_mday;
litrosHoje = 0;
}
bool madrugada = t.tm_hour >= 2 && t.tm_hour < 5;
if (madrugada && vazao > LIMITE_LMIN) {
segundosCorrendo++;
} else {
segundosCorrendo = 0;
}
if (segundosCorrendo > TEMPO_VAZAMENTO) {
vazamento = true;
}
}
// /dados: JSON para o painel e para a IA
void dados() {
String j = "{\"litros_hoje\":" + String(litrosHoje, 1);
j += ",\"vazao_lmin\":" + String(vazao, 2);
j += ",\"nivel\":" + String(nivel);
j += ",\"vazamento\":" + String(vazamento ? "true" : "false");
j += ",\"caixa_baixa\":" + String(caixaBaixa ? "true" : "false");
j += "}";
servidor.send(200, "application/json", j);
}
// /: página que abre no celular (5 em 5 s)
void painel() {
String h = "<meta name=viewport "
"content='width=device-width'>"
"<meta http-equiv=refresh content=5>";
h += "<h2>Água</h2><p>Hoje: " + String(litrosHoje, 1);
h += " L<br>Agora: " + String(vazao, 1) + " L/min";
h += "<br>Caixa: " + String(nivel) + "%</p>";
if (vazamento) h += "<p><b>ALERTA: vazamento</b></p>";
if (caixaBaixa) h += "<p><b>ALERTA: caixa baixa</b></p>";
servidor.send(200, "text/html", h);
}
// /zera: apaga o alerta depois do conserto
void zera() {
vazamento = false;
servidor.send(200, "text/plain", "ok");
}
void setup() {
Serial.begin(115200);
pinMode(PINO_TRIG, OUTPUT);
pinMode(PINO_ECHO, INPUT);
pinMode(PINO_VAZAO, INPUT);
attachInterrupt(digitalPinToInterrupt(PINO_VAZAO),
contaPulso, FALLING);
WiFi.begin(REDE, SENHA);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// horário de Brasília: UTC -3 h
configTime(-3 * 3600, 0, "pool.ntp.org");
Serial.print("\nPainel em http://");
Serial.println(WiFi.localIP());
servidor.on("/", painel);
servidor.on("/dados", dados);
servidor.on("/zera", zera);
servidor.begin();
}
void loop() {
servidor.handleClient();
if (millis() - ultimoSegundo < 1000) return;
ultimoSegundo = millis();
medirVazao();
medirNivel();
conferirHora();
Serial.printf("hoje=%.1f L vazao=%.2f nivel=%d%%\n",
litrosHoje, vazao, nivel);
}
A camada de IA
O que a IA faz neste projeto
Quanto gastei esta semana?
Um script no computador guarda os litros de cada hora num arquivo. A IA lê o histórico e responde em português, com o dia que mais gastou.
Vazamento explicado
Quando o alerta acende, a IA olha o horário e a vazão e sugere onde procurar: "fluxo baixo e constante parece descarga; fluxo alto parece cano".
Comparar dias
"Domingo gastou o dobro de segunda, o que mudou?" A IA cruza os horários de pico e aponta banho longo, máquina de lavar ou mangueira.
Script em Python, rodando no computador na mesma rede. Rode python agua_ia.py guarda e deixe aberto; depois python agua_ia.py pergunta.
# agua_ia.py — roda no computador,
# na mesma rede do ESP32
import csv, json, sys, time
import urllib.request
from datetime import datetime
# troque pelo IP do seu ESP32
URL = "http://192.168.0.50/dados"
ARQ = "agua.csv"
def guarda():
# uma linha por hora: data, litros, nível
while True:
d = json.load(urllib.request.urlopen(URL))
agora = datetime.now().strftime("%Y-%m-%d %H:00")
with open(ARQ, "a", newline="") as f:
csv.writer(f).writerow(
[agora, d["litros_hoje"], d["nivel"]])
time.sleep(3600)
def pergunta():
# últimas 7 x 24 linhas = uma semana
linhas = open(ARQ).read().splitlines()[-168:]
q = input("Pergunta: ")
prompt = (
"Você analisa o consumo de água de uma casa. "
"Cada linha: data e hora, litros do dia "
"até aquela hora, nível da caixa em %.\n"
+ "\n".join(linhas)
+ "\nResponda em português, em até 4 frases: "
+ q
)
print(prompt)
# Mande o prompt ao modelo que você usa:
# - cole no chat do serviço de IA; ou
# - use a biblioteca oficial do serviço,
# com a SUA chave numa variável de
# ambiente (nunca escrita no código); ou
# - rode um modelo local no PC, sem chave.
if sys.argv[1:] == ["guarda"]:
guarda()
else:
pergunta()
Teste e melhore
Confira antes de mostrar para alguém
- No nó de cada divisor, o multímetro marca no máximo 3,3 V.
- O teste do balde de 10 litros dá entre 9,5 e 10,5 litros no painel.
- Com a torneira fechada, a vazão marca 0 L/min.
- Aproximando a mão do ultrassônico, o nível sobe; afastando, desce.
- A rosca do sensor de vazão não pinga depois de 1 hora com o registro aberto.
- Para testar o alerta sem esperar a madrugada, mude por um dia as horas 2 e 5 no código para a hora atual e deixe uma torneira pingando.
| Erro comum | Causa provável | Como resolver |
|---|---|---|
| Litros sempre zero | Sensor com a seta ao contrário ou fio amarelo solto | Confira a seta no sentido da água e o divisor até o GPIO 27 |
| Litros a mais ou a menos | Cada sensor varia um pouco | Refaça o teste do balde e ajuste PULSOS_LITRO |
| Nível pula ou dá 0% | Eco batendo na parede, na boia ou condensação no sensor | Centralize o sensor, afaste da boia; na caixa, use o JSN-SR04T |
| Alerta de vazamento sem vazamento | Alguém usou água de madrugada ou a caixa enchendo pela boia | Sensor na saída da caixa, não na entrada; aumente TEMPO_VAZAMENTO |
| Litros zeram do nada | ESP32 reiniciou (queda de luz, fonte fraca) | Fonte de 5 V boa; na versão 2, salve o total na flash |
Caderno de testes. Cada vez que mudar alguma coisa, anote numa linha. O registro da primeira semana vira o argumento de venda.
| Data | Versão | O que mudou | Resultado |
|---|---|---|---|
| 20/10 | v1 | 450 pulsos por litro, de fábrica | Balde de 10 L marcou 9,2 L |
| 21/10 | v2 | PULSOS_LITRO = 414 | Balde marcou 10,0 L |
| … | v3 | Total do dia salvo na flash | Anote aqui |
Segurança
Água, cano e altura
Ficha de negócio
Como vender o painel de água
| Quem compra | Vizinho com conta de água alta, condomínio (um painel por bloco ou por caixa), sítio com caixa d'água ou poço, escola |
| Custo do kit | R$ 80–140 (lista acima, a conferir); mais R$ 35–55 se usar o JSN-SR04T |
| Preço sugerido | R$ 250–380 o aparelho montado, calibrado e em caixa (sugestão) |
| Mão de obra | 2 a 3 horas para instalar com o encanador ou o responsável pela casa, calibrar com o balde e ensinar a ler o painel |
| Assinatura opcional | R$ 15–25 por mês: histórico, relatório da semana e aviso de vazamento (sugestão) |
| Argumento de economia | Meça na casa do cliente: litros por hora entre 2 h e 5 h × 24 × 30 = litros perdidos por mês. Divida por 1.000 para ter m³ e multiplique pela tarifa da conta de água dele (a conferir) |
Para ir além
Próximos passos
Para entender como o modelo de IA lê o histórico e por que às vezes erra, comece pelo curso IA do zero. Para usar um agente de IA que ajuda a escrever e corrigir o código, siga para o OSWork. Todos os cursos são abertos e gratuitos no INEMA.CLUB.