#define BLYNK_TEMPLATE_ID "TMPL6Sw5Gqmg3"
#define BLYNK_TEMPLATE_NAME "nongtrai"
#define BLYNK_AUTH_TOKEN "EikzG_ZNhrpt4DVvgRMxLE2ySL9Vv-pf"

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <time.h>
#include <DHT.h>

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

int gio_bat = 18;
int phut_bat = 0;
int gio_tat = 6;
int phut_tat = 30;

#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

#define SOIL_MOISTURE_SENSOR A0
int soilMoistureValue = 0;

#define relay4 26
#define button 27
#define modeButton 25
#define relay1 14
#define relay2 12
#define relay3 17
#define button2 13
#define button3 15
#define button4 16
#define button5 1 
boolean bt_state = HIGH;
boolean modeBtState = HIGH;
bool autoMode = false;
boolean button4State = HIGH;
boolean bothRelaysOn = true;
boolean button5Enabled = false;
boolean relay3State = false;  // Trạng thái ban đầu của relay3

const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 7 * 3600;
const int daylightOffset_sec = 0;

BlynkTimer timer;

void setup() {
  Serial.begin(9600);
  delay(1000);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  pinMode(relay4, OUTPUT);
  pinMode(button, INPUT_PULLUP);
  pinMode(modeButton, INPUT_PULLUP);
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(button2, INPUT_PULLUP);
  pinMode(button3, INPUT_PULLUP);
  pinMode(button4, INPUT_PULLUP);
  pinMode(button5, INPUT_PULLUP);
  pinMode(SOIL_MOISTURE_SENSOR, INPUT);
  Blynk.begin(auth, ssid, pass);
  Blynk.syncVirtual(V0);
  dht.begin();
  connectToWiFi();
  
  timer.setInterval(1000L, sendSensorReadingsToBlynk);
}

void loop() {
  Blynk.run();
  check_button();
  sendSensorReadingsToBlynk();
  checkButton5();
  timer.run();
  soilMoistureValue = analogRead(SOIL_MOISTURE_SENSOR);

  // Gửi giá trị độ ẩm đất lên chân ảo V5 trên Blynk
  Blynk.virtualWrite(V5, soilMoistureValue);
  int button4State = digitalRead(button4);
  int button5State = digitalRead(button5);
  if (!autoMode) {
    // Kiểm tra trạng thái nút nhấn button5 và cập nhật relay3
    if (button5State == LOW && !button5Enabled) {
      relay3State = !relay3State;
      digitalWrite(relay3, relay3State);
      Blynk.virtualWrite(V6, relay3State);
      button5Enabled = true;
    } else if (button5State == HIGH) {
      button5Enabled = false;
    }
  }
  if (button4State == LOW) {
    digitalWrite(relay1, LOW);
    digitalWrite(relay2, LOW);
    Blynk.virtualWrite(V4, LOW);
  }
}

BLYNK_WRITE(V4) {
  int v4State = param.asInt();
  if (v4State == LOW) {
    digitalWrite(relay1, LOW);
    digitalWrite(relay2, LOW);
    Blynk.virtualWrite(V2, LOW);
    Blynk.virtualWrite(V3, LOW);
  }
}

BLYNK_WRITE(V6) {
  int v6State = param.asInt();
  // Đảm bảo relay3 chỉ được điều khiển ở chế độ manual (autoMode = false)
  if (!autoMode) {
    relay3State = v6State;
    digitalWrite(relay3, relay3State);
  }
}

BLYNK_WRITE(V7) {
  int p = param.asInt();
  digitalWrite(relay4, p);
}

BLYNK_WRITE(V0) {
  int p = param.asInt();
  if (p == 1) {
    autoMode = true;
    digitalWrite(modeButton, HIGH);
    modeBtState = HIGH;
    delay(200);
  } else {
    autoMode = false;
    digitalWrite(modeButton, LOW);
    modeBtState = LOW;
    delay(200);
  }
}

BLYNK_WRITE(V2) {
  int v2State = param.asInt();
  digitalWrite(relay1, v2State);
  digitalWrite(relay2, !v2State);
  Blynk.virtualWrite(V3, !v2State);
}

