Introducción a la Agricultura Inteligente
Los sistemas de riego automático representan una revolución en la agricultura de precisión, combinando tecnologías IoT, sensores inteligentes y control automatizado para optimizar el uso del agua. En un mundo donde el agua es cada vez más escasa, estos sistemas mecatrónicos no solo mejoran la eficiencia agrícola, sino que contribuyen significativamente a la conservación de recursos hídricos.
El ESP32 se ha convertido en el corazón de muchos sistemas AgTech (Tecnología Agrícola) debido a su capacidad de conectividad dual (Wi-Fi/Bluetooth), múltiples canales ADC para sensores, y su bajo consumo energético. Esta combinación lo hace ideal para aplicaciones agrícolas que requieren monitoreo continuo y control remoto.
Agricultura de Precisión
- Monitoreo continuo de parámetros del suelo
- Aplicación optimizada de recursos
- Reducción del desperdicio de agua hasta 40%
- Mejora en rendimiento de cultivos
Tecnología de Sensores
- Sensores capacitivos vs resistivos
- Medición de humedad volumétrica
- Compensación de temperatura
- Calibración específica por tipo de suelo
Beneficios de Automatización
- Reducción de mano de obra hasta 60%
- Riego nocturno para minimizar evaporación
- Respuesta inmediata a condiciones cambiantes
- Registro histórico de datos para optimización
Integración IoT
- Monitoreo remoto vía smartphone/web
- Alertas automáticas por SMS/email
- Integración con estaciones meteorológicas
- Análisis predictivo y machine learning
Fundamentos Técnicos del Sistema
Tipos de Sensores de Humedad del Suelo
Los sensores de humedad son el componente crítico en cualquier sistema de riego inteligente. Existen principalmente dos tecnologías:
Sensores Resistivos
Miden la resistencia eléctrica entre dos electrodos. Son económicos pero susceptibles a corrosión y menos precisos en diferentes tipos de suelo.
Sensores Capacitivos
Miden cambios en la capacitancia del suelo. Son más precisos, duraderos y no sufren corrosión, ideales para sistemas permanentes.
Principios de Medición y Calibración
La humedad del suelo se puede expresar de diferentes formas:
- Contenido Volumétrico de Agua (θv): Volumen de agua / Volumen total de suelo
- Contenido Gravimétrico (θg): Masa de agua / Masa de suelo seco
- Potencial Hídrico: Energía necesaria para extraer agua del suelo
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
// Pines del sistema
#define MOISTURE_SENSOR_PIN 34
#define RELAY_PIN 26
#define PUMP_ENABLE_PIN 27
#define FLOW_SENSOR_PIN 35
// Calibración del sensor (valores específicos por sensor)
const int AIR_VALUE = 3000; // Valor en aire seco
const int WATER_VALUE = 1300; // Valor en agua
const int MOISTURE_THRESHOLD = 30; // Porcentaje mínimo de humedad
// Variables del sistema
float moisturePercentage = 0;
bool pumpActive = false;
unsigned long lastReading = 0;
const unsigned long READING_INTERVAL = 30000; // 30 segundos
// Configuración WiFi y MQTT
const char* ssid = "TU_WIFI";
const char* password = "TU_PASSWORD";
const char* mqtt_server = "tu.broker.mqtt.com";
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
Serial.begin(115200);
// Configurar pines
pinMode(MOISTURE_SENSOR_PIN, INPUT);
pinMode(RELAY_PIN, OUTPUT);
pinMode(PUMP_ENABLE_PIN, OUTPUT);
pinMode(FLOW_SENSOR_PIN, INPUT_PULLUP);
// Estado inicial: bomba apagada
digitalWrite(RELAY_PIN, LOW);
digitalWrite(PUMP_ENABLE_PIN, LOW);
// Conectar WiFi
setupWiFi();
// Configurar MQTT
client.setServer(mqtt_server, 1883);
client.setCallback(mqttCallback);
Serial.println("Sistema de riego iniciado");
}
void loop() {
// Mantener conexión MQTT
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
// Lectura periódica del sensor
if (millis() - lastReading >= READING_INTERVAL) {
readMoistureSensor();
controlIrrigation();
sendData();
lastReading = millis();
}
delay(100);
}
float readMoistureSensor() {
// Tomar múltiples lecturas para estabilidad
int totalReading = 0;
const int numReadings = 10;
for (int i = 0; i < numReadings; i++) {
totalReading += analogRead(MOISTURE_SENSOR_PIN);
delay(50);
}
int averageReading = totalReading / numReadings;
// Convertir a porcentaje con calibración
moisturePercentage = map(averageReading, AIR_VALUE, WATER_VALUE, 0, 100);
moisturePercentage = constrain(moisturePercentage, 0, 100);
Serial.printf("Lectura ADC: %d, Humedad: %.1f%%\n",
averageReading, moisturePercentage);
return moisturePercentage;
}
void controlIrrigation() {
if (moisturePercentage < MOISTURE_THRESHOLD && !pumpActive) {
startIrrigation();
} else if (moisturePercentage > (MOISTURE_THRESHOLD + 10) && pumpActive) {
stopIrrigation();
}
}
void startIrrigation() {
pumpActive = true;
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(PUMP_ENABLE_PIN, HIGH);
Serial.println("🌱 Iniciando riego automático");
// Enviar notificación MQTT
client.publish("irrigation/status", "STARTED");
}
void stopIrrigation() {
pumpActive = false;
digitalWrite(RELAY_PIN, LOW);
digitalWrite(PUMP_ENABLE_PIN, LOW);
Serial.println("🛑 Deteniendo riego - Humedad adecuada");
// Enviar notificación MQTT
client.publish("irrigation/status", "STOPPED");
}
Control de Bomba y Sistema de Válvulas
El control preciso de actuadores es fundamental para un sistema eficiente:
- Relés de Estado Sólido: Para control suave y sin chispa
- Válvulas Solenoides: Respuesta rápida y bajo consumo
- Sensores de Flujo: Monitoreo de consumo de agua
- Protección contra Funcionamiento en Seco: Sensor de nivel de tanque
// Sistema de riego multi-zona avanzado
#define NUM_ZONES 4
#define FLOW_SENSOR_INTERRUPT 0
struct IrrigationZone {
int moistureSensorPin;
int valveRelayPin;
float moistureLevel;
bool isActive;
unsigned long startTime;
unsigned long duration;
String name;
};
IrrigationZone zones[NUM_ZONES] = {
{34, 26, 0, false, 0, 600000, "Tomates"}, // 10 min
{35, 27, 0, false, 0, 900000, "Lechugas"}, // 15 min
{32, 28, 0, false, 0, 1200000, "Maíz"}, // 20 min
{33, 29, 0, false, 0, 450000, "Hierbas"} // 7.5 min
};
volatile unsigned int flowPulseCount = 0;
float flowRate = 0.0;
unsigned int flowMilliLitres = 0;
unsigned long totalMilliLitres = 0;
void setup() {
// Configurar zonas
for (int i = 0; i < NUM_ZONES; i++) {
pinMode(zones[i].moistureSensorPin, INPUT);
pinMode(zones[i].valveRelayPin, OUTPUT);
digitalWrite(zones[i].valveRelayPin, LOW);
}
// Configurar sensor de flujo
pinMode(FLOW_SENSOR_PIN, INPUT_PULLUP);
attachInterrupt(FLOW_SENSOR_INTERRUPT, pulseCounter, FALLING);
}
void pulseCounter() {
flowPulseCount++;
}
void updateFlowMeasurement() {
// Cálculo cada segundo
static unsigned long lastTime = 0;
if (millis() - lastTime >= 1000) {
detachInterrupt(FLOW_SENSOR_INTERRUPT);
// Calcular flujo (L/min) - Calibración específica del sensor
flowRate = ((1000.0 / (millis() - lastTime)) * flowPulseCount) / 7.5;
flowMilliLitres = (flowRate / 60) * 1000;
totalMilliLitres += flowMilliLitres;
flowPulseCount = 0;
lastTime = millis();
attachInterrupt(FLOW_SENSOR_INTERRUPT, pulseCounter, FALLING);
}
}
void manageMultiZoneIrrigation() {
for (int i = 0; i < NUM_ZONES; i++) {
// Leer humedad de cada zona
zones[i].moistureLevel = readZoneMoisture(i);
// Control de riego por zona
if (zones[i].moistureLevel < MOISTURE_THRESHOLD && !zones[i].isActive) {
startZoneIrrigation(i);
}
// Verificar duración máxima
if (zones[i].isActive &&
(millis() - zones[i].startTime) > zones[i].duration) {
stopZoneIrrigation(i);
}
}
}
void startZoneIrrigation(int zone) {
zones[zone].isActive = true;
zones[zone].startTime = millis();
digitalWrite(zones[zone].valveRelayPin, HIGH);
Serial.printf("🌱 Iniciando riego en zona %s\n", zones[zone].name.c_str());
// Crear mensaje JSON para MQTT
DynamicJsonDocument doc(200);
doc["zone"] = zones[zone].name;
doc["action"] = "start";
doc["moisture"] = zones[zone].moistureLevel;
doc["timestamp"] = millis();
String message;
serializeJson(doc, message);
client.publish("irrigation/zone_status", message.c_str());
}
Ejercicios Prácticos Progresivos
Objetivo: Familiarizarse con la lectura y calibración de sensores de humedad capacitivos.
Materiales Necesarios:
- ESP32 DevKit V1
- Sensor de humedad capacitivo v1.2
- Protoboard y cables jumper
- Multímetro (opcional)
Procedimiento:
- Conectar sensor al pin ADC (GPIO 34)
- Implementar rutina de calibración
- Probar en diferentes tipos de suelo
- Registrar valores de referencia
Objetivo: Crear un sistema de riego programable con horarios específicos y duración controlada.
Materiales Adicionales:
- Módulo RTC DS3231
- Relé de 5V y válvula solenoide
- Bomba de agua 12V
- Fuente de alimentación
Características del Sistema:
- Programación de múltiples horarios diarios
- Duración configurable por sesión
- Interfaz web para configuración
- Log de eventos en memoria SPIFFS
Objetivo: Implementar sistema inteligente que gestiona múltiples zonas de cultivo con diferentes requerimientos hídricos.
Funcionalidades Avanzadas:
- 4 zonas independientes con sensores dedicados
- Algoritmo de riego basado en tipo de cultivo
- Integración con datos meteorológicos
- Predicción de riego con machine learning básico
- Notificaciones push y alertas por email
Objetivo: Desarrollar una plataforma completa de agricultura de precisión con análisis de datos y optimización automática.
Características Profesionales:
- Dashboard web responsivo con gráficas en tiempo real
- Aplicación móvil con React Native
- Base de datos histórica con análisis trends
- API REST completa para integración
- Sistema de alertas inteligente
- Reportes automáticos PDF
Proyecto Final: Sistema de Agricultura de Precisión
Estación de Monitoreo Agrícola Inteligente
Desarrollaremos un sistema completo de agricultura de precisión que integra múltiples sensores, control automatizado de riego, monitoreo IoT y análisis predictivo para optimizar la producción agrícola.
Especificaciones Técnicas
Hardware Requerido:
- ESP32 DevKit V1 (controlador principal)
- 4x Sensores de humedad capacitivos
- Sensor DHT22 (temperatura/humedad ambiente)
- Sensor BMP280 (presión atmosférica)
- Sensor de luz BH1750
- 4x Relés de estado sólido
- Válvulas solenoides 12V
- Bomba de agua centrífuga
- Sensor de flujo YF-S201
- Panel solar 20W + batería 12V
Software y Conectividad:
- Firmware ESP32 con FreeRTOS
- Comunicación Wi-Fi y MQTT
- Base de datos InfluxDB
- Dashboard Grafana
- API REST con Node.js
- App móvil React Native
- Servidor Raspberry Pi 4
- Integración con OpenWeatherMap
Sistema Completo AgTech
Código Principal del Sistema
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <time.h>
#include <DHT.h>
#include <BMP280.h>
#include <BH1750.h>
#include <SPIFFS.h>
// Configuración del sistema
#define DHT_PIN 22
#define DHT_TYPE DHT22
#define NUM_ZONES 4
#define FLOW_SENSOR_PIN 21
#define WATER_LEVEL_PIN 36
// Estructura para cada zona de cultivo
struct CropZone {
int moistureSensorPin;
int relayPin;
float currentMoisture;
float targetMoisture;
bool isIrrigating;
unsigned long irrigationStartTime;
unsigned long totalIrrigationTime;
String cropType;
float waterConsumption;
};
// Configuración de zonas
CropZone zones[NUM_ZONES] = {
{34, 26, 0, 65, false, 0, 0, "Tomate", 0},
{35, 27, 0, 55, false, 0, 0, "Lechuga", 0},
{32, 28, 0, 70, false, 0, 0, "Maíz", 0},
{33, 29, 0, 60, false, 0, 0, "Hierbas", 0}
};
// Sensores ambientales
DHT dht(DHT_PIN, DHT_TYPE);
BMP280 bmp;
BH1750 lightSensor;
// Variables del sistema
float ambientTemperature = 0;
float ambientHumidity = 0;
float atmosphericPressure = 0;
float lightIntensity = 0;
float waterLevel = 0;
volatile unsigned int flowPulseCount = 0;
float totalWaterUsed = 0;
// Configuración de red y servicios
const char* ssid = "AgTech_Network";
const char* password = "SecurePassword123";
const char* mqtt_server = "192.168.1.100";
const char* weather_api_key = "tu_api_key_openweather";
const char* ntp_server = "pool.ntp.org";
WiFiClient espClient;
PubSubClient client(espClient);
HTTPClient http;
// Variables de tiempo
struct tm timeinfo;
unsigned long lastSensorReading = 0;
unsigned long lastDataTransmission = 0;
unsigned long lastWeatherUpdate = 0;
// Configuración de agricultura de precisión
struct WeatherData {
float temperature;
float humidity;
float pressure;
float windSpeed;
float precipitation;
String description;
};
WeatherData currentWeather;
bool weatherDataAvailable = false;
void setup() {
Serial.begin(115200);
// Inicializar SPIFFS para almacenamiento
if (!SPIFFS.begin(true)) {
Serial.println("Error al montar SPIFFS");
return;
}
// Configurar pines
initializeHardware();
// Inicializar sensores
initializeSensors();
// Conectar a WiFi y servicios
connectToWiFi();
configureTime();
// Configurar MQTT
client.setServer(mqtt_server, 1883);
client.setCallback(mqttCallback);
// Configurar interrupciones
attachInterrupt(digitalPinToInterrupt(FLOW_SENSOR_PIN), flowPulseCounter, FALLING);
Serial.println("🌱 Sistema AgTech iniciado correctamente");
logEvent("Sistema iniciado");
}
void loop() {
// Mantener conexiones activas
maintainConnections();
// Lecturas de sensores (cada 30 segundos)
if (millis() - lastSensorReading >= 30000) {
readAllSensors();
processIrrigationLogic();
lastSensorReading = millis();
}
// Transmisión de datos (cada 5 minutos)
if (millis() - lastDataTransmission >= 300000) {
transmitSensorData();
updatePredictiveModel();
lastDataTransmission = millis();
}
// Actualización meteorológica (cada hora)
if (millis() - lastWeatherUpdate >= 3600000) {
updateWeatherData();
lastWeatherUpdate = millis();
}
// Procesar comandos MQTT
client.loop();
delay(100);
}
void initializeHardware() {
// Configurar pines de sensores de humedad
for (int i = 0; i < NUM_ZONES; i++) {
pinMode(zones[i].moistureSensorPin, INPUT);
pinMode(zones[i].relayPin, OUTPUT);
digitalWrite(zones[i].relayPin, LOW);
}
// Configurar otros pines
pinMode(FLOW_SENSOR_PIN, INPUT_PULLUP);
pinMode(WATER_LEVEL_PIN, INPUT);
Serial.println("Hardware inicializado");
}
void initializeSensors() {
// Inicializar DHT22
dht.begin();
// Inicializar BMP280
if (!bmp.begin()) {
Serial.println("Error al inicializar BMP280");
}
// Inicializar sensor de luz
if (!lightSensor.begin()) {
Serial.println("Error al inicializar BH1750");
}
Serial.println("Sensores inicializados");
}
void readAllSensors() {
// Leer sensores ambientales
ambientTemperature = dht.readTemperature();
ambientHumidity = dht.readHumidity();
atmosphericPressure = bmp.readPressure() / 100.0; // hPa
lightIntensity = lightSensor.readLightLevel();
waterLevel = analogRead(WATER_LEVEL_PIN) * (100.0 / 4095.0);
// Leer sensores de humedad de suelo
for (int i = 0; i < NUM_ZONES; i++) {
zones[i].currentMoisture = readSoilMoisture(zones[i].moistureSensorPin);
}
// Calcular flujo de agua
calculateWaterFlow();
Serial.printf("📊 Lecturas: T=%.1f°C, H=%.1f%%, P=%.1fhPa, L=%.0flux, Agua=%.1f%%\n",
ambientTemperature, ambientHumidity, atmosphericPressure,
lightIntensity, waterLevel);
}
float readSoilMoisture(int pin) {
const int AIR_VALUE = 3000;
const int WATER_VALUE = 1300;
// Promedio de 10 lecturas para estabilidad
long totalReading = 0;
for (int i = 0; i < 10; i++) {
totalReading += analogRead(pin);
delay(50);
}
int averageReading = totalReading / 10;
float moisturePercent = map(averageReading, AIR_VALUE, WATER_VALUE, 0, 100);
return constrain(moisturePercent, 0, 100);
}
void processIrrigationLogic() {
for (int i = 0; i < NUM_ZONES; i++) {
// Lógica inteligente considerando múltiples factores
float adjustedTarget = calculateAdjustedMoistureTarget(i);
if (shouldStartIrrigation(i, adjustedTarget)) {
startZoneIrrigation(i);
} else if (shouldStopIrrigation(i, adjustedTarget)) {
stopZoneIrrigation(i);
}
}
}
float calculateAdjustedMoistureTarget(int zoneIndex) {
float baseTarget = zones[zoneIndex].targetMoisture;
float adjustment = 0;
// Ajustar según temperatura (más calor = más agua)
if (ambientTemperature > 30) adjustment += 5;
else if (ambientTemperature > 25) adjustment += 2;
// Ajustar según humedad relativa (menos humedad = más agua)
if (ambientHumidity < 40) adjustment += 3;
else if (ambientHumidity < 60) adjustment += 1;
// Ajustar según intensidad lumínica (más luz = más agua)
if (lightIntensity > 50000) adjustment += 2;
else if (lightIntensity > 20000) adjustment += 1;
// Considerar pronóstico meteorológico
if (weatherDataAvailable && currentWeather.precipitation < 0.1) {
adjustment += 2; // Sin lluvia esperada
}
return constrain(baseTarget + adjustment, baseTarget - 5, baseTarget + 10);
}
bool shouldStartIrrigation(int zoneIndex, float targetMoisture) {
CropZone &zone = zones[zoneIndex];
// Verificar condiciones mínimas
if (zone.isIrrigating) return false;
if (waterLevel < 20) return false; // Nivel de agua muy bajo
if (zone.currentMoisture >= (targetMoisture - 2)) return false;
// Verificar horario óptimo (evitar horas de mayor calor)
if (!getLocalTime(&timeinfo)) return false;
int hour = timeinfo.tm_hour;
if (hour >= 10 && hour <= 16) return false; // Evitar 10AM - 4PM
return true;
}
void startZoneIrrigation(int zoneIndex) {
CropZone &zone = zones[zoneIndex];
zone.isIrrigating = true;
zone.irrigationStartTime = millis();
digitalWrite(zone.relayPin, HIGH);
Serial.printf("🌱 Iniciando riego en zona %d (%s) - Humedad: %.1f%%\n",
zoneIndex + 1, zone.cropType.c_str(), zone.currentMoisture);
// Enviar notificación MQTT
DynamicJsonDocument doc(300);
doc["zone"] = zoneIndex + 1;
doc["crop"] = zone.cropType;
doc["action"] = "start_irrigation";
doc["moisture_current"] = zone.currentMoisture;
doc["moisture_target"] = calculateAdjustedMoistureTarget(zoneIndex);
doc["timestamp"] = millis();
doc["ambient_temp"] = ambientTemperature;
doc["ambient_humidity"] = ambientHumidity;
String message;
serializeJson(doc, message);
client.publish("agtech/irrigation/status", message.c_str());
logEvent(String("Riego iniciado - Zona ") + String(zoneIndex + 1));
}
Troubleshooting y Diagnóstico
Problemas Comunes de Sensores
Lecturas Inconsistentes
Los sensores de humedad pueden dar lecturas erráticas debido a:
- Corrosión en sensores resistivos
- Variaciones de temperatura no compensadas
- Interferencia electromagnética
- Calibración incorrecta por tipo de suelo
Deriva de Calibración
La calibración se pierde con el tiempo debido a:
- Deposición de sales minerales
- Cambios en la composición del suelo
- Envejecimiento del sensor
Fallos del Sistema de Bombeo
Bomba No Arranca
Posibles causas:
- Falla en el relé de control
- Bomba bloqueada por sedimentos
- Bajo voltaje de alimentación
- Protección térmica activada
Funcionamiento en Seco
Protección crítica del sistema:
- Sensor de nivel de agua defectuoso
- Fuga en tuberías de succión
- Válvula de pie obstruida
// Sistema de diagnóstico y autodiagnóstico
class SystemDiagnostics {
private:
struct DiagnosticTest {
String testName;
bool (*testFunction)();
String errorMessage;
String solution;
};
static DiagnosticTest tests[];
static const int numTests = 8;
public:
static void runFullDiagnostic() {
Serial.println("\n🔍 Iniciando diagnóstico del sistema...");
bool systemHealthy = true;
for (int i = 0; i < numTests; i++) {
Serial.printf("Ejecutando: %s... ", tests[i].testName.c_str());
if (tests[i].testFunction()) {
Serial.println("✅ PASS");
} else {
Serial.println("❌ FAIL");
Serial.printf(" Error: %s\n", tests[i].errorMessage.c_str());
Serial.printf(" Solución: %s\n", tests[i].solution.c_str());
systemHealthy = false;
}
}
if (systemHealthy) {
Serial.println("\n✅ Sistema saludable - Todos los tests pasaron");
} else {
Serial.println("\n⚠️ Sistema requiere atención - Revisar errores");
}
}
// Tests específicos
static bool testWiFiConnection() {
return WiFi.status() == WL_CONNECTED;
}
static bool testMQTTConnection() {
return client.connected();
}
static bool testSensorsReading() {
bool allSensorsOK = true;
// Verificar sensores de humedad
for (int i = 0; i < NUM_ZONES; i++) {
int reading = analogRead(zones[i].moistureSensorPin);
if (reading < 100 || reading > 4000) {
allSensorsOK = false;
break;
}
}
// Verificar sensor DHT
float temp = dht.readTemperature();
float hum = dht.readHumidity();
if (isnan(temp) || isnan(hum)) {
allSensorsOK = false;
}
return allSensorsOK;
}
static bool testWaterLevel() {
return waterLevel > 15; // Mínimo 15% de nivel
}
static bool testRelayFunction() {
// Test rápido de todos los relés
bool allRelaysOK = true;
for (int i = 0; i < NUM_ZONES; i++) {
digitalWrite(zones[i].relayPin, HIGH);
delay(100);
// Aquí podrías agregar verificación de feedback del relé
digitalWrite(zones[i].relayPin, LOW);
}
return allRelaysOK;
}
static bool testPowerVoltage() {
// Leer voltaje de alimentación a través del ADC
int adcReading = analogRead(39); // Pin específico para voltaje
float voltage = (adcReading / 4095.0) * 3.3 * 4; // Factor de división
return (voltage > 11.0 && voltage < 14.5); // Rango aceptable para 12V
}
static bool testFlowSensor() {
unsigned int initialCount = flowPulseCount;
delay(5000); // Esperar 5 segundos
return (flowPulseCount > initialCount) || (totalWaterUsed == 0);
}
static bool testMemoryUsage() {
return ESP.getFreeHeap() > 50000; // Mínimo 50KB libre
}
};
// Inicialización de tests
SystemDiagnostics::DiagnosticTest SystemDiagnostics::tests[] = {
{"Conexión WiFi", testWiFiConnection, "WiFi desconectado", "Verificar SSID y contraseña"},
{"Conexión MQTT", testMQTTConnection, "Broker MQTT inaccesible", "Verificar servidor y credenciales"},
{"Lectura de Sensores", testSensorsReading, "Sensores con lecturas anómalas", "Verificar conexiones y calibración"},
{"Nivel de Agua", testWaterLevel, "Nivel de agua crítico", "Rellenar tanque de agua"},
{"Función de Relés", testRelayFunction, "Relé no responde", "Verificar conexiones y alimentación"},
{"Voltaje de Alimentación", testPowerVoltage, "Voltaje fuera de rango", "Verificar fuente de poder"},
{"Sensor de Flujo", testFlowSensor, "Sensor de flujo sin respuesta", "Verificar instalación del sensor"},
{"Memoria Disponible", testMemoryUsage, "Memoria insuficiente", "Reiniciar sistema o revisar código"}
};
// Función de mantenimiento preventivo
void performPreventiveMaintenance() {
static unsigned long lastMaintenance = 0;
const unsigned long maintenanceInterval = 86400000; // 24 horas
if (millis() - lastMaintenance >= maintenanceInterval) {
Serial.println("🔧 Iniciando mantenimiento preventivo...");
// Limpiar archivos temporales
cleanupTempFiles();
// Verificar y limpiar conexiones
WiFi.disconnect();
delay(1000);
connectToWiFi();
// Ejecutar diagnóstico completo
SystemDiagnostics::runFullDiagnostic();
// Reiniciar contadores
resetSystemCounters();
lastMaintenance = millis();
Serial.println("✅ Mantenimiento preventivo completado");
}
}
void cleanupTempFiles() {
// Limpiar archivos de log antiguos
File root = SPIFFS.open("/");
File file = root.openNextFile();
while (file) {
String fileName = file.name();
if (fileName.endsWith(".tmp") || fileName.startsWith("old_")) {
SPIFFS.remove(fileName);
Serial.printf("Eliminado: %s\n", fileName.c_str());
}
file = root.openNextFile();
}
}
void resetSystemCounters() {
totalWaterUsed = 0;
flowPulseCount = 0;
for (int i = 0; i < NUM_ZONES; i++) {
zones[i].totalIrrigationTime = 0;
zones[i].waterConsumption = 0;
}
}
Criterios de Evaluación
Precisión del Sistema
Criterios de Medición:
- Exactitud de sensores: ±2% de error
- Tiempo de respuesta: <30 segundos
- Repetibilidad: 95% de consistencia
- Calibración: Deriva <1% por mes
Puntuación:
Eficiencia Hídrica
Métricas de Eficiencia:
- Reducción de consumo: Mínimo 30%
- Uniformidad de riego: >85%
- Pérdidas por evaporación: <5%
- Tiempo de saturación: Optimizado
Puntuación:
Confiabilidad IoT
Criterios de Conectividad:
- Uptime del sistema: >99%
- Latencia de datos: <2 segundos
- Recuperación automática: Funcional
- Integridad de datos: 100%
Puntuación:
Evaluación Integral del Sistema
El sistema será evaluado considerando no solo la funcionalidad técnica, sino también el impacto en eficiencia agrícola, sostenibilidad ambiental y viabilidad económica. Se considerará la documentación técnica, la calidad del código, la escalabilidad del diseño y la innovación en la solución propuesta.
Referencias y Recursos Adicionales
Documentación Técnica
- ESP32 Official Documentation
- FAO Guidelines for Irrigation
- MQTT Protocol Specification
- Arduino Language Reference
Agricultura de Precisión
Sensores y Hardware
- Soil Moisture Sensor Guide
- Adafruit Sensor Library
- Last Minute Engineers Tutorials
- Random Nerd ESP32 Projects
IoT y Conectividad
Publicaciones Científicas Relevantes
1. López, M. et al. (2023). "Smart Irrigation Systems using IoT: A Comprehensive Review". Journal of Agricultural Engineering, 45(2), 123-145.
2. González, R. & Martínez, A. (2022). "Precision Agriculture with ESP32 Microcontrollers: Performance Analysis". Computers and Electronics in Agriculture, 189, 106-118.
3. Silva, P. et al. (2023). "Water Conservation through Smart Irrigation: A Mexican Case Study". Water Resources Management, 37(8), 2891-2905.