/*
  https://blynk.cloud/dashboard/login
  https://blynk.cloud/dashboard/334784/global/filter/2410351/organization/334784/devices/1619448/dashboard
*/

#define BLYNK_PRINT Serial

#define BLYNK_TEMPLATE_ID "TMPXXXXX-XXXX"
#define BLYNK_TEMPLATE_NAME "Wokwi"
#define BLYNK_AUTH_TOKEN "RKQ9-I422tq0XSc2Ffs0XXXX-XXXXXXX"
#define BLYNK_FIRMWARE_VERSION "0.1.0"

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <TimeLib.h>
#include <Wire.h>
#include <RTClib.h>
#include <ezButton.h>

char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "Wokwi-GUEST";
char pass[] = "";

#define MANUAL  0   //Manual Operation
#define AUTO    1   //Automaytic Operation
boolean modeChT = MANUAL;   //กำหนดให้ modeChT เป็น MANUAL

struct schedule{
  boolean setup;
  int SThour;
  int STmin;
  int STsec;
  int SPhour;
  int SPmin;
  int SPsec;
  boolean day[7];
};

boolean modeOperate = false;
boolean timer0_Active = false;
boolean timer1_Active = false;

#define RTC_DATA_PIN 21 // Pin SDA
#define RTC_CLK_PIN 22  // Pin SCL
RTC_DS1307 rtc;

schedule timer0, timer1;

BlynkTimer timer;
//unsigned char day_of_week;
//long rtc_sec;
unsigned long period = 1000; //ระยะเวลาที่ต้องการรอ
unsigned long last_time = 0; //ประกาศตัวแปรเป็น global เพื่อเก็บค่าไว้ไม่ให้ reset จากการวนloop

#define LED4 4  // BLUE
#define LED3 5  // GREEN
#define LED2 19 // YELLOW
#define LED1 23 // RED
#define SW 34  // Operation Mode (AUTO or MANUAL)
#define S1 26  // Button 1
#define S2 27  // Button 2
#define S3 14  // Button 3
#define S4 12  // Button 4

ezButton button1(S1);
ezButton button2(S2);
ezButton button3(S3);
ezButton button4(S4);

BLYNK_CONNECTED(){ // เรียกค่าเริ่มต้น เมื่อสามารถกลับมา Connect ได้
  Serial.println("BLYNK SERVER CONNECTED !!!");
  Blynk.syncVirtual(V0);
  Blynk.syncVirtual(V1);
  Blynk.syncVirtual(V2);
  Blynk.syncVirtual(V3);
  Blynk.syncVirtual(V4);
  Blynk.syncVirtual(V5);
}

BLYNK_WRITE (V4)
{
  TimeInputParam t(param);

  // Process start time
  if (t.hasStartTime())
  {
    timer0.setup = true;
    timer0.SThour = t.getStartHour();
    timer0.STmin = t.getStartMinute();
    timer0.STsec = t.getStartSecond();
    Serial.println(String("Start: ") +
                   timer0.SThour + ":" +
                   timer0.STmin + ":" +
                   timer0.STsec);
  }
  else if (t.isStartSunrise())
  {
    Serial.println("Start at sunrise");
  }
  else if (t.isStartSunset())
  {
    Serial.println("Start at sunset");
  }
  else
  {
    // Do nothing
    timer0.setup = false;
  }

  // Process stop time
  if (t.hasStopTime())
  {
    timer0.SPhour = t.getStopHour();
    timer0.SPmin = t.getStopMinute();
    timer0.SPsec = t.getStopSecond();
    Serial.println(String("Stop: ") +
                   timer0.SPhour + ":" +
                   timer0.SPmin + ":" +
                   timer0.SPsec);
  }
  else if (t.isStopSunrise())
  {
    Serial.println("Stop at sunrise");
  }
  else if (t.isStopSunset())
  {
    Serial.println("Stop at sunset");
  }
  else
  {
    // Do nothing: no stop time was set
  }

  // Process timezone
  // Timezone is already added to start/stop time
  Serial.println(String("Time zone: ") + t.getTZ());

  // Get timezone offset (in seconds)
  Serial.println(String("Time zone offset: ") + t.getTZ_Offset());

  // Process weekdays (1. Mon, 2. Tue, 3. Wed, ...)
  for (int i = 1; i <= 7; i++) {
    if (t.isWeekdaySelected(i)) {
      //Serial.println(String("Day ") + i + " is selected");
      timer0.day[i] = true;
    } else {
      timer0.day[i] = false;
    }
  }
  Serial.println();
}