BLYNK_WRITE(V3) {
  int v3State = param.asInt();
  digitalWrite(relay2, v3State);
  digitalWrite(relay1, !v3State);
  Blynk.virtualWrite(V2, !v3State);
}

void check_button() {
  if (autoMode) {
    struct tm timeinfo;
    if (!getLocalTime(&timeinfo)) {
      Serial.println("Failed to obtain time");
      return;
    }
    int currentHour = timeinfo.tm_hour;
    int currentMinute = timeinfo.tm_min;
    if ((currentHour >= gio_bat && currentMinute >= phut_bat) || (currentHour < gio_tat || (currentHour == gio_tat && currentMinute < phut_tat))) {
      digitalWrite(relay4, HIGH);
      Blynk.virtualWrite(V7, HIGH);
    } else {
      digitalWrite(relay4, LOW);
      Blynk.virtualWrite(V7, LOW);
    }
    int button4State = digitalRead(button4);
    if (button4State == LOW) {
      digitalWrite(relay1, LOW);
      digitalWrite(relay2, LOW);
      Blynk.virtualWrite(V4, LOW);
    } else {
      int relay1State = digitalRead(relay1);
      int relay2State = digitalRead(relay2);
    }
    float temperature = dht.readTemperature();
    if (autoMode) {
      float temperature = dht.readTemperature();
      if (!isnan(temperature)) {
        float highTemperature = 35.0;
        float lowTemperature = 35.0;
        if (temperature >= highTemperature) {
          digitalWrite(relay2, LOW);
          digitalWrite(relay1, HIGH);
          Blynk.virtualWrite(V2, digitalRead(relay1));
          Blynk.virtualWrite(V3, digitalRead(relay2));
        } else if (temperature < lowTemperature) {
          digitalWrite(relay2, HIGH);
          digitalWrite(relay1, LOW);
          Blynk.virtualWrite(V2, digitalRead(relay1));
          Blynk.virtualWrite(V3, digitalRead(relay2));
        } else {
          digitalWrite(relay1, LOW);
          digitalWrite(relay2, LOW);
        }
      }
    }
  } else {
    int buttonState = digitalRead(button);
    int button2State = digitalRead(button2);
    int button3State = digitalRead(button3);
    if (buttonState == LOW) {
      if (bt_state == HIGH) {
        digitalWrite(relay4, !digitalRead(relay4));
        Blynk.virtualWrite(V7, digitalRead(relay4));
        bt_state = LOW;
        delay(1000);
      }
    } else if (button2State == LOW) {
      digitalWrite(relay1, HIGH);
      digitalWrite(relay2, LOW);
      Blynk.virtualWrite(V2, digitalRead(relay1));
      Blynk.virtualWrite(V3, digitalRead(relay2));
    } else if (button3State == LOW) {
      digitalWrite(relay1, LOW);
      digitalWrite(relay2, HIGH);
      Blynk.virtualWrite(V2, digitalRead(relay1));
      Blynk.virtualWrite(V3, digitalRead(relay2));
    } else {
      bt_state = HIGH;
    }
    int modeButtonState = digitalRead(modeButton);
    if (modeButtonState == LOW) {
      if (modeBtState == HIGH) {
        autoMode = !autoMode;
        Blynk.virtualWrite(V0, autoMode);
        modeBtState = LOW;
        delay(1000);
      }
    } else {
      modeBtState = HIGH;
    }
  }
}

void sendSensorReadingsToBlynk() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  Blynk.virtualWrite(V1, t);
}

void checkButton5() {
  int button5State = digitalRead(button5);
  if (button5State == LOW && !autoMode) {
    // Khi `autoMode` là `false` và nút nhấn `button5` được nhấn,
    // đảo trạng thái của relay3 và cập nhật nút ảo V6
    relay3State = !relay3State;
    digitalWrite(relay3, relay3State);
    Blynk.virtualWrite(V6, relay3State);
    delay(200); // Tạo một khoảng thời gian tránh lặp nhanh
  }
}

void connectToWiFi() {
  while (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(ssid, pass);
    Serial.print("Attempting to connect to WiFi...");
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi connected");
  }
}
NOCOMNCVCCGNDINLED1PWRRelay Module