#include <Wire.h>
#include <Adafruit_INA219.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
// INA219
#define SDA_PIN 21
#define SCL_PIN 20
#define LCD_BUTTON_PIN 33
Adafruit_INA219 ina219;
LiquidCrystal_I2C lcd(0x27, 16, 2);
// DHT22
#define DHT_PIN 4
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
// PIR
#define PIR_PIN 17
// RELÉS
#define RELAY_FAN_PIN 18
#define RELAY_LIGHT_PIN 19
// TEMPERATURA LÍMITE
#define TEMPERATURE_LIMIT 28.0
// TIEMPO DE MEDICIÓN
unsigned long previousMillis = 0;
const unsigned long MEASUREMENT_INTERVAL = 2000;
// TIEMPOS DE FUNCIONAMIENTO
unsigned long fanRuntime = 0;
unsigned long lightRuntime = 0;
unsigned long totalRuntime = 0;
// ENERGÍA
double energyWh = 0.0;
// VARIABLES
bool lastButtonState = HIGH;
bool buttonState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long DEBOUNCE_DELAY = 50;
uint8_t lcdScreen = 0;
bool lcdNeedsUpdate = true;
// Últimos valores medidos
float lastTemperature = 0.0;
float lastHumidity = 0.0;
bool lastFanOn = false;
bool lastLightOn = false;
float lastVoltage = 0.0;
float lastCurrentA = 0.0;
float lastPowerW = 0.0;
double lastEnergyWh = 0.0;
// SETUP
void updateINA219LoadState(bool fanOn, bool lightOn) {
uint8_t state = 0;
if (fanOn) {state |= 0x01;}
if (lightOn) {state |= 0x02;}
Wire.beginTransmission(0x40);
Wire.write(0x06); // Registro personalizado
Wire.write(state); // Estado de las cargas
Wire.endTransmission();
}
void updateLCD (float temperature, float humidity, bool fanOn, bool lightOn, float voltage, float currentA, float powerW, double energyWh) {
lcd.clear();
switch (lcdScreen) {
// PANTALLA 1 - AMBIENTE
case 0:
lcd.setCursor(0, 0); lcd.print("TEMP: "); lcd.print(temperature, 1); lcd.print(" C");
lcd.setCursor(0, 1); lcd.print("HUM: "); lcd.print(humidity, 0); lcd.print(" %");
break;
// PANTALLA 2 - CARGAS
case 1:
lcd.setCursor(0, 0); lcd.print("VENT: "); lcd.print(fanOn ? "ON" : "OFF");
lcd.setCursor(0, 1); lcd.print("LUZ: "); lcd.print(lightOn ? "ON" : "OFF");
break;
// PANTALLA 3 - VOLTAJE / CORRIENTE
case 2:
lcd.setCursor(0, 0); lcd.print("V: "); lcd.print(voltage, 2); lcd.print(" V");
lcd.setCursor(0, 1); lcd.print("I: "); lcd.print(currentA, 2); lcd.print(" A");
break;
// PANTALLA 4 - POTENCIA / ENERGIA
case 3:
lcd.setCursor(0, 0); lcd.print("P: "); lcd.print(powerW, 2); lcd.print(" W");
lcd.setCursor(0, 1); lcd.print("E: "); lcd.print(energyWh, 2); lcd.print(" Wh");
break;
}
}
void checkLCDButton() {
bool reading = digitalRead(LCD_BUTTON_PIN);
if (reading != lastButtonState) {lastDebounceTime = millis();}
if ((millis() - lastDebounceTime) > DEBOUNCE_DELAY) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == LOW) {
lcdScreen++;
if (lcdScreen > 3) {
lcdScreen = 0;
}
lcdNeedsUpdate = true;
Serial.print("Pantalla seleccionada: ");
Serial.println(lcdScreen + 1);
}
}
}
lastButtonState = reading;
}
void setup() {
Serial.begin(115200);
delay(1000);
// I2C
Wire.begin(SDA_PIN, SCL_PIN);
// LCD 16x2 I2C
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0); lcd.print("Sistema listo");
lcd.setCursor(0, 1); lcd.print("Iniciando...");
pinMode(LCD_BUTTON_PIN, INPUT_PULLUP);
// INA219
if (!ina219.begin()) {
Serial.println("ERROR: INA219 no encontrado.");
while (true) {
delay(100);
}
}
ina219.setCalibration_32V_2A();
// DHT22
dht.begin();
// PIR
pinMode(PIR_PIN, INPUT);
// RELÉS
pinMode(RELAY_FAN_PIN, OUTPUT);
pinMode(RELAY_LIGHT_PIN, OUTPUT);
// Ambos apagados
digitalWrite(RELAY_FAN_PIN, LOW);
digitalWrite(RELAY_LIGHT_PIN, LOW);
// TEMPORIZADOR
previousMillis = millis();
//Serial.println();
//Serial.println("======================================");
//Serial.println(" SISTEMA DE MONITOREO");
//Serial.println("======================================");
//Serial.println("INA219 OK");
//Serial.println("DHT22 OK");
//Serial.println("PIR OK");
//Serial.println("Sistema iniciado.");
//Serial.println();
}
// LOOP
void loop() {
checkLCDButton();
unsigned long currentMillis = millis();
// Actualizar LCD inmediatamente si se pulsó el botón
if (lcdNeedsUpdate) {
updateLCD(lastTemperature, lastHumidity, lastFanOn, lastLightOn, lastVoltage, lastCurrentA, lastPowerW, lastEnergyWh);
lcdNeedsUpdate = false;
}
// Esperar para realizar una nueva medición
if (currentMillis - previousMillis < MEASUREMENT_INTERVAL) {
return;
}
// Tiempo transcurrido desde la última medición
unsigned long elapsedMillis = currentMillis - previousMillis;
previousMillis = currentMillis;
// DHT22
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
Serial.println("ERROR: DHT22 no responde.");
return;
}
// PIR
int motion = digitalRead(PIR_PIN);
// VENTILACIÓN
bool fanOn = false;
if (temperature >= TEMPERATURE_LIMIT) {
digitalWrite(RELAY_FAN_PIN, HIGH);
fanOn = true;
} else {
digitalWrite(RELAY_FAN_PIN, LOW);
fanOn = false;
}
// ILUMINACIÓN
bool lightOn = false;
if (motion == HIGH) {
digitalWrite(RELAY_LIGHT_PIN, HIGH);
lightOn = true;
} else {
digitalWrite(RELAY_LIGHT_PIN, LOW);
lightOn = false;
}
updateINA219LoadState(fanOn, lightOn);
// TIEMPO DE FUNCIONAMIENTO
if (fanOn) {fanRuntime += elapsedMillis;}
if (lightOn) {lightRuntime += elapsedMillis;}
if (fanOn || lightOn) {
totalRuntime += elapsedMillis;
}
// LECTURA INA219
float voltage = ina219.getBusVoltage_V();
float currentmA = ina219.getCurrent_mA();
float powermW = ina219.getPower_mW();
// Conversión
float currentA = currentmA / 1000.0;
float powerW = powermW / 1000.0;
// ENERGÍA
double elapsedHours = elapsedMillis / 3600000.0;
energyWh += powerW * elapsedHours;
double energyKWh = energyWh / 1000.0;
// TIEMPOS
unsigned long fanSeconds = fanRuntime / 1000;
unsigned long lightSeconds = lightRuntime / 1000;
unsigned long totalSeconds = totalRuntime / 1000;
// MONITOR SERIAL
Serial.println("--------------------------------------");
// AMBIENTE
Serial.print("Temperatura: "); Serial.print(temperature, 1); Serial.println(" C");
Serial.print("Humedad: "); Serial.print(humidity, 0); Serial.println(" %");
Serial.print("Movimiento: "); Serial.println(motion == HIGH ? "SI" : "NO");
// CARGAS
Serial.print("Ventilacion: "); Serial.println(fanOn ? "ON" : "OFF");
Serial.print("Iluminacion: "); Serial.println(lightOn ? "ON" : "OFF");
// CONSUMO ELÉCTRICO
Serial.println();
Serial.print("Voltaje: "); Serial.print(voltage, 3); Serial.println(" V");
Serial.print("Corriente: "); Serial.print(currentA, 3); Serial.println(" A");
Serial.print("Potencia: "); Serial.print(powerW, 3); Serial.println(" W");
// ENERGÍA
Serial.print("Energia: "); Serial.print(energyWh, 5); Serial.println(" Wh");
Serial.print("Energia: "); Serial.print(energyKWh, 7); Serial.println(" kWh");
// TIEMPO
Serial.println();
Serial.print("Tiempo ventilacion: "); Serial.print(fanSeconds); Serial.println(" s");
Serial.print("Tiempo iluminacion: "); Serial.print(lightSeconds); Serial.println(" s");
Serial.print("Tiempo total cargas: "); Serial.print(totalSeconds); Serial.println(" s");
Serial.println("--------------------------------------");
updateLCD(temperature, humidity, fanOn, lightOn, voltage, currentA, powerW, energyWh);
lastTemperature = temperature;
lastHumidity = humidity;
lastFanOn = fanOn;
lastLightOn = lightOn;
lastVoltage = voltage;
lastCurrentA = currentA;
lastPowerW = powerW;
lastEnergyWh = energyWh;
}