#include <ServoESP32.h>
#include <DHT.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Ultrasonic.h> // Use Ultrasonic library for reliable distance measurement

// Pin Definitions
#define TRIG_PIN 12
#define ECHO_PIN 14
#define DHT_PIN 4
#define DHT_TYPE DHT11
#define PIR_PIN 5
#define GREEN_LED 15
#define YELLOW_LED 2
#define RED_LED 0
#define ORANGE_LED 13
#define SERVO_PIN 18

Servo servo;
DHT dht(DHT_PIN, DHT_TYPE);
Ultrasonic ultrasonic(TRIG_PIN, ECHO_PIN);

// WiFi credentials
const char* ssid = "Your_SSID";
const char* password = "Your_PASSWORD";

// ThingSpeak API
const char* server = "http://<thingsboard_server_url>";
String apiKey = "V404LG5Z7A8U7U7F";

unsigned long lastBlinkTime = 0;
bool isBlinking = false;

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

  pinMode(PIR_PIN, INPUT);
  pinMode(GREEN_LED, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  pinMode(ORANGE_LED, OUTPUT);

  dht.begin();
  servo.attach(SERVO_PIN, 500, 2400); // Attach servo with pulse width limits
  servo.write(0);                     // Lid closed by default

  // 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() {
  // Measure bin fill level
  float distance = ultrasonic.read(); // Use Ultrasonic library
  int binHeight = 100; // Example bin height in cm
  int fillLevel = ((binHeight - distance) / binHeight) * 100; // Percentage fill

  // Measure humidity
  float humidity = dht.readHumidity();
  if (isnan(humidity)) {
    Serial.println("Failed to read humidity!");
    humidity = -1; // Set an invalid value to handle errors
  }

  // LED indicators for waste level
  digitalWrite(GREEN_LED, LOW);
  digitalWrite(YELLOW_LED, LOW);
  digitalWrite(RED_LED, LOW);

  if (fillLevel < 80) {
    digitalWrite(GREEN_LED, HIGH);
  } else if (fillLevel >= 80 && fillLevel <= 95) {
    digitalWrite(YELLOW_LED, HIGH);
  } else if (fillLevel > 95) {
    digitalWrite(RED_LED, HIGH);
  }

  // Orange LED for humidity warning
  if (humidity > 70 && humidity != -1) {
    unsigned long currentMillis = millis();
    if (currentMillis - lastBlinkTime >= 500) {
      lastBlinkTime = currentMillis;
      isBlinking = !isBlinking;
      digitalWrite(ORANGE_LED, isBlinking ? HIGH : LOW);
    }
  } else {
    digitalWrite(ORANGE_LED, LOW);
  }

  // Servo motor control based on PIR sensor
  if (digitalRead(PIR_PIN) == HIGH) {
    servo.write(90); // Open lid
    delay(3000);     // Keep open for 3 seconds
    servo.write(0);  // Close lid
  }

  // Push data to ThingSpeak
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    String url = String(server) + "?api_key=" + apiKey + "&field1=" + String(fillLevel) + "&field2=" + String(humidity);
    http.begin(url);
    int httpCode = http.GET();
    if (httpCode > 0) {
      Serial.println("Data sent to ThingSpeak!");
    } else {
      Serial.println("Failed to send data!");
    }
    http.end();
  } else {
    Serial.println("WiFi disconnected! Reconnecting...");
    WiFi.reconnect();
  }

  delay(2000); // Wait before next loop iteration
}