/*
Controlador de Aires acondicionados para Shelters
Placa Esp32-s3-devkitc-1
Módulo Ethernet: Basado en W5500

*/

//#include "ethernet.h"

#include "config.h" // <--- Change settings for YOUR network here.

#include "funciones.h"

#include "pantalla.h"

#include "almacenamiento.h"

#include "funciones_estados.h"

#include <Ticker.h>

//#include <unordered_map>

uint8_t estado;
bool marca_seleccionado;
bool modo_auto;
bool equipo_principal;     // Si true => AA1, si false => AA2
//bool estado_equipo_principal;   // Si true => en_marcha
float temp_de_control;   // Temperatura de control. Tomará el valor de AA1_temp_in ó de AA2_temp_in según corresponda.
bool marcha_AA1;
bool marcha_AA2;
bool fan_AA1;
bool fan_AA2;
bool habilitado_AA1;
bool habilitado_AA2;
String rot_equipos;
float setpoint_1;
float histeresis;
float setpoint_2;
uint8_t direccionIP[4];
uint8_t mascara_subnet[4];
uint8_t servidor_dns[4];
uint8_t puerta_enlace[4];


float _contador;  // Valor temporal para edición de los parámetros en el menu
uint8_t _contadorIP[4];  // Valor temporal para edición de los parámetros IP en el menu
uint8_t _nbyte_a_ajustar; // Valor temporal del byte a ajustar para edición de los parámetros IP en el menu

bool modo_manual;


// Creo el objeto oled para manejar el display
Pantalla pantalla(SCL_PIN,SDA_PIN);

//OLED oled;
// Declaro el objeto que controla los parámetros del sistema
Parametros params;


// Temporizador para apagar la pantalla
Ticker inactivityTimer;
const unsigned long inactivityTimeout = 30000; // 1/2 minuto

bool botones_en_uso = true; // Va a indicar si se están presionando los botones del display
bool display_encendido = true;
bool delay_active = false;
//#include "display.h"

// Defino la versión del programa
#define VerNum "1.4.5"






/*
uint8_t btn_estado[4];
uint8_t btnPres(uint8_t btn){
    uint8_t new_value = digitalRead(button[btn]);
    uint8_t resutl = btn_estado[btn] != new_value && new_value == 1;
    btn_estado[btn] = new_value;
    return resutl;
}
*/
/*
uint8_t btn_estado[4];

uint8_t btnPres(uint8_t btn) {
    uint8_t new_value = digitalRead(button[btn]);
    uint8_t result = btn_estado[btn] == 0 && new_value == 1;
    btn_estado[btn] = new_value;
    return result;
}

uint8_t btn_estado[4];
uint8_t btnPres(uint8_t btn) {
    uint8_t new_value = digitalRead(button[btn]);
    uint8_t result = btn_estado[btn] == HIGH && new_value == LOW;
    btn_estado[btn] = new_value;
    return result;
}
*/

//uint8_t btn_estado[4];
volatile bool btnBackPressed = false;
volatile bool btnSelectPressed = false;
volatile bool btnUpPressed = false;
volatile bool btnDownPressed = false;
//volatile bool btnUpCheckLongPress = false;
bool btnUpHold = false;
bool btnDownHold = false;
bool btnUpHoldStep = false;
bool btnDownHoldStep = false;
uint8_t btn_up_state = 0;
uint8_t btn_down_state = 0;
uint8_t btn_up_prev_state = 0;
uint8_t btn_down_prev_state = 0;
//volatile bool btnDownCheckLongPress = false;
const uint16_t BTN_MIN_HOLD_DURATION = 1000; // Mínimo intervalo de tiempo para considerar mantenido al botón
const uint16_t DEBOUNCE_DELAY = 350;   // Tiempo de debounce en ms
volatile unsigned long current_millis;
volatile unsigned long last_millis = 0;
unsigned long time_init_btn_press = 0;  // Memoriza el número de millis en el inicio del conteo
float counter = 0.0;
const uint16_t COUNTER_TIME_STEP = 200;
unsigned long lastCounterTime = 0;
unsigned long lastTempCheckTime = 0;
const uint16_t TEMP_CHECK_INTERVAL = 1000;   // Tiempo de chequeo entre mediciones
unsigned long rotation_interval = 0;  // Intervalo de rotación en milisegundos
unsigned long last_rotation_time = 0;  // Último tiempo de rotación registrado


