#include <ESP32Servo.h>          // Library for servomotor on ESP32
#include <NewPing.h>             // Library for ultrasonic sensor
#include <LiquidCrystal_I2C.h>   // Library for LCD
#include <DHT.h>                 // Library for DHT sensor
#include <Wire.h>
#include <MPU6050.h>             // Library for MPU6050 sensor
#include <WiFi.h>                // ESP32 WiFi library
#include <WebServer.h>           // Library for Web server
#include <HTTPClient.h>          // Library for HTTP client

Servo servo1;

// WiFi credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";

String googleScriptID = "https://script.google.com/macros/s/AKfycbyzdYlWJggf0-tunnlZfF2wz7Q1jqzuRn-TZp2-NFeET3T-gbP4KUjVV58EcvJxbDCf/exec";

// DHT22 Setup
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// HC-SR04 Setup
#define TRIGGER_PIN 17
#define ECHO_PIN 16
#define ECHO_TIMEOUT 30000

class HCSR04 {
public:
  HCSR04(int trigger_pin, int echo_pin, int echo_timeout_us = 30000)
    : trigger(trigger_pin), echo(echo_pin), echo_timeout_us(echo_timeout_us) {
    pinMode(trigger, OUTPUT);
    pinMode(echo, INPUT);
  }

  float distance_cm() {
    digitalWrite(trigger, LOW);
    delayMicroseconds(5);
    digitalWrite(trigger, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigger, LOW);
    unsigned long duration = pulseIn(echo, HIGH, echo_timeout_us);
    float distance = (duration / 2.0) / 29.1;
    return distance;
  }

private:
  int trigger, echo;
  int echo_timeout_us;
};

HCSR04 ultrasonic_sensor(TRIGGER_PIN, ECHO_PIN);

// MPU6050 Setup
Adafruit_MPU6050 mpu;

bool initializeMPU() {
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    return false;
  }
  mpu.setAccelerometerRange(MPU6050_RANGE_2_G);
  mpu.setGyroRange(MPU6050_RANGE_250_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
  return true;
}

// I2C LCD Setup
#define I2C_ADDR 0x27
LiquidCrystal_I2C lcd(I2C_ADDR, 16, 2);

bool lcdState = false;

void display_data(float temp, float hum, float dist, float accel[3], float gyro[3]) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Temp: ");
  lcd.print(temp);
  lcd.print("C");
  delay(2000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Hum: ");
  lcd.print(hum);
  lcd.print("%");
  delay(2000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Dist: ");
  lcd.print(dist);
  lcd.print("cm");
  delay(2000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Accel: ");
  lcd.print(String(accel[0]) + "," + String(accel[1]) + "," + String(accel[2]));
  delay(2000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Gyro: ");
  lcd.print(String(gyro[0]) + "," + String(gyro[1]) + "," + String(gyro[2]));
  delay(2000);
}

void setup() {
  Serial.begin(115200);
  servo1.attach(14);

  // Initialize DHT sensor
  dht.begin();

  // Initialize MPU6050
  if (!initializeMPU()) {
    while (1) {
      delay(10);
    }
  }

  // Initialize LCD
  lcd.begin(16, 2);
  lcd.backlight();

  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

}

void loop() {
 
  // Read DHT22 sensor
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  // Read ultrasonic sensor
  float distance = ultrasonic_sensor.distance_cm();

  // Read MPU6050 sensor
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);
  float accel[3] = {a.acceleration.x, a.acceleration.y, a.acceleration.z};
  float gyro[3] = {g.gyro.x, g.gyro.y, g.gyro.z};

  // Display data on LCD if the LCD is enabled
  if (lcdState) {
    display_data(temperature, humidity, distance, accel, gyro);
  }

  delay(1000); // Delay before next loop iteration
}