#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 };
volatile int encoderPos = 0;
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] = {800, 900, 1000, 1100, 1200, 1300, 1400, 1300, 1200, 1100, 1000, 900, 800};
myDisplay disp;
// ===========================================================
// INTERRUPCIÓN DEL ENCODER
// ===========================================================
void IRAM_ATTR handleEncoder() {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime < 100) return; // anti-rebote
int currentCLK = digitalRead(CLK);
int currentDT = digitalRead(DT);
if (currentCLK == LOW) {
if (currentDT == HIGH) {
// Giro a la derecha
if (currentState == STATE_NOW) {
currentState = STATE_MEM_SHOW_HOUR;
encoderPos = 0;
inMemoryMode = true;
modeChangeTime = millis();
}
else if (inMemoryMode) {
encoderPos++;
if (encoderPos > 12) {
// Si pasa de las 18H → volver a NOW
encoderPos = 0;
currentState = STATE_NOW;
inMemoryMode = false;
} else {
currentState = STATE_MEM_SHOW_HOUR;
modeChangeTime = millis();
}
}
}
else {
// Giro a la izquierda
if (inMemoryMode) {
if (encoderPos > 0) {
encoderPos--;
currentState = STATE_MEM_SHOW_HOUR;
modeChangeTime = millis();
}
else {
// Si ya estaba en 6H y sigue girando a la izquierda → salir a NOW
currentState = STATE_NOW;
inMemoryMode = false;
encoderPos = 0;
}
}
}
}
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 RTC DS3231
rtcBegin();
// Inicializar sensor BH1750
bh1750Begin();
// Verificar EEPROM
eepromWriteByte(0, 0x12);
eepromWriteByte(1, 0x34);
eepromWriteByte(0, 0);
eepromWriteByte(1, 0);
// 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;
}
// ===========================================================
// LOOP PRINCIPAL
// ===========================================================
void loop() {
// Actualizar display (sin Ticker)
disp.update();
// 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;
static int lastEncoderPos = -1;
if (inMemoryMode) {
// Si el encoder cambió → guardar nuevo valor actual en esa hora
if (encoderPos != lastEncoderPos) {
uint16_t nuevaLectura = readLightLevel(); // lectura actual BH1750
if (nuevaLectura > 0 && nuevaLectura < 65535) {
medidasBackup[encoderPos] = nuevaLectura;
writeMeasurement(encoderPos, nuevaLectura);
}
lastEncoderPos = encoderPos;
}
// 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);
}