// volatile uint8_t btn_estado[4] = {HIGH, HIGH, HIGH, HIGH};
void IRAM_ATTR buttonBackInterrupt();
void IRAM_ATTR buttonSelectInterrupt();
void IRAM_ATTR buttonUpInterrupt();
void IRAM_ATTR buttonDownInterrupt();
void checkHoldButtons();
//void IRAM_ATTR buttonUpCheckLongPressInterrupt();
//void IRAM_ATTR buttonDownCheckLongPressInterrupt();
//uint8_t btnPres(uint8_t btn);


void reiniciarInactividad();
void apagarPantalla();
void encenderPantalla();
//void delayStable();




void setup() {
    //delay(2000);
    Serial.begin(115200);
    current_millis = millis();

    // Inicializo el espacio de nombres del objeto de la clase Parametros, se inicializa dentro de la función
    // setup() porque sino me da problemas con la inicialización del espacio de nombre de la partición NVS
    params.begin();
    
    Serial.println("Hello, ESP32-S3!");

    // Borro todos los parámetros del sistema (todo el espacio de nombres)
    //params.systemParamsReset();
    //params.netParamsReset();

    // Chequeo si es la primera vez que se corre el programa entonces seteo los parámetros por defecto
    if(!params.existeClave("seteo_inicial")) {
        Serial.println("--- Seteo los parámetros por defecto ---");
        params.defaultToSystemParams();
        params.defaultToNetParams();
    }

    // Mostrar los valores de los parámetros en el puerto serial
    params.showSystemParams();
    params.showNetParams();

    // Inicializo las salidas
    for (uint8_t i = 0; i < NUM_SALIDAS; i++) {
        pinMode(salidas[i], OUTPUT); // Configura los pines de salidas
    }

    // Inicializo las entradas analógicas
    for (int i = 0; i < NUM_ENTRADAS_ANAL; i++) {
        pinMode(entradas_anal[i], INPUT);
    }

    // Inicializo los botones y el arreglo btn_estado[] en HIGH para poner el estado inicial de los botones como no presionado
//    pinMode(button[BTN_BACK], INPUT_PULLUP);
//    pinMode(button[BTN_SELECT], INPUT_PULLUP);
//    pinMode(button[BTN_UP], INPUT_PULLUP);
//    pinMode(button[BTN_DOWN], INPUT_PULLUP);

    pinMode(button[BTN_BACK], INPUT_PULLUP);
    pinMode(button[BTN_SELECT], INPUT_PULLUP);
    pinMode(button[BTN_UP], INPUT_PULLUP);
    pinMode(button[BTN_DOWN], INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(button[BTN_BACK]), buttonBackInterrupt, RISING);
    attachInterrupt(digitalPinToInterrupt(button[BTN_SELECT]), buttonSelectInterrupt, RISING);
    attachInterrupt(digitalPinToInterrupt(button[BTN_UP]), buttonUpInterrupt, RISING);
    attachInterrupt(digitalPinToInterrupt(button[BTN_DOWN]), buttonDownInterrupt, RISING);

//attachInterrupt(digitalPinToInterrupt(button[BTN_BACK]), buttonBackInterrupt, RISING);
//attachInterrupt(digitalPinToInterrupt(button[BTN_SELECT]), buttonSelectInterrupt, RISING);
//attachInterrupt(digitalPinToInterrupt(button[BTN_UP]), buttonUpInterrupt, RISING);
//attachInterrupt(digitalPinToInterrupt(button[BTN_DOWN]), buttonDownInterrupt, RISING);

//    btn_estado[0] = btn_estado[1] = btn_estado[2] = btn_estado[3] = HIGH;

    // Inicializo las variables que almacenarán los valores de los parámetros y si al momento tiene marca de selección
    modo_auto = params.obtenerModoAuto();
    p_estado[AUTO_ON] = modo_auto;
    p_estado[AUTO_OFF] = !modo_auto;

    marcha_AA1 = false; // *** Ver si hay que dejarlo solo como variable (como está acá), pero sacarlo de almacenamiento como parámetro
    p_estado[AA1_ON] = marcha_AA1;
    p_estado[AA1_OFF] = !marcha_AA1;
    marcha_AA2 = false; // *** Ver si hay que dejarlo solo como variable (como está acá), pero sacarlo de almacenamiento como parámetro
    p_estado[AA2_ON] = marcha_AA2;
    p_estado[AA2_OFF] = !marcha_AA2;


    Serial.printf("setup::p_estado AA1_ON: %d, - AA1_OFF: %d, - AA2_ON: %d, - AA2_OFF: %d\n", p_estado[AA1_ON], p_estado[AA1_OFF], p_estado[AA2_ON], p_estado[AA2_OFF]);

    habilitado_AA1 = params.obtenerHabilitadoAA1();
    habilitado_AA2 = params.obtenerHabilitadoAA2();
    p_estado[HAB_TODOS] = (habilitado_AA1 && habilitado_AA2) ? true : false;
    p_estado[SOLO_AA1] = (habilitado_AA1 && !habilitado_AA2) ? true : false;
    p_estado[SOLO_AA2] = (!habilitado_AA1 && habilitado_AA2) ? true : false;

    rot_equipos = params.obtenerRotacionEquipos();

    p_estado[ROT_DIARIA] = (rot_equipos == "DIARIA") ? true : false;
    p_estado[ROT_SEMANAL] = (rot_equipos == "SEMANAL") ? true : false;
    p_estado[ROT_POR_CICLO] = (rot_equipos == "POR_CICLO") ? true : false;
    setIntervaloRotacion(); // Seteo el intervalo de rotación

    Serial.printf("setup::rot_equipos: %s - p_estado[ROT_DIARIA]: %u - p_estado[ROT_SEMANAL]: %u - p_estado[ROT_POR_CICLO]: %u\n", rot_equipos, p_estado[ROT_DIARIA], p_estado[ROT_SEMANAL], p_estado[ROT_POR_CICLO]);

    setpoint_1 = params.obtenerSetPoint1();
    histeresis = params.obtenerHisteresis();
    setpoint_2 = params.obtenerSetPoint2();

    // Defino el equipo principal
    equipo_principal = true;    // Si true => AA1, si false => AA2
 //   temp_de_control

    params.obtenerIP("direccion_ip", direccionIP);
    params.obtenerIP("mascara_subnet", mascara_subnet);
    params.obtenerIP("servidor_dns", servidor_dns);
    params.obtenerIP("puerta_enlace", puerta_enlace);

    modo_manual = false;    // Se utiliza para hacer test de funcionamiento de los equipos de aire 

    // Defino la variable que va a indicar cuando hay que marcar en el display el parámetro actualmente vigente
    marca_seleccionado = false;
 

    // inicializo el display
    pantalla.begin();

    Serial.print("AireControl SRL - Version ");
    Serial.println(VerNum);

    char version[20];
    snprintf(version, sizeof(version), "Version: %s", VerNum);

    pantalla.clearDisplay();
    pantalla.mostrarMsg("AireControl SRL", version);
    //pantalla.mostrarMenu("AireControl SRL", version, marca_seleccionado);
    //delay(2000);


// *** INTERCALAR LO DEL NTP PARA EL SETUP CUANDO LO DEMÁS ESTÉ LISTO ***

    // Estado inicial
    estado = VISUALIZACION;

    // Dibujo el menu principal
    pantalla.clearDisplay();
    pantalla.mostrarHeader(modo_auto,true, true);
    pantalla.mostrarMenu(tablaTransiciones[estado].menu_raiz, tablaTransiciones[estado].menu_elemento, marca_seleccionado);
    Serial.printf("Menu por defecto: %d\n", estado);

    // Configuración inicial del temporizador de inactividad de la pantalla
    //inactivityTimer.attach_ms(inactivityTimeout, apagarPantalla); // Iniciar el temporizador de inactividad
}

