#include "DHT.h"
// =============================
// CONFIGURACIÓN DE PINES
// =============================
#define DHTPIN 25 // Pin conectado al DHT22
#define DHTTYPE DHT22
#define SOIL_PIN 34 // Pin analógico sensor de humedad suelo
#define RELAY_PIN 0 // Pin digital para relay (control de bomba)
#define LED_PIN 2 // LED en ESP32 (estado de bomba)
#define PIN_BUTTON 27 // Pulsador para alternar entre Modo Real/Simulado
#define PIN_BUTTON_MANUAL 26 // Pulsador para control manual de la bomba
// Pines para simulación (potenciómetros)
#define POT_EVAPO 32 // Control de evapotranspiración
#define POT_CALOR 33 // Control de calor ambiental
// =============================
// OBJETOS Y VARIABLES
// =============================
DHT dht(DHTPIN, DHTTYPE);
// Estado del sistema
bool SIMULACION = true; // Comienza en modo SIMULACIÓN
bool lastButtonState = HIGH;
bool lastButtonManual = HIGH;
// Umbrales de humedad suelo (% C.C.)
const float HUM_ON = 60.0;
const float HUM_OFF = 80.0;
// Seguridad: tiempo máximo de riego (30 min = 1800000 ms)
const unsigned long MAX_RIEGO_MS = 1800000;
// Variables de estado
float soilHumidity = 70.0; // Humedad inicial simulada (%)
float temp = 18.0; // Temperatura inicial simulada (°C)
float humAmb = 50.0; // Humedad relativa ambiente (%)
bool bombaEncendida = false;
bool controlManual = false; // Nuevo: bandera para control manual
long tiempoInicioRiego = 0;
// =============================
// SETUP
// =============================
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(PIN_BUTTON, INPUT_PULLUP);
pinMode(PIN_BUTTON_MANUAL, INPUT_PULLUP);
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
Serial.println("===== Sistema de Riego Automático ESP32 =====");
Serial.println("[MODO] SIMULACIÓN ACTIVADA (usar pulsador para cambiar)");
Serial.println("[CONTROL] Botón manual disponible para encender/apagar bomba.");
}
// =============================
// LOOP PRINCIPAL
// =============================
void loop() {
unsigned long now = millis();
checkButton(); // Verificar si se presionó el botón
checkManualButton(now); // Verificar control manual de la bomba
if(!controlManual){
if (SIMULACION) {
simularParcela(now); // Simulación con riego integrado
} else {
leerSensores(); // Lectura real
controlRiego(now); // Control real
}
}
delay(5000);
}
// =============================
// FUNCIONES
// =============================
// --- Pulsador para cambiar modo ---
void checkButton() {
bool buttonState = digitalRead(PIN_BUTTON);
if (buttonState == LOW && lastButtonState == HIGH) {
SIMULACION = !SIMULACION;
Serial.print("[MODO] Cambiado a: ");
Serial.println(SIMULACION ? "SIMULACIÓN" : "REAL");
delay(300); // antirrebote
}
lastButtonState = buttonState;
}
// --- Pulsador para control manual de bomba ---
void checkManualButton(unsigned long now) {
bool buttonState = digitalRead(PIN_BUTTON_MANUAL);
if (buttonState == LOW && lastButtonManual == HIGH) {
if (!controlManual) {
controlManual = true;
encenderBomba(now);
Serial.println("[MANUAL] Control manual ACTIVADO → Bomba encendida.");
} else {
controlManual = false;
apagarBomba();
Serial.println("[MANUAL] Control manual DESACTIVADO → Volviendo a modo automático.");
}
delay(300); // antirrebote
}
lastButtonManual = buttonState;
}
// --- Lectura de sensores reales ---
void leerSensores() {
humAmb = dht.readHumidity();
temp = dht.readTemperature();
if (isnan(humAmb) || isnan(temp)) {
Serial.println("[ERROR] Fallo en lectura DHT22");
}
int rawValue = analogRead(SOIL_PIN);
soilHumidity = map(rawValue, 0, 4095, 100, 0);
logEstado("REAL");
}
// --- Simulación de parcela/planta con riego ---
void simularParcela(unsigned long now) {
// Factores externos (centrados en 0 = neutral)
float evapFactor = (analogRead(POT_EVAPO) / 4095.0) - 0.5; // -0.5 a +0.5
float calorFactor = (analogRead(POT_CALOR) / 4095.0) - 0.5; // -0.5 a +0.5
// Dinámica del suelo
if (bombaEncendida) {
soilHumidity += 2.0;
temp -= 0.2;
} else {
soilHumidity -= (0.5 + evapFactor * 2.0);
}
temp += (calorFactor * 1.0);
// Límites físicos
if (soilHumidity > 100) soilHumidity = 100;
if (soilHumidity < 0) soilHumidity = 0;
if (temp < -5) temp = -5;
if (temp > 60) temp = 60;
logEstado("SIM");
// Control de riego también en modo simulado
controlRiego(now);
}
// --- Control de riego con histéresis y protección ---
void controlRiego(unsigned long now) {
if (!bombaEncendida && soilHumidity <= HUM_ON) {
encenderBomba(now);
}
else if (bombaEncendida && soilHumidity >= HUM_OFF) {
apagarBomba();
}
// Condición de seguridad: tiempo máximo de riego
if (bombaEncendida && (now - tiempoInicioRiego >= MAX_RIEGO_MS)) {
Serial.println("[ALERTA] Tiempo máximo de riego (30 min) alcanzado → Apagando bomba.");
apagarBomba();
}
// Alertas ambientales
if (temp < 9.0 || temp > 20.0) {
Serial.print("[ALERTA] Temperatura fuera de rango: ");
Serial.print(temp);
Serial.println(" °C");
}
}
// --- Encender bomba ---
void encenderBomba(unsigned long now) {
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
bombaEncendida = true;
tiempoInicioRiego = now;
Serial.println("[RIEGO] 💧 Bomba ENCENDIDA - Regando...");
}
// --- Apagar bomba ---
void apagarBomba() {
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
bombaEncendida = false;
Serial.println("[RIEGO] ✅ Bomba APAGADA – Humedad dentro del rango óptimo.");
}
// --- Log con timestamp ---
void logEstado(String modo) {
unsigned long timestamp = millis() / 1000;
Serial.print("[LOG][");
Serial.print(timestamp);
Serial.print("s][");
Serial.print(modo);
Serial.print("] Temp=");
Serial.print(temp);
Serial.print("°C | HumAmb=");
Serial.print(humAmb);
Serial.print("% | HumSuelo=");
Serial.print(soilHumidity);
Serial.print("% | Bomba=");
Serial.println(bombaEncendida ? "ON" : "OFF");
}