#include "myDisplay.h"
#include "modulos.h"
#define CLK 25
#define DT 26
#define SW 27
// Máscaras para el RTC
#define HOUR_MASK 0x3F
#define MINUTE_MASK 0x7F
#define SECOND_MASK 0x7F
enum SystemState { STATE_NOW, STATE_MEM_SHOW_HOUR, STATE_MEM_SHOW_VALUE };
// Variables volatile para ISR
volatile int encoderPos = 0;
volatile bool encoderChanged = false;
volatile unsigned long lastInterruptTime = 0;
// Variables del sistema
int lastCLK = HIGH;
int medidaActual = 0;
int horaActual = 0;
unsigned long modeChangeTime = 0, lastMeasureTime = 0;
SystemState currentState = STATE_NOW;
bool inMemoryMode = false;
uint16_t medidasBackup[13];
myDisplay disp;
// ===========================================================
// INTERRUPCIÓN DEL ENCODER
// ===========================================================
void IRAM_ATTR handleEncoder() {
unsigned long interruptTime = micros();
if (interruptTime - lastInterruptTime < 1000) return; // Anti-rebote 1ms
int currentCLK = digitalRead(CLK);
int currentDT = digitalRead(DT);
if (currentCLK == LOW) {
// Solo actualizar posición y marcar cambio
if (currentDT == HIGH) {
encoderPos++;
} else {
encoderPos--;
}
encoderChanged = true;
}
lastInterruptTime = interruptTime;
lastCLK = currentCLK;
}
// ===========================================================
// CONFIGURACIÓN INICIAL
// ===========================================================
void setup() {
Serial.begin(115200);
disp.begin();
// Inicializar I2C con SDA en pin 32 y SCL en pin 33
Wire.begin(32, 33); // SDA=32, SCL=33
Wire.setClock(100000);
delay(100);
// Inicializar sensor BH1750
bh1750Begin();
// Encoder
pinMode(CLK, INPUT_PULLUP);
pinMode(DT, INPUT_PULLUP);
pinMode(SW, INPUT_PULLUP);
lastCLK = digitalRead(CLK);
attachInterrupt(digitalPinToInterrupt(CLK), handleEncoder, FALLING);
}
// ===========================================================
// FUNCIONES AUXILIARES
// ===========================================================
uint16_t leerMedicion(uint8_t hora) {
uint16_t valor = readMeasurement(hora);
if (valor == 0 || valor > 10000)
valor = medidasBackup[hora];
return valor;
}
// ===========================================================
// PROCESAMIENTO
// ===========================================================
void procesarEncoder() {
if (!encoderChanged) return;
noInterrupts();
int currentPos = encoderPos;
encoderChanged = false;
interrupts();
// Limitar rango del encoder
if (currentPos > 12) currentPos = 12;
if (currentPos < 0) currentPos = 0;
if (currentState == STATE_NOW) {
currentState = STATE_MEM_SHOW_HOUR;
encoderPos = 0;
inMemoryMode = true;
modeChangeTime = millis();
}
else if (inMemoryMode) {
// Si pasa de las 18H → volver a NOW
if (currentPos > 12) {
encoderPos = 0;
currentState = STATE_NOW;
inMemoryMode = false;
} else {
currentState = STATE_MEM_SHOW_HOUR;
modeChangeTime = millis();
// Guardar lectura actual en la nueva posición
uint16_t nuevaLectura = readLightLevel();
if (nuevaLectura > 0 && nuevaLectura < 65535) {
medidasBackup[currentPos] = nuevaLectura;
writeMeasurement(currentPos, nuevaLectura);
}
}
}
}
// ===========================================================
// LOOP PRINCIPAL
// ===========================================================
void loop() {
// Actualizar display (sin Ticker)
disp.update();
// Procesar cambios del encoder (fuera de ISR)
procesarEncoder();
// Botón SW -> regresar manualmente a modo NOW
if (!digitalRead(SW)) {
static unsigned long lastButtonPress = 0;
if (millis() - lastButtonPress > 300) {
currentState = STATE_NOW;
inMemoryMode = false;
encoderPos = 0;
lastButtonPress = millis();
}
}
// ============================
// ACTUALIZAR HORA ACTUAL DESDE RTC
// ============================
uint8_t currentRtcHour = getCurrentHour();
if (currentRtcHour >= 6 && currentRtcHour <= 18) {
horaActual = currentRtcHour - 6;
}
// ============================
// MODO NOW → medir y guardar valor real
// ============================
if (currentState == STATE_NOW && millis() - lastMeasureTime >= 2000) {
uint16_t lectura = readLightLevel(); // radiación real BH1750
if (lectura > 0 && lectura < 65535) {
medidaActual = lectura;
medidasBackup[horaActual] = lectura;
// Guardar en EEPROM solo si estamos en horario de medición
if (currentRtcHour >= 6 && currentRtcHour <= 18) {
writeMeasurement(horaActual, lectura);
}
}
lastMeasureTime = millis();
}
// ============================
// MODO HISTÓRICO → mostrar datos guardados
// ============================
static uint16_t valorGuardado = 0;
if (inMemoryMode) {
// Alternar cada 2s entre hora ↔ valor guardado
if (millis() - modeChangeTime >= 2000) {
if (currentState == STATE_MEM_SHOW_HOUR) {
currentState = STATE_MEM_SHOW_VALUE;
valorGuardado = leerMedicion(encoderPos);
} else {
currentState = STATE_MEM_SHOW_HOUR;
}
modeChangeTime = millis();
}
}
// ============================
// VISUALIZACIÓN
// ============================
if (currentState == STATE_NOW) {
disp.showNumber(medidaActual);
} else if (currentState == STATE_MEM_SHOW_HOUR) {
disp.showHour(encoderPos + 6);
} else if (currentState == STATE_MEM_SHOW_VALUE) {
disp.showNumber(leerMedicion(encoderPos));
}
delay(10);
}