/*
Arduino Electronic-Dreno (I2C) - v3.0
Controle inteligente de drenagem por turbidez
03/06/2026 17:10
NOVAS FUNÇÕES:
✔ Dreno proporcional à turbidez
✔ Tempo de dreno adaptativo
✔ Repetição automática
✔ Histerese anti-oscilação
✔ Média móvel do LDR
✔ LCD sem flicker
✔ Sistema mais estável
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// ================= PINOS =================
#define BUZZER_PIN 8
#define RELAY_PIN 9
#define RELAY_NC_PIN 7
#define LDR_PIN A0
#define LED_PWM_PIN 11
// ================= LCD =================
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ================= CONFIGURAÇÕES =================
// Limites NTU
const int NTU_LIMPO = 2200;
const int NTU_SUJO = 1400;
const int NTU_MUITO_SUJO = 700;
const int NTU_CRITICO = 400;
// Tempos
const unsigned long COOLDOWN_TIME = 10000UL;
const unsigned long DISPLAY_TIMEOUT = 5000UL;
const unsigned long DRAIN_INTERVAL = 60UL * 60UL * 1000UL;
// Segurança
const int MAX_DRAINS = 15;
// ================= VARIÁVEIS =================
unsigned long lastDrainTime = 0;
unsigned long drainStartTime = 0;
unsigned long lastSensorRead = 0;
unsigned long lastDisplayTime = 0;
unsigned long currentDrainDuration = 10000UL;
bool drenando = false;
bool displayOn = true;
bool aguaSuja = false;
int drainCount = 0;
long ldrFiltrado = 0;
float ntu = 0;
float Tntu = 0;
float Dntu = 0;
// ================= LEITURA SENSOR =================
float readLDR() {
long soma = 0;
for (byte i = 0; i < 20; i++) {
soma += analogRead(LDR_PIN);
delay(2);
}
return soma / 20.0;
}
void atualizarSensor() {
float leitura = readLDR();
// Filtro exponencial
ldrFiltrado = (ldrFiltrado * 0.85) + (leitura * 0.15);
// Conversão aproximada
ntu = map((int)ldrFiltrado, 0, 1023, 3000, 0);
ntu = constrain(ntu, 0, 3000);
Tntu = map((int)ntu, 3000, 0, 0, 300);
Dntu = Tntu / 10;
// Histerese
if (!aguaSuja && ntu <= NTU_SUJO) {
aguaSuja = true;
}
if (aguaSuja && ntu >= NTU_LIMPO) {
aguaSuja = false;
}
}
// ================= DRENO INTELIGENTE =================
unsigned long calcularTempoDreno(float ntuAtual) {
if (ntuAtual <= NTU_CRITICO)
return 30000UL;
if (ntuAtual > NTU_CRITICO && ntuAtual <= NTU_MUITO_SUJO)
return 20000UL;
if (ntuAtual >= NTU_SUJO && ntuAtual < NTU_LIMPO)
return 12000UL;
return 10000UL;
}
int calcularRepeticoes(float ntuAtual) {
if (ntuAtual >= NTU_MUITO_SUJO && ntuAtual < NTU_SUJO)
return 2;
else if (ntuAtual <= NTU_CRITICO)
return 3;
return 1;
}
// ================= BUZZER =================
void beep(int freq, int tempo) {
tone(BUZZER_PIN, freq, tempo);
}
// ================= LCD =================
void atualizarLCD() {
static int ultimoNTU = -1;
if ((int)ntu == ultimoNTU && !drenando)
return;
ultimoNTU = ntu;
lcd.setCursor(0, 0);
lcd.print("NTU:");
lcd.print(Dntu);
lcd.setCursor(9, 0);
lcd.print("T:");
lcd.print((int)Tntu);
lcd.setCursor(0, 1);
if (drenando) {
lcd.print("DRENANDO ");
} else if (aguaSuja) {
lcd.print("Status: SUJA ");
} else {
lcd.print("Status: OK ");
}
lastDisplayTime = millis();
if (!displayOn) {
lcd.backlight();
displayOn = true;
}
}
// ================= DISPLAY =================
void controlarDisplay() {
if (displayOn && millis() - lastDisplayTime > DISPLAY_TIMEOUT) {
displayOn = false;
lcd.noBacklight();
}
}
// ================= DRENO =================
void iniciarDreno() {
drenando = true;
drainStartTime = millis();
currentDrainDuration = calcularTempoDreno(ntu);
digitalWrite(RELAY_PIN, HIGH);
beep(1500, 200);
drainCount++;
atualizarLCD();
Serial.println("DRENO INICIADO");
}
void controlarDreno() {
if (!drenando)
return;
if (millis() - drainStartTime >= currentDrainDuration) {
digitalWrite(RELAY_PIN, LOW);
drenando = false;
beep(1000, 300);
lastDrainTime = millis();
Serial.println("DRENO FINALIZADO");
delay(200);
// Verifica falha do relé
if (digitalRead(RELAY_NC_PIN) == HIGH) {
lcd.clear();
lcd.print("ERRO RELE");
while (1) {
tone(BUZZER_PIN, 2000, 200);
delay(300);
}
}
}
}
// ================= AUTO RECUPERAÇÃO =================
void executarDrenagemInteligente() {
int repeticoes = calcularRepeticoes(ntu);
Serial.print("Repeticoes: ");
Serial.println(repeticoes);
for (int i = 0; i < repeticoes; i++) {
iniciarDreno();
while (drenando) {
controlarDreno();
atualizarLCD();
}
// Aguarda estabilização da água
delay(5000);
atualizarSensor();
Serial.print("NTU pos dreno: ");
Serial.println(ntu);
// Se limpou suficientemente, para
if (ntu > NTU_SUJO) {
Serial.println("AGUA LIMPA");
break;
}
}
}
// ================= SETUP =================
void setup() {
Serial.begin(9600);
pinMode(RELAY_PIN, OUTPUT);
pinMode(RELAY_NC_PIN, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PWM_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("ElectronicDreno");
lcd.setCursor(0, 1);
lcd.print(" <Turbidimetro> ");
delay(5000);
lcd.clear();
}
// ================= LOOP =================
void loop() {
// Atualiza sensor
if (millis() - lastSensorRead >= 500) {
lastSensorRead = millis();
atualizarSensor();
atualizarLCD();
// PWM proporcional
int brilho = map((int)ntu, 0, 3000, 0, 255);
brilho = constrain(brilho, 0, 255);
analogWrite(LED_PWM_PIN, brilho);
// Debug serial
Serial.print("LDR: ");
Serial.print(ldrFiltrado);
Serial.print(" | NTU: ");
Serial.print(ntu);
Serial.print(" | TNTU: ");
Serial.print(Tntu);
Serial.print(" | DNTU: ");
Serial.print(Dntu);
Serial.print(" | Drenos: ");
Serial.println(drainCount);
}
controlarDisplay();
controlarDreno();
// ================= DRENO AUTOMÁTICO =================
if (!drenando) {
// Dreno por turbidez
if (aguaSuja && millis() - lastDrainTime > COOLDOWN_TIME) {
executarDrenagemInteligente();
}
// Dreno preventivo por tempo
if (millis() - lastDrainTime > DRAIN_INTERVAL) {
iniciarDreno();
while (drenando) {
controlarDreno();
}
drainCount = 0;
}
}
// ================= SEGURANÇA =================
if (drainCount >= MAX_DRAINS) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("LIMITE DRENO");
lcd.setCursor(0, 1);
lcd.print("MANUTENCAO");
while (1) {
tone(BUZZER_PIN, 1800, 300);
delay(500);
}
}
}