void loop() {


    // Ejecuto una vez la lectura de los botones y lo muestro por el serial
    static bool primer_lectura_BTN = false;
    if(!primer_lectura_BTN){
//        Serial.printf("BTN_DOWN: %d - BTN_UP: %d - BTN_SELECT: %d - BTN_BACK: %d\n", btnPres(BTN_DOWN), btnPres(BTN_UP), btnPres(BTN_SELECT), btnPres(BTN_BACK));
Serial.printf("BTN_DOWN: %d - BTN_UP: %d - BTN_SELECT: %d - BTN_BACK: %d\n", btnDownPressed, btnUpPressed, btnSelectPressed, btnBackPressed);
        Serial.printf("p_estado AA1_ON: %d, - AA1_OFF: %d, - AA2_ON: %d, - AA2_OFF: %d\n", p_estado[AA1_ON], p_estado[AA1_OFF], p_estado[AA2_ON], p_estado[AA2_OFF]);
        primer_lectura_BTN = true;
    }

    current_millis = millis();

// **** INTERCALAR CON LO DEL NTP PARA EL LOOP CUANDO LO DEMÁS ESTÉ LISTO ****

//  delay(10); // this speeds up the simulation

    // **** MEDICION DE LAS ENTRADAS ANALOGICAS Cant: 5 ****
        // Leo las temperaturas: AA1_temp_in, AA1_temp_out, AA2_temp_in, AA2_temp_out y temp_ambiente
        // Las temperaturas: AA1_temp_in y AA2_temp_in son las que controlan los equipos
        if (current_millis - lastTempCheckTime >= TEMP_CHECK_INTERVAL) {
            leerTemperaturas();
            lastTempCheckTime = current_millis;
        }

    
    // **** MEDICION DE LAS ENTRADAS DIGITALES Cant: 6 ****
        // Alarmas equipos
        // Falta de fase
    
    // **** ESTADO DE SALIDAS DIGITALES Cant: 5 ****
    digitalWrite(salidas[AA1_COMP], marcha_AA1);    // Comando compresor AA1
    digitalWrite(salidas[AA1_FAN], fan_AA1); // Comando turbina AA1
    //if (marcha_AA1) {digitalWrite(salidas[AA1_FAN], HIGH);} // Comando turbina AA1
    digitalWrite(salidas[AA2_COMP], marcha_AA2);    // Comando compresor AA2
    digitalWrite(salidas[AA2_FAN], fan_AA2); // Comando turbina AA2
    //if (marcha_AA2) {digitalWrite(salidas[AA2_FAN], HIGH);} // Comando turbina AA2
    // Falla general (activa cuando: alarma de equipos/falta de fase, falla sensores temp., y alarma de temp. en sitio).


    // **** MODO AUTO ****
    if (modo_auto) {
        // La temperatura de control que comanda el arranque o la parada es la que marca el equipo principal
        if (equipo_principal) {
            //Serial.println("-- modo_auto::Controla AA1_temp_in");
            temp_de_control = AA1_temp_in;
        } else {
            //Serial.println("-- modo_auto::Controla AA2_temp_in");
            temp_de_control = AA2_temp_in;
        }

        // Comprobar si no rota por ciclo y si ha pasado suficiente tiempo para rotar => Rotar
        if (!p_estado[ROT_POR_CICLO] && (current_millis - last_rotation_time >= rotation_interval)) {
            Serial.println("modo_auto:: Rotación por intervalo de tiempo - Debo rotar");
            // Rotar equipos
            equipo_principal = !equipo_principal;  // Alternar entre equipos principales
            last_rotation_time = current_millis;  // Actualizar el último tiempo de rotación
            Serial.printf("-- modo_auto::equipo_principal: %u - rotation_interval: %u\n", equipo_principal, rotation_interval);
        }

        // Si ambos equipos apagados Y temp  >=  (SP1 + H/2) =>  Enciendo equipo principal
        if ((!marcha_AA1 && !marcha_AA2) && (temp_de_control >= setpoint_1 + histeresis/2)) {
            Serial.println("modo_auto:: - Enciendo equipo principal");
            Serial.printf("modo_auto::temp_de_control: %.2f - AA1_temp_in: %.2f - AA1_temp_out: %.2f - AA2_temp_in: %.2f - AA2_temp_out: %.2f - temp_ambiente: %.2f\n", temp_de_control, AA1_temp_in, AA1_temp_out, AA2_temp_in, AA2_temp_out, temp_de_control);
            arranqueEquipo(true);
        }
        // Si (marcha_AA1 XOR marcha_AA2 está encendido) Y temp  >=  (SP2) =>  Enciendo equipo stand-by
        if ((marcha_AA1 ^ marcha_AA2) && (temp_de_control >= setpoint_2)) {
            Serial.println("modo_auto - Enciendo equipo secundario");
            Serial.printf("modo_auto::temp_de_control: %.2f - AA1_temp_in: %.2f - AA1_temp_out: %.2f - AA2_temp_in: %.2f - AA2_temp_out: %.2f - temp_ambiente: %.2f\n", temp_de_control, AA1_temp_in, AA1_temp_out, AA2_temp_in, AA2_temp_out, temp_de_control);
            arranqueApoyo();
        }
        // Si (marcha_AA1 ó marcha_AA1 están encendidos) Y temp  <=  (SP1 - H/2) =>  Apago ambos equipos
        if ((marcha_AA1 || marcha_AA2) && (temp_de_control <= setpoint_1 - histeresis/2)) {
            Serial.println("modo_auto - Apago ambos equipos");
            Serial.printf("modo_auto::temp_de_control: %.2f - AA1_temp_in: %.2f - AA1_temp_out: %.2f - AA2_temp_in: %.2f - AA2_temp_out: %.2f - temp_ambiente: %.2f\n", temp_de_control, AA1_temp_in, AA1_temp_out, AA2_temp_in, AA2_temp_out, temp_de_control);
            arranqueEquipo(false);
//            equipoSecundario(false);
        }
    }
    // Contemplar situación particular en que el equipo enciende por alta temperatura y nunca apaga porque
    // no logra bajarla pero la misma no llega a ser tan alta como para disparar el segundo setpoint.

    // Ver donde y como apago los FANs
    // Apago los ventiladores
    //fan_AA1 = false;
    //fan_AA2 = false;

    // **** REGISTRO DE FALLAS HISTÓRICAS ****


    // Mientras no esté activo el retardo de bloqueo de los botones evalúo si hay alguno presionado
    if (!delay_active && display_encendido){      

            // Obtener la transición correspondiente al estado actual
            //Transicion transicion = tablaTransiciones[estado];

        if(btnDownPressed && !btnDownHold){
            // Cambio el estado y luego ejecuto la acción de la transición si la tuviera.
            Serial.printf("*** BTN_DOWN::Estado actual: %d ***\n", estado);
            estado = tablaTransiciones[estado].sig_estado;
            ejecutarTransicion(BTN_DOWN);
            Serial.printf("*** BTN_DOWN::Nuevo estado: %d ***\n", estado);
            btnDownPressed = false;
        } else if (btnUpPressed && !btnUpHold){
            Serial.printf("*** BTN_UP::Estado actual: %d ***\n", estado);
            estado = tablaTransiciones[estado].ant_estado;
            ejecutarTransicion(BTN_UP);
            Serial.printf("*** BTN_UP::Nuevo estado: %d ***\n", estado);
            btnUpPressed = false;
        } else if(btnSelectPressed){
            Serial.printf("*** BTN_SELECT::Estado actual: %d ***\n", estado);
            // Llamo a la función ejecutarTransición. En el caso del BTN_SELECT, el cambio de estado se evaluará allí.
            ejecutarTransicion(BTN_SELECT);
            Serial.printf("*** BTN_SELECT::Nuevo estado: %d ***\n", estado);
            btnSelectPressed = false;
        } else if(btnBackPressed){
            Serial.printf("*** BTN_BACK::Estado actual: %d ***\n", estado);
            estado = tablaTransiciones[estado].atras_estado;
            ejecutarTransicion(BTN_BACK);
            Serial.printf("*** BTN_BACK::Nuevo estado: %d ***\n", estado);
            btnBackPressed = false;
        } else if(!btnDownPressed && btnDownHold && btnDownHoldStep){
            Serial.printf("*** BTN_DOWN HOLD::Estado actual: %d ***\n", estado);
            ejecutarTransicion(BTN_DOWN);
            btnDownHold = false;
            btnDownHoldStep = false;
            Serial.printf("*** BTN_DOWN HOLD::Nuevo estado: %d ***\n", estado);
        } else if(!btnUpPressed && btnUpHold && btnUpHoldStep){
            Serial.printf("*** BTN_UP HOLD::Estado actual: %d ***\n", estado);
            ejecutarTransicion(BTN_UP);
            btnUpHold = false;
            btnUpHoldStep = false;
            Serial.printf("*** BTN_UP HOLD::Nuevo estado: %d ***\n", estado);
        }

        
        checkHoldButtons();


    }

    // Si está en modo visualización muestro las temperaturas
    if(estado == VISUALIZACION){

    } 

    // Si el display está apagado y se presionó algún botón, llamo a la función reiniciarInactividad    
    if (!display_encendido){
        if(btnDownPressed || btnUpPressed || btnSelectPressed || btnBackPressed) {
            btnBackPressed = false;
            btnSelectPressed = false;
            btnUpPressed = false;
            btnDownPressed = false;

            reiniciarInactividad(); // Se presionó un botón, reiniciar el temporizador de inactividad
        }
    // Si el display está encendido y la variable botones_en_uso es true, llamo a la función reiniciarInactividad
    } else if (display_encendido && botones_en_uso){
        reiniciarInactividad(); // Se presionó un botón, reiniciar el temporizador de inactividad
    }
    // Ya evalué si los botones están en uso, lo paso a false
    botones_en_uso = false;


/*     btnBackPressed = false;
    btnSelectPressed = false;
    btnUpPressed = false;
    btnDownPressed = false;
 */
}


