#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <IRremote.h>
// --- Control fuzzy básico ---
float fuzzy_control(float error) {
// Reglas simples: si el error es alto, calefactor ON fuerte, si bajo, calefactor OFF
if (error < -5) return 1.0; // Muy frío → calefactor encendido al máximo
else if (error < -2) return 0.7;
else if (error < 0) return 0.5;
else if (error < 2) return 0.3;
else return 0.0; // Demasiado caliente → calefactor apagado
}
// --- Definición de pines ---
#define DHTPIN 7
#define DHTBATPIN 8
#define DHTTYPE DHT22
#define LDR_PIN A0
#define AIR_PIN A1
#define WIND_SPEED_PIN A2
#define WIND_DIR_PIN A3
#define LED_PIN 3
#define BUZZER_PIN 5
#define HEATER_PIN 6
#define SERVO_PIN 9
#define PIN_RECEIVER 2
IRrecv receiver(PIN_RECEIVER);
// --- Inicialización de dispositivos ---
DHT dht(DHTPIN, DHTTYPE);
DHT dhtBat(DHTBATPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo servoCompuerta;
unsigned long lastBeepTime = 0;
bool buzzerState = false;
float TEMP_SETPOINT = 25.0;
const float HUM_SETPOINT = 80.0;
const float TEMP_DEADZONE = 3.0;
const float TEMP_OVERHEAT = 40.0;
void setup() {
Serial.begin(9600);
dht.begin();
dhtBat.begin();
lcd.init();
lcd.backlight();
pinMode(LED_PIN, OUTPUT);
pinMode(HEATER_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
servoCompuerta.attach(SERVO_PIN);
lcd.setCursor(0, 0);
lcd.print("Iniciando...");
delay(2000);
lcd.clear();
receiver.enableIRIn();
}
void loop() {
if (receiver.decode()) {
uint8_t cmd = receiver.decodedIRData.command;
if (cmd == 2) TEMP_SETPOINT += 1.0;
else if (cmd == 152) TEMP_SETPOINT -= 1.0;
receiver.resume();
}
float temp = dht.readTemperature();
float hum = dht.readHumidity();
float tempBat = dhtBat.readTemperature();
// --- AUTODIAGNÓSTICO: Rangos anómalos ---
if (isnan(temp) || temp < -10 || temp > 60) {
lcd.setCursor(0, 0); lcd.print("Err: T amb");
delay(1000);
return;
}
if (isnan(tempBat) || tempBat < -10 || tempBat > 60) {
lcd.setCursor(0, 0); lcd.print("Err: T bat");
delay(1000);
return;
}
if (abs(temp - tempBat) > 10) {
lcd.setCursor(0, 0); lcd.print("Dif Temp >10C");
delay(1000);
}
// --- SUPERVISIÓN INTELIGENTE: Ajuste automático del setpoint ---
float deltaTemp = temp - tempBat;
if (deltaTemp > 5) TEMP_SETPOINT += 0.2;
else if (deltaTemp < -5) TEMP_SETPOINT -= 0.2;
// --- Lectura otros sensores ---
int luz = analogRead(LDR_PIN);
int luzPct = map(luz, 0, 1023, 100, 0);
int airePct = map(analogRead(AIR_PIN), 0, 1023, 0, 100);
int vientoVel = map(analogRead(WIND_SPEED_PIN), 0, 1023, 0, 100);
int vientoDir = map(analogRead(WIND_DIR_PIN), 0, 1023, 0, 360);
// --- Iluminación y buzzer nocturno ---
unsigned long now = millis();
if (luzPct < 70) {
if (now - lastBeepTime >= (buzzerState ? 100 : 400)) {
buzzerState = !buzzerState;
lastBeepTime = now;
if (buzzerState) {
tone(BUZZER_PIN, 1000);
analogWrite(LED_PIN, 255);
} else {
noTone(BUZZER_PIN);
analogWrite(LED_PIN, 0);
}
}
} else {
noTone(BUZZER_PIN);
analogWrite(LED_PIN, 0);
}
// --- Control calefactor con fuzzy y zona muerta ---
float upperLimit = TEMP_SETPOINT + TEMP_DEADZONE;
float lowerLimit = TEMP_SETPOINT - TEMP_DEADZONE;
float error = TEMP_SETPOINT - tempBat;
float fuzzyOutput = fuzzy_control(error);
if (tempBat < lowerLimit) {
digitalWrite(HEATER_PIN, HIGH);
} else if (tempBat > upperLimit) {
digitalWrite(HEATER_PIN, LOW);
}
// --- Control compuerta ---
if (tempBat > TEMP_OVERHEAT) {
servoCompuerta.write(90);
} else {
servoCompuerta.write(0);
}
// --- Mostrar en LCD ---
mostrarLCD(temp, hum, luzPct, airePct, vientoVel, vientoDir, tempBat);
// --- Debug serial ---
Serial.print(" Temp: "); Serial.print(temp);
Serial.print(" Hum: "); Serial.print(hum);
Serial.print(" Set: "); Serial.print(TEMP_SETPOINT);
Serial.print(" Luz: "); Serial.print(luzPct);
Serial.print(" Aire: "); Serial.print(airePct);
Serial.print(" Vv: "); Serial.print(vientoVel);
Serial.print(" Dir: "); Serial.print(vientoDir);
Serial.print(" Tbat: "); Serial.print(tempBat);
Serial.print(" Heater: "); Serial.print(digitalRead(HEATER_PIN) ? "ON" : "OFF");
Serial.print(" Comp: "); Serial.println(tempBat > TEMP_OVERHEAT ? "Abierta" : "Cerrada");
delay(1000);
}
void mostrarLCD(float temp, float hum, int luz, int aire, int vv, int dir, float tempBat) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("T:"); lcd.print(temp, 1); lcd.print((char)223); lcd.print("C H:"); lcd.print(hum, 0); lcd.print("%");
lcd.setCursor(0, 1);
lcd.print("Set: "); lcd.print(TEMP_SETPOINT, 1); lcd.print((char)223); lcd.print("C");
delay(1500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Luz:"); lcd.print(luz); lcd.print("% Aire:"); lcd.print(aire); lcd.print("%");
delay(1500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Vv:"); lcd.print(vv); lcd.print("km/h");
lcd.setCursor(0, 1);
lcd.print("Dir:"); lcd.print(dir); lcd.print((char)223);
delay(1500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Tbat:"); lcd.print(tempBat, 1); lcd.print((char)223); lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Heater:"); lcd.print(tempBat < TEMP_SETPOINT ? "ON " : "OFF");
delay(1500);
}
Calidad Aire
Dirección viento
Velocidad viento
Sonido y luz
Resistencia Calefactora
Temperatura ambiente