Buenas noches,
tengo una código para ESP32 que consiste en un sistema de amanecer/anochecer con pantalla 2004 i2c, 6 botones (arriba, abajo, izq., der., Ok e Inspección), DHT21, 2 reles y RTC.
Mi problema viene cuando al cargar el codigo se ve la pantalla como si estuvieran los botones pulsados y no para de moverse el cursor por todo el menú y demás. No se queda en la pantalla principal donde tiene que mostrar la información de datos y el acceso al Menú.
Os cuelgo el código para que veais lo que pasa.
Si pudierais echarme una mano os lo agradecería.
#include <Wire.h>
#include <RTClib.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#define DHTPIN 4
#define DHTTYPE DHT21
#define BUTTON_PIN 16 // Botón físico principal
#define RELAY1_PIN 17
#define RELAY2_PIN 5
#define LED_STRIP1_PIN 13
#define LED_STRIP2_PIN 12
#define LED_STRIP3_PIN 14
#define LED_STRIP4_PIN 27
#define LED_MOON_PIN 26
// Botones del joystick digital
#define BUTTON_UP_PIN 32
#define BUTTON_DOWN_PIN 33
#define BUTTON_LEFT_PIN 25
#define BUTTON_RIGHT_PIN 23
#define BUTTON_OK_PIN 18
#define NUM_MENU_ITEMS 5 // Define el número de ítems del menú
unsigned long lastDebounceTime = 0; // Para llevar el tiempo del último cambio
unsigned long lastButtonPress = 0; // Para almacenar el último momento de pulsación
// Estados de los botones
int lastButtonStateUp = HIGH;
int buttonStateUp = HIGH;
int lastButtonStateDown = HIGH;
int buttonStateDown = HIGH;
int lastButtonStateLeft = HIGH;
int buttonStateLeft = HIGH;
int lastButtonStateRight = HIGH;
int buttonStateRight = HIGH;
int lastButtonStateOK = HIGH;
int buttonStateOK = HIGH;
int lastButtonStateButton = HIGH;
int buttonStateButton = HIGH;
// Constantes
const unsigned long DEBOUNCE_DELAY = 200;
const int EEPROM_ADDRESS = 0;
const char* menuNames[] = { "Hora", "Amanecer", "Anochecer", "Luz Luna", "Salidas Aux." };
// Caracteres personalizados para iconos
byte sunIcon[8] = {
0b00000,
0b01010,
0b11111,
0b01010,
0b00000,
0b00000,
0b00000,
0b00000
};
byte dropIcon[8] = {
0b00100,
0b01110,
0b11111,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000
};
byte moonIcon[8] = {
0b00111,
0b01100,
0b11000,
0b11000,
0b11000,
0b01100,
0b00111,
0b00000
};
byte thermometerIcon[8] = {
0b00100,
0b01010,
0b01010,
0b01010,
0b01010,
0b01110,
0b01110,
0b00100
};
// Inicialización de componentes
DHT dht(DHTPIN, DHTTYPE);
RTC_DS3231 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Estructura para guardar la configuración en la EEPROM
struct Config {
bool moonLightEnabled;
int moonLightIntensity;
bool relay1Enabled;
bool relay2Enabled;
int relay1StartHour;
int relay1EndHour;
int relay2StartHour;
int relay2EndHour;
int dawnDuration;
int duskDuration;
int dawnStartHour;
int dawnStartMinute;
int duskStartHour;
int duskStartMinute;
bool autoAdjustEnabled;
int autoAdjustMinutes;
int autoAdjustMaxHour;
};
Config config;
// Definir las variables para los estados
bool isMainScreen = true; // Variable para saber si estamos en la pantalla principal o en el menú
bool inMenu = false;
// Definir variables para el debounce de cada botón
unsigned long lastDebounceTimeUp = 0;
unsigned long lastDebounceTimeDown = 0;
unsigned long lastDebounceTimeLeft = 0;
unsigned long lastDebounceTimeRight = 0;
unsigned long lastDebounceTimeOK = 0;
unsigned long lastDebounceTimeButton = 0;
// Variables globales
int menuPosition = 0;
int subMenuPosition = 0;
bool inSubMenu = false;
bool screenUpdated = false;
unsigned long lastDHTTime = 0;
unsigned long dhtInterval = 2000; // Intervalo de 2 segundos
unsigned long lastScreenUpdateTime = 0;
unsigned long screenUpdateInterval = 3000; // 3 segundos
bool inspectionNight = false; // Para llevar un control del estado de la inspección nocturna
bool buttonPressed = false; // Para controlar el estado del botón
bool inspectionModeActive = false; // Indica si el modo de inspección nocturna está activo
// Variables para la hora, temperatura y humedad
String currentTime = "00:00:00"; // Iniciar como cadena de ejemplo
float temperature = 0.0; // Temperatura en grados Celsius
float humidity = 0.0; // Humedad en porcentaje
// Declaraciones de funciones
void loadConfig();
void displayMainScreen(DateTime now, float humidity, float temperature);
void handleMenu();
void controlRelay1(float humidity, DateTime now);
void controlRelay2(DateTime now);
void controlMoonLightLED(DateTime now);
void controlDawnDuskLEDs(DateTime now);
void handleAutoAdjust(DateTime now);
void quickSunrise();
void quickSunset();
void adjustValue(bool increment);
void displaySubMenu();
void displayDateTimeSubMenu();
void displayDawnSubMenu();
void displayDuskSubMenu();
void displayMoonLightSubMenu();
void displayAuxOutputsSubMenu();
void adjustDate(bool increment);
void adjustTime(bool increment);
void adjustDawnSettings(bool increment);
void adjustDuskSettings(bool increment);
void adjustMoonLightSettings(bool increment);
void adjustAuxOutputsSettings(bool increment);
void saveConfig();
void setLEDStripsBrightness(int brightness);
int getSubMenuSize(int menuPosition);
void updateScreen();
void changeMenuUp();
void changeMenuDown();
void navigateLeft();
void navigateRight();
void selectOption();
void toggleNightInspection();
bool isReturnOptionSelected(int menuPos, int subMenuPos);
void handleSubMenu();
void displayMainMenu();
void setup() {
Serial.begin(921600);
dht.begin();
if (!rtc.begin()) {
Serial.println("No se pudo encontrar el RTC");
while (1)
;
}
if (rtc.lostPower()) {
Serial.println("RTC perdió energía, ¡vamos a ajustar la hora!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
lcd.init();
lcd.backlight();
lcd.createChar(0, sunIcon); // Crear el carácter personalizado para el sol
lcd.createChar(1, dropIcon); // Crear el carácter personalizado para la gota
lcd.createChar(2, moonIcon); // Crear el carácter personalizado para la luna
lcd.createChar(3, thermometerIcon); // Crear el carácter personalizado para el termómetro
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(RELAY1_PIN, OUTPUT);
pinMode(RELAY2_PIN, OUTPUT);
pinMode(LED_STRIP1_PIN, OUTPUT);
pinMode(LED_STRIP2_PIN, OUTPUT);
pinMode(LED_STRIP3_PIN, OUTPUT);
pinMode(LED_STRIP4_PIN, OUTPUT);
pinMode(LED_MOON_PIN, OUTPUT);
pinMode(BUTTON_UP_PIN, INPUT_PULLUP);
pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP);
pinMode(BUTTON_LEFT_PIN, INPUT_PULLUP);
pinMode(BUTTON_RIGHT_PIN, INPUT_PULLUP);
pinMode(BUTTON_OK_PIN, INPUT_PULLUP);
// Cargar configuración desde la EEPROM
loadConfig();
// Mostrar pantalla principal al arrancar
updateScreen();
}
void loop() {
DateTime now = rtc.now();
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
unsigned long currentMillis = millis();
if (currentMillis - lastDHTTime >= dhtInterval) {
lastDHTTime = currentMillis;
float newHumidity = dht.readHumidity();
float newTemperature = dht.readTemperature();
// Solo actualizamos los valores si han cambiado
if (newHumidity != humidity || newTemperature != temperature) {
humidity = newHumidity;
temperature = newTemperature;
screenUpdated = true; // Indicamos que los datos han cambiado y necesitamos actualizar la pantalla
}
}
// Leemos el estado del botón
if (digitalRead(BUTTON_PIN) == LOW) { // El botón está presionado (porque usamos pull-up)
if (!buttonPressed) { // Si el botón no estaba presionado antes
buttonPressed = true;
if (!inspectionModeActive) {
// Si el modo de inspección no está activo, hacemos un amanecer rápido
quickSunrise();
inspectionModeActive = true; // Activamos el modo de inspección
} else {
// Si el modo de inspección está activo, hacemos un anochecer rápido
quickSunset();
inspectionModeActive = false; // Desactivamos el modo de inspección después del anochecer
}
}
} else {
buttonPressed = false; // Reseteamos el estado del botón cuando no está presionado
}
// Manejar el menú y submenús
handleMenu();
// Control de relés
controlRelay1(humidity, now);
controlRelay2(now);
// Control de luz lunar y amanecer/anochecer
controlMoonLightLED(now);
controlDawnDuskLEDs(now);
// Ajuste automático si está habilitado
handleAutoAdjust(now);
handleButtons();
// Código para actualizar la pantalla y otros procesos
if (screenUpdated) {
updateScreen(); // Actualiza la pantalla si es necesario
}
delay(100);
// Depuración de lecturas de botones
Serial.print("Botón UP: ");
Serial.println(digitalRead(BUTTON_UP_PIN));
Serial.print("Botón DOWN: ");
Serial.println(digitalRead(BUTTON_DOWN_PIN));
Serial.print("Botón LEFT: ");
Serial.println(digitalRead(BUTTON_LEFT_PIN));
Serial.print("Botón RIGHT: ");
Serial.println(digitalRead(BUTTON_RIGHT_PIN));
Serial.print("Botón OK: ");
Serial.println(digitalRead(BUTTON_OK_PIN));
delay(500); // Pequeña pausa para evitar saturar el monitor serial
}
void handleButtons() {
int readingUp = digitalRead(BUTTON_UP_PIN);
int readingDown = digitalRead(BUTTON_DOWN_PIN);
int readingLeft = digitalRead(BUTTON_LEFT_PIN);
int readingRight = digitalRead(BUTTON_RIGHT_PIN);
int readingOK = digitalRead(BUTTON_OK_PIN);
int readingInspeccion = digitalRead(BUTTON_PIN);
// Button UP (Arriba)
if (readingUp != lastButtonStateUp) {
lastDebounceTimeUp = millis(); // Se actualiza el tiempo de debounce
}
if ((millis() - lastDebounceTimeUp) > DEBOUNCE_DELAY) {
if (readingUp != buttonStateUp) {
buttonStateUp = readingUp; // Actualizamos el estado del botón
if (buttonStateUp == LOW) {
changeMenuUp(); // Llamamos a la función que manejará la acción de "Arriba"
}
}
}
lastButtonStateUp = readingUp; // Guardamos el estado del botón actual
// Button DOWN (Abajo)
if (readingDown != lastButtonStateDown) {
lastDebounceTimeDown = millis(); // Actualizamos el tiempo de debounce
}
if ((millis() - lastDebounceTimeDown) > DEBOUNCE_DELAY) {
if (readingDown != buttonStateDown) {
buttonStateDown = readingDown;
if (buttonStateDown == LOW) {
changeMenuDown(); // Llamamos a la función que manejará la acción de "Abajo"
}
}
}
lastButtonStateDown = readingDown;
// Button LEFT (Izquierda)
if (readingLeft != lastButtonStateLeft) {
lastDebounceTimeLeft = millis();
}
if ((millis() - lastDebounceTimeLeft) > DEBOUNCE_DELAY) {
if (readingLeft != buttonStateLeft) {
buttonStateLeft = readingLeft;
if (buttonStateLeft == LOW) {
navigateLeft(); // Acción para "Izquierda"
}
}
}
lastButtonStateLeft = readingLeft;
// Button RIGHT (Derecha)
if (readingRight != lastButtonStateRight) {
lastDebounceTimeRight = millis();
}
if ((millis() - lastDebounceTimeRight) > DEBOUNCE_DELAY) {
if (readingRight != buttonStateRight) {
buttonStateRight = readingRight;
if (buttonStateRight == LOW) {
navigateRight(); // Acción para "Derecha"
}
}
}
lastButtonStateRight = readingRight;
// Button OK
if (readingOK != lastButtonStateOK) {
lastDebounceTimeOK = millis();
}
if ((millis() - lastDebounceTimeOK) > DEBOUNCE_DELAY) {
if (readingOK != buttonStateOK) {
buttonStateOK = readingOK;
if (buttonStateOK == LOW) {
selectOption(); // Acción para "OK"
}
}
}
lastButtonStateOK = readingOK;
// Button Inspección Nocturna
if (readingInspeccion != lastButtonStateButton) {
lastDebounceTimeButton = millis();
}
if ((millis() - lastDebounceTimeButton) > DEBOUNCE_DELAY) {
if (readingInspeccion != buttonStateButton) {
buttonStateButton = readingInspeccion;
if (buttonStateButton == LOW) {
toggleNightInspection(); // Acción para "Inspección Nocturna"
}
}
}
lastButtonStateButton = readingInspeccion;
}
void changeMenuUp() {
if (menuPosition > 0) {
menuPosition--; // Mueve hacia arriba en el menú
updateScreen(); // Actualiza la pantalla
}
}
void changeMenuDown() {
if (menuPosition < NUM_MENU_ITEMS - 1) {
menuPosition++; // Mueve hacia abajo en el menú
updateScreen(); // Actualiza la pantalla
}
}
void navigateLeft() {
subMenuPosition = (subMenuPosition - 1 + getSubMenuSize(menuPosition)) % getSubMenuSize(menuPosition);
screenUpdated = false;
}
void navigateRight() {
subMenuPosition = (subMenuPosition + 1) % getSubMenuSize(menuPosition);
screenUpdated = false;
}
void selectOption() {
inSubMenu = !inSubMenu; // Alterna entre el menú principal y el submenú
if (!inSubMenu) {
subMenuPosition = 0; // Reiniciar la posición del submenú al salir
}
screenUpdated = false;
}
void toggleNightInspection() {
inspectionNight = !inspectionNight;
screenUpdated = false;
}
void updateScreen() {
unsigned long currentMillis = millis();
// Si ha pasado el intervalo de actualización de pantalla o si los datos han cambiado
if (currentMillis - lastScreenUpdateTime >= screenUpdateInterval || screenUpdated) {
lastScreenUpdateTime = currentMillis; // Actualiza el tiempo de la última actualización
// Mostrar información en la pantalla LCD
DateTime now = rtc.now();
displayMainScreen(now, humidity, temperature);
// Restablecer la variable de actualización
screenUpdated = false; // Se restablece para evitar actualizaciones repetidas innecesarias
}
}
void displayMainScreen(DateTime now, float humidity, float temperature) {
// Limpiar la pantalla antes de actualizar
lcd.clear();
// Mostrar la hora en formato HH:MM:SS
lcd.setCursor(0, 0);
lcd.print(now.hour());
lcd.print(":");
lcd.print(now.minute());
lcd.print(":");
lcd.print(now.second());
// Mostrar la fecha (solo año y mes, por ejemplo)
lcd.setCursor(0, 1);
lcd.print(now.year());
lcd.print("-");
lcd.print(now.month());
lcd.print("-");
lcd.print(now.day());
// Mostrar la temperatura y humedad
lcd.setCursor(0, 2);
lcd.write(byte(3)); // Icono de termómetro
lcd.print("Temp: ");
lcd.print(temperature);
lcd.print(" C");
lcd.setCursor(0, 3);
lcd.write(byte(1)); // Icono de gota
lcd.print("Hum: ");
lcd.print(humidity);
lcd.print(" %");
// Mostrar el acceso al menú
lcd.setCursor(0, 3); // Esta es la misma línea de humedad, si quieres un ícono diferente o texto puedes modificar esto
lcd.setCursor(12, 3); // Posicionar un poco más a la derecha
lcd.print("> Menu"); // Indicación de acceso al menú
}
void handleMenu() {
if (digitalRead(BUTTON_OK_PIN) == LOW) {
inMenu = !inMenu; // Cambiar entre la pantalla principal y el menú
delay(200); // Pequeña pausa para evitar rebotes
}
// Si estamos en el menú, se pueden manejar las opciones del menú
if (inMenu) {
if (digitalRead(BUTTON_UP_PIN) == LOW) {
menuPosition = (menuPosition - 1 + NUM_MENU_ITEMS) % NUM_MENU_ITEMS;
delay(200); // Pausa para evitar rebotes
}
if (digitalRead(BUTTON_DOWN_PIN) == LOW) {
menuPosition = (menuPosition + 1) % NUM_MENU_ITEMS;
delay(200); // Pausa para evitar rebotes
}
}
}
void handleSubMenu() {
if (digitalRead(BUTTON_LEFT_PIN) == LOW && millis() - lastDebounceTime > DEBOUNCE_DELAY) {
lastDebounceTime = millis();
adjustValue(false); // Ajustar valor hacia abajo
screenUpdated = false; // Marcar que la pantalla necesita actualizarse
}
if (digitalRead(BUTTON_RIGHT_PIN) == LOW && millis() - lastDebounceTime > DEBOUNCE_DELAY) {
lastDebounceTime = millis();
adjustValue(true); // Ajustar valor hacia arriba
screenUpdated = false; // Marcar que la pantalla necesita actualizarse
}
displaySubMenu(); // Mostrar el submenú actualizado
}
bool isReturnOptionSelected(uint8_t menu, uint8_t sub) {
// Si "Volver" es la última opción en cada submenú:
return sub == getSubMenuSize(menu) - 1;
}
// Definición de la función isReturnOptionSelected
bool isReturnOptionSelected(int menuPos, int subMenuPos) {
// Lógica que determine si la opción de retorno (volver) ha sido seleccionada
// Por ejemplo, podemos comprobar si las posiciones del menú coinciden
if (menuPos == 0 && subMenuPos == 0) {
return true;
} else {
return false;
}
}
int getSubMenuSize(int menuPosition) {
switch (menuPosition) {
case 0: return 2; // Fecha y Hora
case 1: return 6; // Amanecer
case 2: return 6; // Anochecer
case 3: return 2; // Luz Luna
case 4: return 6; // Salidas Auxiliares
default: return 0;
}
}
void displayMainMenu() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Menu Principal");
lcd.setCursor(0, 1);
lcd.print("1. Amanecer");
lcd.setCursor(0, 2);
lcd.print("2. Anochecer");
lcd.setCursor(0, 3);
lcd.print("3. Luz Luna");
lcd.setCursor(0, 4);
lcd.print("4. Salidas Aux");
lcd.setCursor(0, 5);
lcd.print("5. Ajustes");
}
void displaySubMenu() {
lcd.clear();
lcd.setCursor(0, 0);
switch (menuPosition) {
case 0:
lcd.print("Fecha y Hora");
displayDateTimeSubMenu();
break;
case 1:
lcd.print("Amanecer");
displayDawnSubMenu();
break;
case 2:
lcd.print("Anochecer");
displayDuskSubMenu();
break;
case 3:
lcd.print("Luz Luna");
displayMoonLightSubMenu();
break;
case 4:
lcd.print("Salidas Aux.");
displayAuxOutputsSubMenu();
break;
}
}
void displayDateTimeSubMenu() {
lcd.setCursor(0, 1);
switch (subMenuPosition) {
case 0:
lcd.print(">Ajustar Fecha");
break;
case 1:
lcd.print(">Ajustar Hora");
break;
}
}
void displayDawnSubMenu() {
lcd.setCursor(0, 1);
switch (subMenuPosition) {
case 0:
lcd.print(">Duracion: ");
lcd.print(config.dawnDuration);
lcd.print(" min");
break;
case 1:
lcd.print(">Hora Inicio: ");
lcd.print(config.dawnStartHour);
lcd.print(":");
lcd.print(config.dawnStartMinute);
break;
case 2:
lcd.print(">Auto Ajuste: ");
lcd.print(config.autoAdjustEnabled ? "Si" : "No");
break;
case 3:
lcd.print(">Minutos Ajuste: ");
lcd.print(config.autoAdjustMinutes);
break;
case 4:
lcd.print(">Hora Max Ajuste: ");
lcd.print(config.autoAdjustMaxHour);
lcd.print(":00");
break;
case 5:
lcd.print(">Activar Ajuste: ");
lcd.print(config.autoAdjustEnabled ? "Si" : "No");
break;
}
}
void displayDuskSubMenu() {
lcd.setCursor(0, 1);
switch (subMenuPosition) {
case 0:
lcd.print(">Duracion: ");
lcd.print(config.duskDuration);
lcd.print(" min");
break;
case 1:
lcd.print(">Hora Inicio: ");
lcd.print(config.duskStartHour);
lcd.print(":");
lcd.print(config.duskStartMinute);
break;
case 2:
lcd.print(">Auto Ajuste: ");
lcd.print(config.autoAdjustEnabled ? "Si" : "No");
break;
case 3:
lcd.print(">Minutos Ajuste: ");
lcd.print(config.autoAdjustMinutes);
break;
case 4:
lcd.print(">Hora Max Ajuste: ");
lcd.print(config.autoAdjustMaxHour);
lcd.print(":00");
break;
case 5:
lcd.print(">Activar Ajuste: ");
lcd.print(config.autoAdjustEnabled ? "Si" : "No");
break;
}
}
void displayMoonLightSubMenu() {
lcd.setCursor(0, 1);
switch (subMenuPosition) {
case 0:
lcd.print(">Activar: ");
lcd.print(config.moonLightEnabled ? "Si" : "No");
break;
case 1:
lcd.print(">Intensidad: ");
lcd.print(config.moonLightIntensity);
lcd.print("%");
break;
}
}
void displayAuxOutputsSubMenu() {
lcd.setCursor(0, 1);
switch (subMenuPosition) {
case 0:
lcd.print(">Rele 1 Activar: ");
lcd.print(config.relay1Enabled ? "Si" : "No");
break;
case 1:
lcd.print(">Rele 1 Inicio: ");
lcd.print(config.relay1StartHour);
lcd.print(":00");
break;
case 2:
lcd.print(">Rele 1 Fin: ");
lcd.print(config.relay1EndHour);
lcd.print(":00");
break;
case 3:
lcd.print(">Rele 2 Activar: ");
lcd.print(config.relay2Enabled ? "Si" : "No");
break;
case 4:
lcd.print(">Rele 2 Inicio: ");
lcd.print(config.relay2StartHour);
lcd.print(":00");
break;
case 5:
lcd.print(">Rele 2 Fin: ");
lcd.print(config.relay2EndHour);
lcd.print(":00");
break;
}
}
void adjustValue(bool increment) {
switch (menuPosition) {
case 0: // Fecha y Hora
if (subMenuPosition == 0) {
adjustDate(increment);
} else if (subMenuPosition == 1) {
adjustTime(increment);
}
break;
case 1: // Amanecer
adjustDawnSettings(increment);
break;
case 2: // Anochecer
adjustDuskSettings(increment);
break;
case 3: // Luz Luna
adjustMoonLightSettings(increment);
break;
case 4: // Salidas Auxiliares
adjustAuxOutputsSettings(increment);
break;
}
saveConfig();
}
void adjustDate(bool increment) {
DateTime now = rtc.now();
if (increment) {
rtc.adjust(DateTime(now.year(), now.month(), now.day() + 1, now.hour(), now.minute(), now.second()));
} else {
rtc.adjust(DateTime(now.year(), now.month(), now.day() - 1, now.hour(), now.minute(), now.second()));
}
}
void adjustTime(bool increment) {
DateTime now = rtc.now();
if (increment) {
rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute() + 1, now.second()));
} else {
rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute() - 1, now.second()));
}
}
void adjustDawnSettings(bool increment) {
switch (subMenuPosition) {
case 0:
config.dawnDuration += increment ? 1 : -1;
break;
case 1:
config.dawnStartHour = (config.dawnStartHour + (increment ? 1 : -1) + 24) % 24;
break;
case 2:
config.dawnStartMinute = (config.dawnStartMinute + (increment ? 1 : -1) + 60) % 60;
break;
case 3:
config.autoAdjustEnabled = !config.autoAdjustEnabled;
break;
case 4:
config.autoAdjustMinutes += increment ? 1 : -1;
break;
case 5:
config.autoAdjustMaxHour = (config.autoAdjustMaxHour + (increment ? 1 : -1) + 24) % 24;
break;
}
}
void adjustDuskSettings(bool increment) {
switch (subMenuPosition) {
case 0:
config.duskDuration += increment ? 1 : -1;
break;
case 1:
config.duskStartHour = (config.duskStartHour + (increment ? 1 : -1) + 24) % 24;
break;
case 2:
config.duskStartMinute = (config.duskStartMinute + (increment ? 1 : -1) + 60) % 60;
break;
case 3:
config.autoAdjustEnabled = !config.autoAdjustEnabled;
break;
case 4:
config.autoAdjustMinutes += increment ? 1 : -1;
break;
case 5:
config.autoAdjustMaxHour = (config.autoAdjustMaxHour + (increment ? 1 : -1) + 24) % 24;
break;
}
}
void adjustMoonLightSettings(bool increment) {
switch (subMenuPosition) {
case 0:
config.moonLightEnabled = !config.moonLightEnabled;
break;
case 1:
config.moonLightIntensity += increment ? 1 : -1;
break;
}
}
void adjustAuxOutputsSettings(bool increment) {
switch (subMenuPosition) {
case 0:
config.relay1Enabled = !config.relay1Enabled;
break;
case 1:
config.relay1StartHour = (config.relay1StartHour + (increment ? 1 : -1) + 24) % 24;
break;
case 2:
config.relay1EndHour = (config.relay1EndHour + (increment ? 1 : -1) + 24) % 24;
break;
case 3:
config.relay2Enabled = !config.relay2Enabled;
break;
case 4:
config.relay2StartHour = (config.relay2StartHour + (increment ? 1 : -1) + 24) % 24;
break;
case 5:
config.relay2EndHour = (config.relay2EndHour + (increment ? 1 : -1) + 24) % 24;
break;
}
}
void quickSunrise() {
for (int i = 0; i <= 255; i++) {
setLEDStripsBrightness(i);
delay(48); // 2 minutos / 256 pasos
}
}
void quickSunset() {
for (int i = 255; i >= 0; i--) {
setLEDStripsBrightness(i);
delay(732); // 30 minutos / 256 pasos
}
}
void controlRelay1(float humidity, DateTime now) {
if (config.relay1Enabled) {
if (humidity >= 65) {
digitalWrite(RELAY1_PIN, HIGH); // Activa el relé si la humedad es >= 65%
} else if (humidity <= 50) {
digitalWrite(RELAY1_PIN, LOW); // Desactiva el relé si la humedad es <= 50%
}
// Control basado en horario
if (now.hour() >= config.relay1StartHour && now.hour() < config.relay1EndHour) {
digitalWrite(RELAY1_PIN, HIGH); // Activa el relé dentro del horario configurado
} else {
digitalWrite(RELAY1_PIN, LOW); // Desactiva el relé fuera del horario configurado
}
} else {
digitalWrite(RELAY1_PIN, LOW); // Asegúrate de que el relé esté desactivado si no está habilitado
}
}
void controlRelay2(DateTime now) {
if (config.relay2Enabled) {
if (now.hour() >= config.relay2StartHour && now.hour() < config.relay2EndHour) {
digitalWrite(RELAY2_PIN, HIGH); // Activa el relé dentro del horario configurado
} else {
digitalWrite(RELAY2_PIN, LOW); // Desactiva el relé fuera del horario configurado
}
} else {
digitalWrite(RELAY2_PIN, LOW); // Asegúrate de que el relé esté desactivado si no está habilitado
}
}
void controlMoonLightLED(DateTime now) {
if (config.moonLightEnabled) {
int duskEndMinute = config.duskStartHour * 60 + config.duskStartMinute + config.duskDuration;
int dawnStartMinute = config.dawnStartHour * 60 + config.dawnStartMinute;
int currentMinute = now.hour() * 60 + now.minute();
if (currentMinute >= duskEndMinute - 10 && currentMinute <= duskEndMinute + config.duskDuration + 10) {
int brightness = map(currentMinute, duskEndMinute - 10, duskEndMinute + config.duskDuration + 10, 0, config.moonLightIntensity);
analogWrite(LED_MOON_PIN, brightness);
} else if (currentMinute >= dawnStartMinute - 10 && currentMinute <= dawnStartMinute + config.dawnDuration + 10) {
int brightness = map(currentMinute, dawnStartMinute + config.dawnDuration + 10, dawnStartMinute - 10, 0, config.moonLightIntensity);
analogWrite(LED_MOON_PIN, brightness);
} else {
analogWrite(LED_MOON_PIN, 0);
}
}
}
void controlDawnDuskLEDs(DateTime now) {
int currentMinute = now.hour() * 60 + now.minute();
int dawnStartMinute = config.dawnStartHour * 60 + config.dawnStartMinute;
int duskStartMinute = config.duskStartHour * 60 + config.duskStartMinute;
if (currentMinute >= dawnStartMinute && currentMinute <= dawnStartMinute + config.dawnDuration) {
int brightness = map(currentMinute, dawnStartMinute, dawnStartMinute + config.dawnDuration, 0, 255);
setLEDStripsBrightness(brightness);
} else if (currentMinute >= duskStartMinute && currentMinute <= duskStartMinute + config.duskDuration) {
int brightness = map(currentMinute, duskStartMinute, duskStartMinute + config.duskDuration, 255, 0);
setLEDStripsBrightness(brightness);
} else {
setLEDStripsBrightness(255);
}
}
void setLEDStripsBrightness(int brightness) {
analogWrite(LED_STRIP1_PIN, brightness);
analogWrite(LED_STRIP2_PIN, brightness);
analogWrite(LED_STRIP3_PIN, brightness);
analogWrite(LED_STRIP4_PIN, brightness);
}
void handleAutoAdjust(DateTime now) {
if (config.autoAdjustEnabled && now.hour() == 0 && now.minute() == 0) {
config.dawnStartMinute += config.autoAdjustMinutes;
config.duskStartMinute += config.autoAdjustMinutes;
if (config.dawnStartHour * 60 + config.dawnStartMinute >= config.autoAdjustMaxHour * 60) {
config.dawnStartMinute = config.autoAdjustMaxHour * 60;
}
if (config.duskStartHour * 60 + config.duskStartMinute >= config.autoAdjustMaxHour * 60) {
config.duskStartMinute = config.autoAdjustMaxHour * 60;
}
saveConfig();
}
}
void saveConfig() {
EEPROM.put(EEPROM_ADDRESS, config);
if (!EEPROM.commit()) {
Serial.println("Error al guardar la configuración en la EEPROM");
}
}
void loadConfig() {
EEPROM.get(EEPROM_ADDRESS, config);
}