#define BLYNK_TEMPLATE_ID           "TMPL6qaqr-tsf"
#define BLYNK_TEMPLATE_NAME         "IoT Project"
#define BLYNK_AUTH_TOKEN            "6TMups-NMoXaOIlJIqEMUdaC3TA-2duV"

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

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

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

// Pin Definitions
#define LDR_ANALOG_PIN 34          // Analog pin for LDR
#define LDR_DIGITAL_PIN 15         // Digital pin for LDR
#define PIR_PIN 13                 // Pin for PIR sensor
#define ULTRASONIC_TRIG 14         // Trig pin for ultrasonic sensor
#define ULTRASONIC_ECHO 27         // Echo pin for ultrasonic sensor
#define LED_PIN 2                  // Pin for LED control
#define LDR_THRESHOLD 500          // Threshold for LDR analog value

// Variables for sensor data
long duration;
int distance;
int ldrValue;
int illuminance;                   // Changed to integer for Blynk compatibility
int pirState = 0;
int ledStatus = 0;

// Function to calculate the distance using the ultrasonic sensor
void readUltrasonicDistance() {
  digitalWrite(ULTRASONIC_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(ULTRASONIC_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(ULTRASONIC_TRIG, LOW);

  duration = pulseIn(ULTRASONIC_ECHO, HIGH);
  distance = (duration * 0.034 / 2); // Convert duration to distance in cm
  
  // Ensure distance is capped between 0 and 400 cm
  if (distance > 400) {
    distance = 400;
  }
  
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");
}

// Function to read the LDR sensor value and convert it to lux
void readLDR() {
  ldrValue = analogRead(LDR_ANALOG_PIN);
  
  // Conversion to illuminance (lux) - approximation and converted to integer
  illuminance = (int)((float)ldrValue / 4096 * 10000);  // Convert to lux and round to integer

  Serial.print("LDR Illuminance: ");
  Serial.print(illuminance);
  Serial.println(" lux");

  // Check if the light level is below threshold
  if (ldrValue < LDR_THRESHOLD) {
    digitalWrite(LED_PIN, HIGH); // Turn on LED
    ledStatus = 1;
    Serial.println("Low light detected - LED ON");
  } else {
    digitalWrite(LED_PIN, LOW);  // Turn off LED
    ledStatus = 0;
    Serial.println("Sufficient light - LED OFF");
  }
}

// Function to read the PIR sensor state and interpret motion
void readPIR() {
  pirState = digitalRead(PIR_PIN);
  if (pirState == 1) {
    Serial.println("PIR State: Motion detected");
  } else {
    Serial.println("PIR State: No motion");
  }
}

// Function to send sensor data to Blynk
void sendSensorData() {
  // Send sensor data to Blynk virtual pins
  Blynk.virtualWrite(V0, pirState);       // PIR state to V0
  Blynk.virtualWrite(V1, distance);       // Distance from ultrasonic sensor to V1
  Blynk.virtualWrite(V2, illuminance);    // LDR illuminance (lux as integer) to V2
  Blynk.virtualWrite(V3, ledStatus);      // LED status to V3
}

void setup() {
  // Initialize serial communication
  Serial.begin(115200);

  // Initialize Blynk
  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);

  // Set pin modes
  pinMode(LDR_ANALOG_PIN, INPUT);
  pinMode(PIR_PIN, INPUT);
  pinMode(ULTRASONIC_TRIG, OUTPUT);
  pinMode(ULTRASONIC_ECHO, INPUT);
  pinMode(LED_PIN, OUTPUT);

  // Initial status of the LED
  digitalWrite(LED_PIN, LOW);
}

void loop() {
  Blynk.run();              // Run Blynk
  readPIR();                // Read PIR sensor
  readUltrasonicDistance();  // Read ultrasonic sensor
  readLDR();                // Read LDR sensor
  sendSensorData();         // Send data to Blynk
  delay(1000);              // Wait for 1 second before next cycle
}