#include <Arduino.h>
#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <LiquidCrystal.h>
// PINES
#define MQ135_PIN 34
#define FAN_PWM_PIN 25
#define RELAY_PIN 26
#define LED_GREEN 12
#define LED_YELLOW 13
#define LED_RED 14
#define BUTTON_PIN 27
#define LCD_RS 15
#define LCD_EN 2
#define LCD_D4 19
#define LCD_D5 18
#define LCD_D6 5
#define LCD_D7 4
// PWM
#define PWM_CHANNEL 0
#define PWM_FREQUENCY 25000
#define PWM_RESOLUTION 8
// UMBRALES
#define HUMIDITY_THRESHOLD_LOW 60
#define HUMIDITY_THRESHOLD_HIGH 75
#define TEMP_THRESHOLD 28
#define AIR_QUALITY_THRESHOLD 400
#define AUTO_OFF_DELAY 300000
#define SENSOR_READ_INTERVAL 2000
// OBJETOS
Adafruit_BME280 bme;
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
// VARIABLES GLOBALES
enum Mode { AUTO, MANUAL };
enum FanSpeed { FAN_OFF, FAN_LOW, FAN_MEDIUM, FAN_HIGH };
Mode currentMode = AUTO;
FanSpeed currentSpeed = FAN_OFF;
FanSpeed manualSpeed = FAN_OFF;
float humidity = 0;
float temperature = 0;
int airQuality = 0;
// ... (resto de variables globales)
bool buttonPressed = false;
bool lastButtonState = false;
unsigned long lastSensorRead = 0;
unsigned long fanStartTime = 0;
unsigned long lastButtonPress = 0;
const unsigned long debounceDelay = 200;
bool errorState = false;
unsigned long lastErrorBlink = 0;
bool errorLedState = false;
void setup() {
Serial.begin(115200);
lcd.begin(16, 2);
lcd.print("Extractor Bano");
lcd.setCursor(0, 1);
lcd.print("Iniciando...");
if (!bme.begin(0x76)) {
Serial.println("Error BME280");
lcd.clear();
lcd.print("ERROR SENSOR");
while (1) delay(10);
}
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_YELLOW, OUTPUT);
pinMode(LED_RED, OUTPUT);
pinMode(MQ135_PIN, INPUT);
digitalWrite(RELAY_PIN, LOW);
turnOffAllLEDs();
ledcSetup(PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);
ledcAttachPin(FAN_PWM_PIN, PWM_CHANNEL);
ledcWrite(PWM_CHANNEL, 0);
delay(2000);
lcd.clear();
updateDisplay();
}
void loop() {
checkButton();
if (millis() - lastSensorRead >= SENSOR_READ_INTERVAL) {
readSensors();
lastSensorRead = millis();
}
if (currentMode == AUTO) processAutoMode();
else processManualMode();
controlFan();
updateLEDs();
updateDisplay();
if (errorState) handleErrorState();
delay(100);
}
void readSensors() {
float newHumidity = bme.readHumidity();
float newTemperature = bme.readTemperature();
if (isnan(newHumidity) || isnan(newTemperature)) {
errorState = true;
return;
} else {
errorState = false;
humidity = newHumidity;
temperature = newTemperature;
}
airQuality = analogRead(MQ135_PIN);
}
void checkButton() {
bool buttonState = !digitalRead(BUTTON_PIN);
if (buttonState && !lastButtonState && (millis() - lastButtonPress > debounceDelay)) {
buttonPressed = true;
lastButtonPress = millis();
toggleMode();
}
lastButtonState = buttonState;
}
void processAutoMode() {
FanSpeed requiredSpeed = FAN_OFF;
if (humidity >= HUMIDITY_THRESHOLD_HIGH) requiredSpeed = FAN_HIGH;
else if (humidity >= HUMIDITY_THRESHOLD_LOW) requiredSpeed = FAN_MEDIUM;
if (temperature >= TEMP_THRESHOLD) requiredSpeed = max(requiredSpeed, FAN_MEDIUM);
if (airQuality >= AIR_QUALITY_THRESHOLD) requiredSpeed = max(requiredSpeed, FAN_LOW);
if (requiredSpeed != currentSpeed) {
if (requiredSpeed != FAN_OFF && currentSpeed == FAN_OFF) fanStartTime = millis();
currentSpeed = requiredSpeed;
}
if (currentSpeed != FAN_OFF && (millis() - fanStartTime >= AUTO_OFF_DELAY) &&
humidity < HUMIDITY_THRESHOLD_LOW && temperature < TEMP_THRESHOLD &&
airQuality < AIR_QUALITY_THRESHOLD) {
currentSpeed = FAN_OFF;
}
}
void processManualMode() {
if (buttonPressed) {
buttonPressed = false;
switch (manualSpeed) {
case FAN_OFF: manualSpeed = FAN_LOW; break;
case FAN_LOW: manualSpeed = FAN_MEDIUM; break;
case FAN_MEDIUM: manualSpeed = FAN_HIGH; break;
case FAN_HIGH: manualSpeed = FAN_OFF; break;
}
currentSpeed = manualSpeed;
if (currentSpeed != FAN_OFF) fanStartTime = millis();
}
}
void controlFan() {
int pwmValue = 0;
bool relayState = false;
switch (currentSpeed) {
case FAN_LOW: pwmValue = 85; relayState = true; break;
case FAN_MEDIUM: pwmValue = 170; relayState = true; break;
case FAN_HIGH: pwmValue = 255; relayState = true; break;
default: pwmValue = 0; relayState = false; break;
}
digitalWrite(RELAY_PIN, relayState);
ledcWrite(PWM_CHANNEL, pwmValue);
}
void updateLEDs() {
if (errorState) return;
turnOffAllLEDs();
switch (currentSpeed) {
case FAN_LOW: digitalWrite(LED_GREEN, HIGH); break;
case FAN_MEDIUM: digitalWrite(LED_YELLOW, HIGH); break;
case FAN_HIGH: digitalWrite(LED_RED, HIGH); break;
default: break;
}
}
void turnOffAllLEDs() {
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_RED, LOW);
}
void handleErrorState() {
if (millis() - lastErrorBlink >= 500) {
errorLedState = !errorLedState;
digitalWrite(LED_GREEN, errorLedState);
digitalWrite(LED_YELLOW, errorLedState);
digitalWrite(LED_RED, errorLedState);
lastErrorBlink = millis();
}
currentSpeed = FAN_OFF;
}
void updateDisplay() {
static unsigned long lastDisplayUpdate = 0;
if (millis() - lastDisplayUpdate < 1000) return;
lastDisplayUpdate = millis();
lcd.clear();
lcd.setCursor(0, 0);
if (currentMode == AUTO) lcd.print("Modo: AUTO ");
else lcd.print("Modo: MANUAL ");
switch (currentSpeed) {
case FAN_OFF: lcd.print("OFF"); break;
case FAN_LOW: lcd.print("BAJA"); break;
case FAN_MEDIUM: lcd.print("MEDIA"); break;
case FAN_HIGH: lcd.print("ALTA"); break;
}
lcd.setCursor(0, 1);
if (errorState) {
lcd.print("ERROR SENSORES");
} else {
char buffer[17];
snprintf(buffer, sizeof(buffer), "H:%d%% T:%dC A:%d", (int)humidity, (int)temperature, airQuality);
lcd.print(buffer);
}
}
void toggleMode() {
if (currentMode == AUTO) {
currentMode = MANUAL;
manualSpeed = FAN_OFF;
currentSpeed = FAN_OFF;
} else {
currentMode = AUTO;
}
}