/*
Arduino Electronic-Dreno (I2C) - v2.0
Versão otimizada e não bloqueante
Melhorias:
✔ Sem uso de String
✔ Sem delay() no loop principal
✔ Sistema não bloqueante com millis()
✔ Média do sensor de turbidez
✔ Histerese anti-oscilação
✔ Proteção contra drenagem contínua
✔ LEDs separados
✔ LCD otimizado
✔ Uso de F() para economizar RAM
✔ Código modularizado
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// ==========================
// PINOS
// ==========================
#define BUZZER_PIN 8
#define RELAY_PIN 9
#define TURBIDITY_PIN A0
#define POT_PIN A1
#define LED_PWM 3
#define LED_STATUS 4
// ==========================
// LCD
// ==========================
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ==========================
// CONFIGURAÇÕES
// ==========================
const unsigned long DRAIN_DURATION = 10000;
const unsigned long DRAIN_INTERVAL = 60000;
const unsigned long DISPLAY_TIMEOUT = 30000;
const unsigned long MIN_DRAIN_DELAY = 30000;
const float LIMITE_ALTO = 2.5;
const float LIMITE_BAIXO = 2.2;
// ==========================
// CONTROLE
// ==========================
unsigned long lastDrainTime = 0;
unsigned long drainStartTime = 0;
unsigned long lastDisplayTime = 0;
unsigned long lastInteractionTime = 0;
bool displayIsOn = true;
bool draining = false;
bool waterDirty = false;
float currentNTU = 0;
// ==========================
// FUNÇÕES
// ==========================
// ---------- Ativa display ----------
void wakeUpDisplay() {
lastInteractionTime = millis();
if (!displayIsOn) {
lcd.backlight();
displayIsOn = true;
}
}
// ---------- Beep ----------
void beep(int freq, int duration) {
tone(BUZZER_PIN, freq, duration);
}
// ---------- Leitura do sensor ----------
float readNTU() {
long soma = 0;
for (byte i = 0; i < 10; i++) {
soma += analogRead(TURBIDITY_PIN);
delay(5);
}
float media = soma / 10.0;
float voltage = media * 5.0 / 1023.0;
float ntu =
-1120.4 * sq(voltage)
+ 5742.3 * voltage
- 4353.8;
ntu = constrain(ntu, 0, 3000);
return ntu;
}
// ---------- Atualiza LCD ----------
void updateDisplay() {
if (!displayIsOn) return;
if (millis() - lastDisplayTime < 500)
return;
lastDisplayTime = millis();
lcd.setCursor(0, 0);
char linha1[17];
snprintf(linha1, sizeof(linha1), "Turb:%4d NTU ", (int)currentNTU);
lcd.print(linha1);
lcd.setCursor(0, 1);
if (draining) {
lcd.print(F("DRENANDO... "));
}
else if (waterDirty) {
lcd.print(F("Status: SUJA "));
}
else {
lcd.print(F("Status: LIMPA "));
}
}
// ---------- Controle do LED PWM ----------
void controlLED() {
int valorPot = analogRead(POT_PIN);
int brilho = map(valorPot, 0, 1023, 0, 255);
analogWrite(LED_PWM, brilho);
}
// ---------- Inicia drenagem ----------
void startDrain(const char* motivo) {
draining = true;
drainStartTime = millis();
lastDrainTime = millis();
wakeUpDisplay();
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_STATUS, HIGH);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("DRENO ATIVADO"));
lcd.setCursor(0, 1);
lcd.print(motivo);
beep(1500, 200);
}
// ---------- Controle da drenagem ----------
void controlDrain() {
unsigned long currentTime = millis();
// Finaliza drenagem
if (draining) {
if (currentTime - drainStartTime >= DRAIN_DURATION) {
draining = false;
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_STATUS, LOW);
beep(1000, 400);
lcd.clear();
}
return;
}
// Proteção contra acionamentos frequentes
if (currentTime - lastDrainTime < MIN_DRAIN_DELAY)
return;
// Drenagem por turbidez
if (waterDirty) {
startDrain("POR TURBIDEZ");
return;
}
// Drenagem periódica
if (currentTime - lastDrainTime >= DRAIN_INTERVAL) {
startDrain("POR TEMPO");
}
}
// ---------- Controle standby display ----------
void controlDisplayStandby() {
if (
displayIsOn &&
(millis() - lastInteractionTime >= DISPLAY_TIMEOUT)
) {
lcd.noBacklight();
displayIsOn = false;
}
}
// ---------- Atualiza estado da água ----------
void updateWaterState() {
currentNTU = readNTU();
// Histerese
if (!waterDirty && currentNTU >= LIMITE_ALTO) {
waterDirty = true;
}
if (waterDirty && currentNTU <= LIMITE_BAIXO) {
waterDirty = false;
}
}
// ==========================
// SETUP
// ==========================
void setup() {
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
pinMode(TURBIDITY_PIN, INPUT);
pinMode(LED_PWM, OUTPUT);
pinMode(LED_STATUS, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print(F("ELETRONIC"));
lcd.setCursor(0, 1);
lcd.print(F("DRENO v2.0"));
beep(2000, 200);
delay(2000);
lcd.clear();
lastInteractionTime = millis();
}
// ==========================
// LOOP PRINCIPAL
// ==========================
void loop() {
wakeUpDisplay();
updateWaterState();
controlLED();
controlDrain();
updateDisplay();
controlDisplayStandby();
}