Problema LCD 2004 + ESP

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);
}

Muestra cómo están cableados los botones. Su código establece todos los pines de botón con una resistencia pullup = HIGH (botón no presionado)

¿Podrías mostrar cómo tienes los botones conectados? Con INPUT_PULLUP cada botón debe ir de la entrada a GND. Si están al revés o hay ruido, el LCD creera que están siempre pulsados. Prueba este mini código solo para leer uno y ver si responde bien antes de añadir el resto:

pinMode(BUTTON_UP_PIN, INPUT_PULLUP);
Serial.begin(115200);
void loop() {
  Serial.println(digitalRead(BUTTON_UP_PIN));
  delay(200);
}

Hola a todos, los botones los tengo conectados con un pin al GND y otro al pin asignado en el ESP32. No les pongo resistencias al utilizar las internas.
Un saludo.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.