void IRAM_ATTR buttonBackInterrupt() {
    current_millis = millis();
    if (current_millis - last_millis >= DEBOUNCE_DELAY) {
        btnBackPressed = true;
        last_millis = current_millis; // Establecer el inicio de la pulsación
    }
}

void IRAM_ATTR buttonSelectInterrupt() {
    current_millis = millis();
    if (current_millis - last_millis >= DEBOUNCE_DELAY) {
        btnSelectPressed = true;
        last_millis = current_millis; // Establecer el inicio de la pulsación
    }
}

void IRAM_ATTR buttonUpInterrupt() {
    current_millis = millis();
    if (current_millis - last_millis >= DEBOUNCE_DELAY) {
        if(btnUpHold) {
            btnUpPressed = false;
            btnUpHold = false;
        } else {
            btnUpPressed = true;
        }
        last_millis = current_millis; // Establecer el inicio de la pulsación
    }
}

void IRAM_ATTR buttonDownInterrupt() {
    current_millis = millis();
    if (current_millis - last_millis >= DEBOUNCE_DELAY) {
        if(btnDownHold) {
            btnDownPressed = false;
            btnDownHold = false;
        } else {
            btnDownPressed = true;
        }
        last_millis = current_millis; // Establecer el inicio de la pulsación
    }
}