BLYNK_WRITE (V5)
{
  TimeInputParam t(param);

  // Process start time
  if (t.hasStartTime())
  {
    timer1.setup = true;
    timer1.SThour = t.getStartHour();
    timer1.STmin = t.getStartMinute();
    timer1.STsec = t.getStartSecond();  
    Serial.println(String("Start: ") +
                   timer1.SThour + ":" +
                   timer1.STmin + ":" +
                   timer1.STsec);
  }
  else if (t.isStartSunrise())
  {
    Serial.println("Start at sunrise");
  }
  else if (t.isStartSunset())
  {
    Serial.println("Start at sunset");
  }
  else
  {
    // Do nothing
    timer1.setup = false;
  }

  // Process stop time
  if (t.hasStopTime())
  {
    Serial.println(String("Stop: ") +
                   t.getStopHour() + ":" +
                   t.getStopMinute() + ":" +
                   t.getStopSecond());
    timer1.SPhour = t.getStopHour();
    timer1.SPmin = t.getStopMinute();
    timer1.SPsec = t.getStopSecond();
  }
  else if (t.isStopSunrise())
  {
    Serial.println("Stop at sunrise");
  }
  else if (t.isStopSunset())
  {
    Serial.println("Stop at sunset");
  }
  else
  {
    // Do nothing: no stop time was set
  }

  // Process timezone
  // Timezone is already added to start/stop time
  Serial.println(String("Time zone: ") + t.getTZ());

  // Get timezone offset (in seconds)
  Serial.println(String("Time zone offset: ") + t.getTZ_Offset());

  // Process weekdays (1. Mon, 2. Tue, 3. Wed, ...)
  for (int i = 1; i <= 7; i++) {
    if (t.isWeekdaySelected(i)) {
      //Serial.println(String("Day ") + i + " is selected");
      timer1.day[i] = true;
    } else {
      timer1.day[i] = false;
    }
  }
  Serial.println();
}

BLYNK_WRITE (V0)
{
  int SW_State_V0 = param.asInt();
  if (SW_State_V0 == 1)
  {
    digitalWrite(LED1, HIGH);
    Serial.println("RED ON");
  }
  else
  {
    digitalWrite(LED1, LOW);
    Serial.println("RED OFF");
  }
}

BLYNK_WRITE (V1)
{
  int SW_State_V1 = param.asInt();
  if (SW_State_V1 == 1)
  {
    digitalWrite(LED2, HIGH);
    Serial.println("YELLOW ON");
  }
  else
  {
    digitalWrite(LED2, LOW);
    Serial.println("YELLOW OFF");
  }
}

BLYNK_WRITE (V2)
{
  int SW_State_V2 = param.asInt();
  if (SW_State_V2 == 1)
  {
    digitalWrite(LED3, HIGH);
    Serial.println("GREEN ON");
  }
  else
  {
    digitalWrite(LED3, LOW);
    Serial.println("GREEN OFF");
  }
}

BLYNK_WRITE (V3)
{
 int SW_State_V3 = param.asInt();
  if (SW_State_V3 == 1)
  {
    digitalWrite(LED4, HIGH);
  }
  else
  {
    digitalWrite(LED4, LOW);
    Serial.println("BLUE OFF");
  }
}

