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

// WiFi credentials
char auth[] = "YourAuthToken";
char ssid[] = "Wokwi-GUEST";
char pass[] = "";

// Pin definitions
#define PIR_PIN        2
#define MOISTURE_PIN   11
#define WATER_FLOW_PIN 5
#define LED_PIN        13
#define BUZZER_PIN     12
#define SERVO_PIN      14
#define DHT_PIN        15 // DHT11 data pin

// Blynk virtual pin
#define VIRTUAL_PIN    V1

// DHT sensor
#define DHT_TYPE       DHT11

DHT dht(DHT_PIN, DHT_TYPE);
Servo servo;

// Timers
unsigned long previousPIRMillis = 0;
unsigned long previousFlowMillis = 0;
const unsigned long pirInterval = 60000; // 1 minute
const unsigned long flowInterval = 300000; // 5 minutes

// Initialize Blynk with WiFi credentials and auth token
void setupBlynk() {
  Blynk.begin(auth, ssid, pass);
}

// Initialize sensors and pins
void setupSensors() {
  pinMode(PIR_PIN, INPUT);
  pinMode(MOISTURE_PIN, INPUT);
  pinMode(WATER_FLOW_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  servo.attach(SERVO_PIN);
  dht.begin();
}

// Function to send notification to Blynk app
void sendNotification() {
  Blynk.notify("Motion not detected for a long time. Check water flow!");
}

// Function to send sensor data to Blynk dashboard
void sendSensorDataToBlynk() {
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  Blynk.virtualWrite(VIRTUAL_PIN, temperature);
  Blynk.virtualWrite(VIRTUAL_PIN + 1, humidity);
}

// Function to handle motion detection
void handleMotion() {
  if (digitalRead(PIR_PIN) == HIGH) {
    digitalWrite(LED_PIN, HIGH); // Turn on LED
    unsigned long currentMillis = millis();
    if (currentMillis - previousPIRMillis >= pirInterval) {
      previousPIRMillis = currentMillis;
      sendSensorDataToBlynk();
    }
  } else {
    digitalWrite(LED_PIN, LOW); // Turn off LED
  }
}

// Function to handle moisture detection
void handleMoisture() {
  float moisture_percentage;
  int sensor_analog;
  sensor_analog = analogRead(MOISTURE_PIN);
  moisture_percentage = (100 - ((sensor_analog / 1023.00) * 100));
  if (moisture_percentage < 50) {
    servo.write(90); // Turn servo to 90 degrees if moisture is low
    delay(1000);     // Wait for servo to turn
  }
}

// Function to handle water flow detection
void handleWaterFlow() {
  if (digitalRead(WATER_FLOW_PIN) == HIGH) {
    unsigned long currentMillis = millis();
    if (currentMillis - previousFlowMillis >= flowInterval) {
      previousFlowMillis = currentMillis;
      sendNotification();
    }
  }
}

void setup() {
  Serial.begin(9600);
  setupBlynk();
  setupSensors();
}

void loop() {
  Blynk.run();
  handleMotion();
  handleMoisture();
  handleWaterFlow();
}