/* tắt mở led esp32 và app blynk
đặt thời gian trên app ,tắt mở nút nhấn
*/

#define BLYNK_TEMPLATE_ID   "Mã_ID_của_bạn"
#define BLYNK_TEMPLATE_NAME "Tên_Template_của_bạn"
#define BLYNK_AUTH_TOKEN    "Mã_Token_của_bạn"


#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
#include <Preferences.h>

// Thông tin WiFi của bạn
char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "Tên_WiFi_Nhà_Bạn";
char pass[] = "Mật_Khẩu_WiFi";
// --- CẤU HÌNH HỆ THỐNG (DỄ SỬA) ---

const int LED_PIN = 2;

// Các chân Virtual Pin trên App Blynk
#define V_BTN_LED     V1
#define V_TIME_INPUT  V2
#define V_MODE_SELECT V3

// --- BIẾN TOÀN CỤC ---
long startSecond = -1, stopSecond = -1;
bool isScheduled = false;
bool isManualMode = false; // false: Auto (Timer), true: Manual
int manualLedState = 0;
bool autoShouldBeOn = false;

WidgetRTC rtc;
BlynkTimer timer;
Preferences pref;

// --- HÀM KIỂM TRA THỜI GIAN ---
void checkTime() {
    if (year() <= 1970 || !isScheduled) return;

    long nowSec = hour() * 3600 + minute() * 60 + second();
    bool status = false;

    if (startSecond < stopSecond) { // Ví dụ: 08:00 - 17:00
        status = (nowSec >= startSecond && nowSec < stopSecond);
    } else { // Ví dụ: 22:00 - 05:00 (qua đêm)
        status = (nowSec >= startSecond || nowSec < stopSecond);
    }

    autoShouldBeOn = status;

    // Nếu đang ở chế độ Tự động, cập nhật trạng thái nút nhấn trên App cho đồng bộ
    if (!isManualMode) {
        Blynk.virtualWrite(V_BTN_LED, autoShouldBeOn ? 1 : 0);
    }  
}

// --- HÀM ĐIỀU KHIỂN CHÍNH (Chạy mỗi 500ms) ---
void controlLogic() {
    int finalState;

    if (isManualMode) {
        finalState = manualLedState;
    } else {
        finalState = autoShouldBeOn ? HIGH : LOW;
    }

    // Chỉ xuất lệnh và Serial khi có thay đổi trạng thái thực sự để tránh lag
    static int lastState = -1;
    if (finalState != lastState) {
        digitalWrite(LED_PIN, finalState);
        lastState = finalState;
        Serial.printf("Mode: %s | LED: %s\n", 
                      isManualMode ? "MANUAL" : "AUTO", 
                      finalState ? "ON" : "OFF");
    }
}
 
// --- XỬ LÝ DỮ LIỆU TỪ BLYNK ---
BLYNK_WRITE(V_BTN_LED) {
    manualLedState = param.asInt();
    
    // Nếu đang ở Auto  bấm nút này, tự động nhảy sang Manual
    if (!isManualMode) {
        isManualMode = true;
        Blynk.virtualWrite(V_MODE_SELECT, 0); // Gạt nút Mode trên App sang Manual
       
        Blynk.virtualWrite(V_BTN_LED, manualLedState); //  trên App  hiển thị đúng theo cái đèn
        Serial.println("Action: Bấm nút LED -> Tự động chuyển sang Manual");
    }
}

// Widget đặt giờ
BLYNK_WRITE(V_TIME_INPUT) {
    TimeInputParam t(param);
    if (t.hasStartTime()) startSecond = t.getStartHour() * 3600 + t.getStartMinute() * 60;
    if (t.hasStopTime())  stopSecond = t.getStopHour() * 3600 + t.getStopMinute() * 60;

    if (t.hasStartTime() && t.hasStopTime()) {
        isScheduled = true;
        isManualMode = false; // Có lịch mới thì ưu tiên chạy Auto
        Blynk.virtualWrite(V_MODE_SELECT, 255); // Cập nhật nút Mode trên App (255 là Auto)

        pref.begin("schedule", false);
        pref.putLong("start", startSecond);
        pref.putLong("stop", stopSecond);
        pref.putBool("active", true);
        pref.end();
        Serial.println("Updated Schedule -> Mode: AUTO");
    }
}

BLYNK_WRITE(V_MODE_SELECT) {
    int val = param.asInt();
    bool oldMode = isManualMode;
    isManualMode = (val == 0); // nếu val == 0 thì isManualMode = true; else = false;

    // Nếu vừa mới chuyển từ AUTO sang MANUAL (val từ 255 về 0)
    if (isManualMode && !oldMode) {
        // Đọc trạng thái đèn thực tế đang có để gán vào biến Manual
        manualLedState = digitalRead(LED_PIN);
        //  trên App  hiển thị đúng theo cái đèn
        Blynk.virtualWrite(V_BTN_LED, manualLedState);
        Serial.println("Sync: Đã đồng bộ nút V1 theo đèn khi chuyển sang Manual");
    }
}

BLYNK_CONNECTED() {
    Blynk.sendInternal("rtc", "sync");
   // Đồng bộ nút gạt Auto/Manual từ thiết bị lên App
    Blynk.virtualWrite(V_MODE_SELECT, isManualMode ? 0 : 255);
    Blynk.syncVirtual(V_BTN_LED, V_TIME_INPUT, V_MODE_SELECT);
}

void setup() {
    Serial.begin(115200);
    pinMode(LED_PIN, OUTPUT);

    pref.begin("schedule", true);
    startSecond = pref.getLong("start", -1);
    stopSecond = pref.getLong("stop", -1);
    isScheduled = pref.getBool("active", false);
    pref.end();

    Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
    rtc.begin();
    
    // Timer kiểm tra thời gian (1s/lần) và thực thi lệnh (500ms/lần)
    timer.setInterval(1000L, checkTime);
    timer.setInterval(500L, controlLogic);
}

void loop() {
    Blynk.run();
    timer.run();
}