/*
Projeto: Sistema Inteligente de Monitoramento de Nível de Água baseado em IoT
Autores: Guilherme Ribeiro Amorim, Heder Alves dos Reis
Hardware: ESP32 + HC-SR04 + LCD I2C + API Clima
Comunicação: Telegram Bot
Versão: 1.0
*/
/*
Projeto: Sistema Inteligente de Monitoramento de Nível de Água baseado em IoT
Hardware: ESP32 + HC-SR04 + LCD I2C
Comunicação: Telegram Bot + API Clima
Versão: FINAL
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
// ===== LCD =====
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ===== WIFI =====
const char* ssid = "UFVJM";
const char* password = "UFVJMPROF1243";
// ===== TELEGRAM =====
#define BOT_TOKEN "8505412147:AAFN54-JKu6MH32sAoN_4wakEkmvm5nlHJA"
#define CHAT_ID "6672622636"
// ===== API CLIMA =====
#define WEATHER_URL "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/-17.882478,-41.496477?unitGroup=metric&include=current&lang=pt&key=R847ZB6F2P5RQ6LSPK95BCT22&contentType=json"
WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);
// ===== PINOS =====
#define TRIG 32
#define ECHO 33
#define LED_VERDE 2
#define LED_VERMELHO 4
#define BUZZER 15
// ===== CONFIG =====
int nivelMax = 100;
int criticoBaixo = 20;
int criticoAlto = 90;
bool alarmeAtivo = true;
bool alertaBaixoEnviado = false;
bool alertaAltoEnviado = false;
// ===== TELEGRAM =====
unsigned long lastTimeBotRan = 0;
int botRequestDelay = 1000;
// ===== SENSOR =====
long medirDistancia() {
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
long duracao = pulseIn(ECHO, HIGH, 30000);
if (duracao == 0) return -1;
return duracao * 0.034 / 2;
}
// ===== CLIMA =====
String getClima() {
HTTPClient http;
client.setInsecure();
http.begin(client, WEATHER_URL);
int httpCode = http.GET();
if (httpCode != 200) {
http.end();
return "Erro ao obter clima";
}
String payload = http.getString();
DynamicJsonDocument doc(2048);
deserializeJson(doc, payload);
float temp = doc["currentConditions"]["temp"];
String condicao = doc["currentConditions"]["conditions"].as<String>();
http.end();
return "🌤 Clima atual\nTemp: " + String(temp) + "°C\nCond: " + condicao;
}
// ===== TELEGRAM =====
void handleNewMessages(int numNewMessages) {
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
if (chat_id != CHAT_ID) return;
if (text == "/start") {
bot.sendMessage(chat_id, "🤖 Bot iniciado!\nUse /ajuda", "");
}
else if (text == "/ajuda") {
bot.sendMessage(chat_id,
"/start\n/status\n/nivel\n/clima\n/alarme_on\n/alarme_off\n/ping\n/info", "");
}
else if (text == "/clima") {
bot.sendMessage(chat_id, getClima(), "");
}
else if (text == "/ping") {
bot.sendMessage(chat_id, "✅ Bot online!", "");
}
else if (text == "/info") {
bot.sendMessage(chat_id,
"ESP32 Monitor de Água\nHC-SR04 + LCD I2C\nVersão Final", "");
}
else if (text == "/status" || text == "/nivel") {
long dist = medirDistancia();
int porcentagem = ((nivelMax - dist) * 100) / nivelMax;
porcentagem = constrain(porcentagem, 0, 100);
String estado =
(porcentagem <= criticoBaixo) ? "BAIXO ⚠️" :
(porcentagem >= criticoAlto) ? "CHEIO 🚨" : "NORMAL 🟢";
bot.sendMessage(chat_id,
"📊 Nível: " + String(porcentagem) + "%\nEstado: " + estado, "");
}
else if (text == "/alarme_on") {
alarmeAtivo = true;
bot.sendMessage(chat_id, "🔔 Alarme ativado", "");
}
else if (text == "/alarme_off") {
alarmeAtivo = false;
bot.sendMessage(chat_id, "🔕 Alarme desativado", "");
}
}
}
// ===== SETUP =====
void setup() {
Serial.begin(115200);
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
pinMode(LED_VERDE, OUTPUT);
pinMode(LED_VERMELHO, OUTPUT);
pinMode(BUZZER, OUTPUT);
Wire.begin(21, 22);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Monitor Agua");
lcd.setCursor(0, 1);
lcd.print("Inicializando");
delay(2000);
lcd.clear();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi conectado!");
client.setInsecure();
}
// ===== LOOP =====
void loop() {
if (millis() > lastTimeBotRan + botRequestDelay) {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
handleNewMessages(numNewMessages);
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
lastTimeBotRan = millis();
}
long distancia = medirDistancia();
lcd.clear();
if (distancia < 0) {
lcd.setCursor(0, 0);
lcd.print("Erro Sensor");
digitalWrite(LED_VERDE, LOW);
digitalWrite(LED_VERMELHO, LOW);
noTone(BUZZER);
delay(1000);
return;
}
int porcentagem = ((nivelMax - distancia) * 100) / nivelMax;
porcentagem = constrain(porcentagem, 0, 100);
lcd.setCursor(0, 0);
lcd.print("Nivel:");
lcd.print(porcentagem);
lcd.print("% ");
if (porcentagem <= criticoBaixo) {
digitalWrite(LED_VERMELHO, HIGH);
digitalWrite(LED_VERDE, LOW);
if (alarmeAtivo) tone(BUZZER, 1000);
else noTone(BUZZER);
lcd.setCursor(0, 1);
lcd.print("Nivel BAIXO!");
if (alarmeAtivo && !alertaBaixoEnviado) {
bot.sendMessage(CHAT_ID, "⚠️ ALERTA: Nível BAIXO!", "");
alertaBaixoEnviado = true;
alertaAltoEnviado = false;
}
}
else if (porcentagem >= criticoAlto) {
digitalWrite(LED_VERMELHO, HIGH);
digitalWrite(LED_VERDE, LOW);
if (alarmeAtivo) tone(BUZZER, 1500);
else noTone(BUZZER);
lcd.setCursor(0, 1);
lcd.print("RESERVATORIO CHEIO");
if (alarmeAtivo && !alertaAltoEnviado) {
bot.sendMessage(CHAT_ID, "🚨 ALERTA: Reservatório CHEIO!", "");
alertaAltoEnviado = true;
alertaBaixoEnviado = false;
}
}
else {
digitalWrite(LED_VERDE, HIGH);
digitalWrite(LED_VERMELHO, LOW);
noTone(BUZZER);
lcd.setCursor(0, 1);
lcd.print("Nivel Normal");
alertaBaixoEnviado = false;
alertaAltoEnviado = false;
}
delay(1000);
}