#include <LiquidCrystal_I2C.h>
#include <DHT.h>
// Configurar DHT22 (temperatura y humedad)
#define DHTPIN 7
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Variables para algoritmo multivariable
float historialHumedad[20];
float historialTemperatura[20];
float historialPresion[20];
int indice = 0;
int contador = 0;
unsigned long ultimoTiempo = 0;
// LEDs
int verde = 2;
int amarillo = 3;
int rojo = 4;
void setup() {
pinMode(verde, OUTPUT);
pinMode(amarillo, OUTPUT);
pinMode(rojo, OUTPUT);
// Inicializar Serial para debug
Serial.begin(9600);
lcd.init();
lcd.backlight();
lcd.print("RainSense-IoT");
lcd.setCursor(0, 1);
lcd.print("Iniciando...");
dht.begin();
// Inicializar historiales con valores realistas
for(int i = 0; i < 20; i++) {
historialHumedad[i] = 50.0; // Valor inicial realista
historialTemperatura[i] = 25.0;
historialPresion[i] = 1013.0;
}
// Secuencia de inicio
digitalWrite(verde, HIGH);
delay(500);
digitalWrite(amarillo, HIGH);
delay(500);
digitalWrite(rojo, HIGH);
delay(500);
digitalWrite(verde, LOW);
digitalWrite(amarillo, LOW);
digitalWrite(rojo, LOW);
delay(1000);
lcd.clear();
}
void loop() {
if (millis() - ultimoTiempo >= 2000) { // Reducido a 2 segundos para mejor respuesta
ultimoTiempo = millis();
// Leer DHT22 real
float temperaturaReal = dht.readTemperature();
float humedadReal = dht.readHumidity();
if (isnan(temperaturaReal) || isnan(humedadReal)) {
lcd.clear();
lcd.print("Error DHT22!");
lcd.setCursor(0, 1);
lcd.print("Revisar conexion");
delay(2000);
lcd.clear();
return;
}
// Simular presión atmosférica REALISTA
float presionSimulada = simularPresionRealista(temperaturaReal, humedadReal);
// DEBUG: Mostrar lectura actual
Serial.print("Lectura - T:");
Serial.print(temperaturaReal);
Serial.print("C H:");
Serial.print(humedadReal);
Serial.print("% P:");
Serial.println(presionSimulada);
// Almacenar datos para tendencias (siempre que sean válidos)
historialHumedad[indice] = humedadReal;
historialTemperatura[indice] = temperaturaReal;
historialPresion[indice] = presionSimulada;
indice = (indice + 1) % 20;
if (contador < 20) contador++;
// Mostrar en LCD
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temperaturaReal, 1);
lcd.print("C H:");
lcd.print(humedadReal, 0);
lcd.print("% ");
lcd.setCursor(0, 1);
lcd.print("P:");
lcd.print(presionSimulada, 0);
lcd.print("hPa ");
// ALGORITMO MULTIVARIABLE DE PREDICCIÓN
float tendenciaHumedad = calcularTendencia(historialHumedad);
float tendenciaPresion = calcularTendencia(historialPresion);
int nivelAlerta = predecirLluvia(temperaturaReal, humedadReal, presionSimulada,
tendenciaHumedad, tendenciaPresion);
// Mostrar estado y controlar LEDs
mostrarEstadoLCD(nivelAlerta);
controlarLEDs(nivelAlerta);
}
}
float simularPresionRealista(float temperatura, float humedad) {
// Presión base más realista (950-1050 hPa rango normal)
float presionBase;
if (humedad > 85) {
// Alta humedad -> baja presión (posible lluvia)
presionBase = 1000.0;
} else if (humedad > 70) {
// Humedad media -> presión media
presionBase = 1013.0;
} else {
// Baja humedad -> alta presión (cielo despejado)
presionBase = 1020.0;
}
// Variación aleatoria pequeña (±2 hPa)
float variacion = random(-20, 20) / 10.0;
// Ajustar por temperatura
if (temperatura < 20) {
presionBase += 2.0;
} else if (temperatura > 30) {
presionBase -= 2.0;
}
float presionFinal = presionBase + variacion;
// Asegurar que esté en rango realista
if (presionFinal < 950) presionFinal = 950;
if (presionFinal > 1050) presionFinal = 1050;
return presionFinal;
}
float calcularTendencia(float* historial) {
if (contador < 3) return 0; // Necesitamos al menos 3 puntos
float sumaX = 0, sumaY = 0, sumaXY = 0, sumaX2 = 0;
int puntos = min(contador, 20);
for (int i = 0; i < puntos; i++) {
float x = i;
float y = historial[i];
sumaX += x;
sumaY += y;
sumaXY += x * y;
sumaX2 += x * x;
}
float denominador = (puntos * sumaX2 - sumaX * sumaX);
if (denominador == 0) return 0; // Evitar división por cero
float tendencia = (puntos * sumaXY - sumaX * sumaY) / denominador;
// Limitar la tendencia a valores razonables
if (tendencia > 1.0) tendencia = 1.0;
if (tendencia < -1.0) tendencia = -1.0;
return tendencia;
}
int predecirLluvia(float temperatura, float humedad, float presion,
float tendenciaHumedad, float tendenciaPresion) {
int puntosRiesgo = 0;
// DEBUG: Mostrar valores en serial
Serial.print("Prediccion - H:");
Serial.print(humedad);
Serial.print(" P:");
Serial.print(presion);
Serial.print(" TendH:");
Serial.print(tendenciaHumedad, 3);
Serial.print(" TendP:");
Serial.println(tendenciaPresion, 3);
// SISTEMA DE PUNTOS MULTIVARIABLE
// Factor 1: Humedad alta
if (humedad > 85.0) puntosRiesgo += 3;
else if (humedad > 75.0) puntosRiesgo += 2;
else if (humedad > 65.0) puntosRiesgo += 1;
// Factor 2: Presión baja
if (presion < 1005.0) puntosRiesgo += 3;
else if (presion < 1010.0) puntosRiesgo += 2;
else if (presion < 1015.0) puntosRiesgo += 1;
// Factor 3: Tendencia de humedad creciente
if (tendenciaHumedad > 0.3) puntosRiesgo += 2;
else if (tendenciaHumedad > 0.1) puntosRiesgo += 1;
// Factor 4: Tendencia de presión decreciente
if (tendenciaPresion < -0.2) puntosRiesgo += 3;
else if (tendenciaPresion < -0.05) puntosRiesgo += 2;
// Factor 5: Temperatura estable o descendiendo
if (temperatura < 25.0) puntosRiesgo += 1;
Serial.print("Puntos Riesgo: ");
Serial.println(puntosRiesgo);
// EVALUACIÓN FINAL
if (puntosRiesgo >= 8 || (humedad > 90.0 && presion < 1010.0)) {
Serial.println(">>> ALERTA ROJA <<<");
return 2; // ALERTA ROJA
}
else if (puntosRiesgo >= 5) {
Serial.println(">>> ALERTA AMARILLA <<<");
return 1; // ALERTA AMARILLA
}
else {
Serial.println(">>> NORMAL <<<");
return 0; // NORMAL
}
}
void mostrarEstadoLCD(int nivelAlerta) {
lcd.setCursor(11, 1);
switch(nivelAlerta) {
case 2:
lcd.print("ALERTA");
break;
case 1:
lcd.print("AVISO ");
break;
case 0:
lcd.print("NORMAL");
break;
}
}
void controlarLEDs(int nivelAlerta) {
// Apagar todos primero
digitalWrite(verde, LOW);
digitalWrite(amarillo, LOW);
digitalWrite(rojo, LOW);
// Encender según alerta
switch(nivelAlerta) {
case 0: // NORMAL
digitalWrite(verde, HIGH);
break;
case 1: // AVISO
digitalWrite(amarillo, HIGH);
break;
case 2: // ALERTA
digitalWrite(rojo, HIGH);
break;
}
}