void controlOutPut()
{
    if (digitalRead(SW)==AUTO) {
      if (modeChT==MANUAL) {
        modeChT = AUTO;
        if (!timer0_Active && !timer1_Active) Blynk.virtualWrite(V6, "Automatic");
        if (!timer0_Active) {
          Blynk.setProperty(V0, "isDisabled", "false");
          Blynk.setProperty(V0, "color", "#D3435C");
        }
        if (!timer1_Active) {
          Blynk.setProperty(V1, "isDisabled", "false");
          Blynk.setProperty(V1, "color", "#FFBB29");
        }
        Blynk.setProperty(V2, "isDisabled", "false");
        Blynk.setProperty(V3, "isDisabled", "false");
        Blynk.setProperty(V2, "color", "#23C48E");
        Blynk.setProperty(V3, "color", "#04C0F8");
      }
    } else {
      if (modeChT==AUTO) {
        modeChT = MANUAL;
        Blynk.virtualWrite(V6, "Manual");
        //Blynk.setProperty(V6, "label", "Manual Mode");
        Blynk.setProperty(V0, "isDisabled", "true");
        Blynk.setProperty(V1, "isDisabled", "true");
        Blynk.setProperty(V2, "isDisabled", "true");
        Blynk.setProperty(V3, "isDisabled", "true");
      }

    }
  DateTime now = rtc.now();
  Serial.println(String("CurrentTime: ")+now.hour() + ":" + now.minute() + ":"+now.second());
  if (modeChT == AUTO){
    // --------- Timer 0 Operation ---------
    if (!timer0_Active && timer0.setup && now.hour() == timer0.SThour && now.minute() == timer0.STmin){
      timer0_Active = true;
      digitalWrite(LED1, HIGH);
      Blynk.virtualWrite(V0, HIGH);
      Blynk.setProperty(V0, "isDisabled", "true");
      Blynk.virtualWrite(V6, "Automatic - Timer 0 Active");
      Serial.println("RED ON");
    } else if(timer0_Active && timer0.setup && now.hour() == timer0.SPhour && now.minute() == timer0.SPmin) {
      timer0_Active = false;
      digitalWrite(LED1, LOW);
      Blynk.virtualWrite(V0, LOW);
      Blynk.setProperty(V0, "isDisabled", "false");
      Blynk.virtualWrite(V6, "Automatic");
      Serial.println("RED OFF");
    }
    // --------- Timer 1 Operation ---------
    if (!timer1_Active && timer1.setup && now.hour() == timer1.SThour && now.minute() == timer1.STmin){
      timer1_Active = true;
      digitalWrite(LED2, HIGH);
      Blynk.virtualWrite(V1, HIGH);
      Blynk.setProperty(V1, "isDisabled", "true");
      Blynk.virtualWrite(V6, "Automatic - Timer 1 Active");
      Serial.println("YELLOW ON");
    } else if(timer1_Active && timer1.setup && now.hour() == timer1.SPhour && now.minute() == timer1.SPmin) {
      timer1_Active = false;
      digitalWrite(LED2, LOW);
      Blynk.virtualWrite(V1, LOW);
      Blynk.setProperty(V1, "isDisabled", "false");
      Blynk.virtualWrite(V6, "Automatic");
      Serial.println("YELLOW OFF");
    }
  }
}

void setup()
{
  Wire.begin();
  rtc.begin();
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(SW, INPUT);
  pinMode(S1, INPUT);
  pinMode(S2, INPUT);
  pinMode(S3, INPUT);
  pinMode(S4, INPUT);
  Serial.begin(9600);
  button1.setDebounceTime(20);
  button2.setDebounceTime(20);
  button3.setDebounceTime(20);
  button4.setDebounceTime(20);
  Blynk.begin(auth, ssid, pass);
}

void loop()
{
  button1.loop(); // MUST call the loop() function first
  button2.loop();
  button3.loop();
  button4.loop();
  Blynk.run();
  timer.run();
  if( millis() - last_time > period) {
    last_time = millis();
    controlOutPut();
  }
  if (modeChT == MANUAL) {
      if (button1.isReleased()) {
        digitalWrite(LED1, !digitalRead(LED1));
        if (digitalRead(LED1)) Blynk.virtualWrite(V0, HIGH);
        else Blynk.virtualWrite(V0, LOW);
      }
      if (button2.isReleased()) {
        digitalWrite(LED2, !digitalRead(LED2));
        if (digitalRead(LED2)) Blynk.virtualWrite(V1, HIGH);
        else Blynk.virtualWrite(V1, LOW);
      }
      if (button3.isReleased()) {
        digitalWrite(LED3, !digitalRead(LED3));
        if (digitalRead(LED3)) Blynk.virtualWrite(V2, HIGH);
        else Blynk.virtualWrite(V2, LOW);
      }
      if (button4.isReleased()) {
        digitalWrite(LED4, !digitalRead(LED4));
        if (digitalRead(LED4)) Blynk.virtualWrite(V3, HIGH);
        else Blynk.virtualWrite(V3, LOW);      } 
  }
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
GND5VSDASCLSQWRTCDS1307+