#define BLYNK_TEMPLATE_ID "TMPL3DF9PhOap"
#define BLYNK_TEMPLATE_NAME "Soil"
#define BLYNK_AUTH_TOKEN "ERJgvowwuDUwPwrpAFKIeKSo8KVL7kt5"
#define BLYNK_DEVICE_NAME "Soil"

#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include "DHTesp.h"
#include <DallasTemperature.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>

#define DHT_PIN 15
#define DALLAS_TEMP_PIN 4
#define SOIL_MOISTURE_PIN 5
#define PUSH_BUTTON 2
#define SOIL_MOIST_PIN 33
#define WATER_PUMP 12
#define BUZZER 13

OneWire oneWire(DALLAS_TEMP_PIN);
DallasTemperature dallasTemp(&oneWire);

LiquidCrystal_I2C LCD = LiquidCrystal_I2C(0x27, 16, 2);

DHTesp dhtSensor;

WiFiClient client;

float dht_temp;
float dht_humidity;
float soil_temp;

unsigned long screen_lastTime = 0;
unsigned long screenDelay = 2000;

int LCD_view = 0;
bool soil_isDry = false;

const char *ssid = "Wokwi-GUEST";
const char *password = "";

void setup() {
  Serial.begin(115200);

  pinMode(PUSH_BUTTON, INPUT_PULLUP);
  pinMode(WATER_PUMP, OUTPUT);
  pinMode(BUZZER, OUTPUT);

  LCD.init();
  LCD.backlight();

  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);

  dallasTemp.begin();

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  Serial.println("Connecting to WiFi...");
  WiFi.begin(ssid, password);
  int attempts = 0;
  const int maxAttempts = 50;
  while (WiFi.status() != WL_CONNECTED && attempts < maxAttempts) {
    delay(100);
    Serial.print(".");
    LCD.setCursor(0, 0);
    LCD.print("Connecting WiFi");
    attempts++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    LCD.clear();
    LCD.setCursor(0, 0);
    LCD.print("Connected to:");
    LCD.setCursor(0, 1);
    LCD.print(ssid);
  } else {
    Serial.println("");
    Serial.println("Failed to connect to WiFi");
    LCD.clear();
    LCD.setCursor(0, 0);
    LCD.print("WiFi Connect Fail");
    LCD.setCursor(0, 1);
    LCD.print("Check Settings");
  }
  delay(500);

  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password);
}

void loop() {
  Blynk.run();

  TempAndHumidity dht = dhtSensor.getTempAndHumidity();
  dht_temp = dht.temperature;
  dht_humidity = dht.humidity;

  if (isnan(dht_temp) || isnan(dht_humidity)) {
    Serial.println("Failed to read from DHT sensor!");
  } else {
    Serial.println("DHT Temperature: " + String(dht_temp));
    Serial.println("DHT Humidity: " + String(dht_humidity));
  }

  dallasTemp.requestTemperatures();
  soil_temp = dallasTemp.getTempCByIndex(0);

  // Your soil moisture logic here

  if ((millis() - screen_lastTime) >= screenDelay) {
    update_Display(LCD_view);
    screen_lastTime = millis();
  }

  if (digitalRead(PUSH_BUTTON) == LOW) {
    LCD_view++;
    if (LCD_view > 3) {
      LCD_view = 0;
    }
    update_Display(LCD_view);
  }
}

void update_Display(int viewOption) {
  Serial.println("Air Temp: " + String(dht_temp, 2) + "°C");
  Serial.println("Humidity: " + String(dht_humidity, 1) + "%");
  Serial.println("Soil Temp: " + String(soil_temp, 2) + "°C");
  // Add soil moisture display if needed

  switch (viewOption) {
    case 0:
      if (!soil_isDry) {
        LCD.clear();
        LCD.setCursor(0, 0);
        LCD.print("Temp: " + String(dht_temp, 2) + char(223) + "C");
        LCD.setCursor(0, 1);
        LCD.print("Humidity: " + String(dht_humidity, 1) + "%");
      } else {
        LCD.clear();
        LCD.setCursor(5, 0);
        LCD.print("ALERT!");
        LCD.setCursor(0, 1);
        LCD.print("Soil is Dry");
      }
      break;
    // Add other display cases as needed
  }
}

void sendDataToBlynk() {
  Blynk.virtualWrite(V1, dht_temp);
  Blynk.virtualWrite(V2, dht_humidity);
  Blynk.virtualWrite(V3, soil_temp);
  // Add virtual writes for soil moisture if needed
}