void checkHoldButtons() {
    current_millis = millis();

    // Read the digital value of the button (LOW/HIGH)
    uint8_t btn_down_state = digitalRead(button[BTN_DOWN]) == LOW;
    uint8_t btn_up_state = digitalRead(button[BTN_UP]) == LOW;

    //empiezo a contar el tiempo
    if ((!btn_down_prev_state && btn_down_state) || (!btn_up_prev_state && btn_up_state)) {
        Serial.println("checkHoldButtons::Permutación estado botones - Empiezo a contar el tiempo");
        time_init_btn_press = millis();
    }

    if (btn_down_prev_state && btn_down_state && current_millis - time_init_btn_press >= BTN_MIN_HOLD_DURATION) {
        //Serial.println("checkHoldButtons::Botón Mantenido !!");
        btnDownHold = true;

        if(current_millis - lastCounterTime >= COUNTER_TIME_STEP){
            btnDownHoldStep = true;
            Serial.print("_contador: ");
            Serial.print(_contador);
            Serial.flush();  // Asegura que los datos se muestran inmediatamente
            Serial.print("\r");  // Carrera de carro para sobrescribir la línea
            lastCounterTime = current_millis;
        }

    } else if (btn_up_prev_state && btn_up_state && current_millis - time_init_btn_press >= BTN_MIN_HOLD_DURATION) {
        //Serial.println("checkHoldButtons::Botón Mantenido !!");
        btnUpHold = true;

        if(current_millis - lastCounterTime >= COUNTER_TIME_STEP){
            btnUpHoldStep = true;
            Serial.print("_contador: ");
            Serial.print(_contador);
            Serial.flush();  // Asegura que los datos se muestran inmediatamente
            Serial.print("\r");  // Carrera de carro para sobrescribir la línea
            lastCounterTime = current_millis;
        }
    }

    btn_down_prev_state =  btn_down_state;
    btn_up_prev_state = btn_up_state;
}


void reiniciarInactividad() {
    Serial.println("reiniciarInactividad::Paso por la función");
    inactivityTimer.detach(); // Detener el temporizador para evitar llamadas múltiples
    if (!display_encendido){encenderPantalla();} // Si la pantalla está apagada encenderla
    inactivityTimer.attach_ms(inactivityTimeout, apagarPantalla); // Volver a iniciar el temporizador
}


void apagarPantalla(){
    Serial.println("apagarPantalla");
    pantalla.pantallaOnOFF(1);
    display_encendido = false;
    // Con la pantalla apagada, apago el timer
    inactivityTimer.detach();

}

void encenderPantalla(){
    Serial.println("encenderPantalla");
    pantalla.pantallaOnOFF(0);
    display_encendido = true;
}


$abcdeabcde151015202530fghijfghij