/* The first number in each array group indicates the trash bin number. 
   For example: Pins 22, 24, 26, 28, 30, and 32 correspond to Trashcan 1.
*/

// Pin definitions for ultrasonic sensors
const int TRIG_PINS[] = {22, 38, 54, 13};
const int ECHO_PINS[] = {24, 40, 55, 12};

// Pin definitions for LEDs
const int GREEN_LEDS[] = {26, 42, 56, 11};
const int YELLOW_LEDS[] = {28, 44, 57, 10};
const int RED_LEDS[] = {30, 46, 58, 9};

// Pin definitions for buzzers
const int BUZZERS[] = {32, 48, 59, 8};

// Trash can thresholds
const int maxDistance = 11;      // Max trash can height in cm
const int warningDistance = 5;  // Distance for yellow LED (warning)
const int fullDistance = 3;     // Distance for red LED (full)

void setup() {
  Serial.begin(9600);
  // Initialize ultrasonic sensors, LEDs, and buzzers
  for (int i = 0; i < 4; i++) {
    pinMode(TRIG_PINS[i], OUTPUT);
    pinMode(ECHO_PINS[i], INPUT);

    pinMode(GREEN_LEDS[i], OUTPUT);
    pinMode(YELLOW_LEDS[i], OUTPUT);
    pinMode(RED_LEDS[i], OUTPUT);

    pinMode(BUZZERS[i], OUTPUT);
    digitalWrite(BUZZERS[i], LOW); // Ensure buzzers are off initially
  }
}

void loop() {
  // Check each trash can separately
  for (int i = 0; i < 4; i++) {
    checkTrashCan(i);
  }
  delay(50); // Small delay to avoid excessive polling
}

// Function to check the status of a specific trash can
void checkTrashCan(int canIndex) {
  int distance = measureDistance(TRIG_PINS[canIndex], ECHO_PINS[canIndex]);
  Serial.print("Trash Can ");
  Serial.print(canIndex + 1);
  Serial.print(": ");
  Serial.print(distance);
  Serial.println(" cm");

  // Update LEDs and buzzer for the current trash can
  if (distance > warningDistance) {
    // Green: Almost empty
    indicateLevel(canIndex, true, false, false);
  } else if (distance <= warningDistance && distance > fullDistance) {
    // Yellow: Warning - almost full
    indicateLevel(canIndex, false, true, false);
  } else if (distance <= fullDistance) {
    // Red: Full
    indicateLevel(canIndex, false, false, true);
    buzzLong(BUZZERS[canIndex]); // Long buzz
  }
}

// Function to measure distance using an ultrasonic sensor
int measureDistance(int trigPin, int echoPin) {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  long duration = pulseIn(echoPin, HIGH, 30000); // 30ms timeout
  if (duration == 0) {
    return maxDistance + 1; // Out of range
  }
  return duration * 0.034 / 2; // Convert to cm
}

// Function to control LEDs for a trash can
void indicateLevel(int canIndex, bool green, bool yellow, bool red) {
  digitalWrite(GREEN_LEDS[canIndex], green);
  digitalWrite(YELLOW_LEDS[canIndex], yellow);
  digitalWrite(RED_LEDS[canIndex], red);
}

// Function to emit a long buzz
void buzzLong(int buzzerPin) {
  digitalWrite(buzzerPin, HIGH);
  delay(1000); // Long buzz
  digitalWrite(buzzerPin, LOW);
}