#include <WiFi.h>
#include <FirebaseESP32.h>
#include <NewPing.h>
#include <HX711.h>
#include <ESP32Servo.h>
// WiFi credentials (use Wokwi-GUEST for simulation)
const char *ssid = "Wokwi-GUEST";
const char *password = "";
// Firebase configuration (replace with your values for real hardware)
#define API_KEY "AIzaSyBre0u4WuqQJyiKyEmDepHbBCSsVRRT5tY"
#define DATABASE_URL "https://projectx-370c2-default-rtdb.firebaseio.com/" // RTDB URL
// Pins
#define LED_PIN 14
#define TRIG_PIN 5
#define ECHO_PIN 18
#define MQ_PIN 34
#define LOADCELL_DT 32
#define LOADCELL_SCK 33
#define SERVO_PIN 13
#define MAX_DISTANCE 400
// Firebase objects
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);
HX711 scale;
Servo myServo;
// System variables
const float bin_height = 100.0; // cm
const String bin_id = "BIN-A1";
const String ward_id = "WARD-A"; // Change for each ESP32: WARD-A, WARD-B, WARD-C
int sprays_today = 0;
unsigned long last_update = 0;
const long update_interval = 30000; // 30 seconds to reduce calls
unsigned long sim_time = 0; // Simulated seconds elapsed
float waste_level = 10.0; // Initial waste level
float accumulation_rate = 0.5; // % increase per 5s
float disinfectant_level = 100.0; // Initial disinfectant level
bool trigger_robot = false;
bool was_triggered = false; // To avoid redundant triggers
// fuction declarations
void connectWifi();
void initializeFirebase();
void callibrate_scale();
void setServo(int angle);
String simulate_timestamp();
void setup()
{
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
// WiFi setup
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print("Connecting to wifi");
}
Serial.println("WiFi connected");
// Firebase setup
config.api_key = API_KEY;
config.database_url = DATABASE_URL;
Firebase.begin(&config, &auth);
// Scale and Servo setup
callibrate_scale();
myServo.attach(SERVO_PIN);
}
void loop()
{
unsigned long current_time = millis();
digitalWrite(LED_PIN, HIGH);
// wait for a second
delay(1000);
// turn the LED off by making the voltage LOW
digitalWrite(LED_PIN, LOW);
if (current_time - last_update >= update_interval)
{
last_update = current_time;
// Sensor readings
float distance = sonar.ping_cm();
if (distance == 0)
distance = MAX_DISTANCE; // No echo
if (distance < 0)
distance = 0;
if (distance > bin_height)
distance = bin_height; // Cap to bin height
float waste_level = ((bin_height - distance) / bin_height) * 100.0;
if (waste_level < 0)
waste_level = 0;
if (waste_level > 100)
waste_level = 100;
float mq_value = analogRead(MQ_PIN) * 0.244; // Mock PPM calibration for
float temperature = 22 + random(-2, 2); // °C
float humidity = 45 + random(-5, 5); // %
float weight = scale.get_units(10); // kg, average 10 readings
// Cap AQI at 100%
float aqi = mq_value;
if (aqi > 100)
aqi = 100;
// Disinfectant logic
if (disinfectant_level < 0)
disinfectant_level = 0;
if (aqi > 200 && disinfectant_level >= 5)
{ // Poor air, enough disinfectant
setServo(90); // Release disinfectant
delay(1000);
setServo(0);
disinfectant_level -= 5; // Use 5% per spray
sprays_today++;
if (!was_triggered)
{
trigger_robot = true;
Serial.println("Disinfectant released, triggering robot for poor air quality");
}
}
else if (disinfectant_level < 20)
{
Serial.println("Warning: Disinfectant level low (<20%)");
}
// Waste level conditions
if (waste_level > 80 && !was_triggered)
{
trigger_robot = true;
Serial.println("Bin ripe (>80%), scheduling collection");
}
else if (waste_level == 100 && !was_triggered)
{
trigger_robot = true;
Serial.println("Bin full/overflowing (100%), triggering immediate collection");
}
// Reset after collection (simulated by Pico)
if (was_triggered && !trigger_robot)
{
waste_level = 10; // Reset to initial level
disinfectant_level = 100; // Refill disinfectant
sprays_today = 0; // Reset sprays
was_triggered = false;
Serial.println("Bin collected, reset waste and disinfectant");
}
// Firebase update only on state change or interval
String bin_collection = "/bins/";
bin_collection += bin_id;
bin_collection += "/trigger_robot";
if (trigger_robot && !was_triggered)
{
was_triggered = true;
if (Firebase.setBool(fbdo, bin_collection.c_str(), true))
{
Serial.println("Trigger flag sent to Firebase");
was_triggered = true;
}
else
{
Serial.println(fbdo.errorReason());
}
}
else if (current_time - last_update >= update_interval)
{
FirebaseJson json;
json.add("waste_level", waste_level);
json.add("aqi", aqi);
json.add("temperature", temperature);
json.add("humidity", humidity);
json.add("weight", weight);
json.add("disinfectant_level", disinfectant_level);
json.add("sprays_today", sprays_today);
json.add("timestamp", simulate_timestamp());
// if (Firebase.setJSON(fbdo, "/bins/" + bin_id, &json)) {
// Serial.println("Data sent to Firebase");
// } else {
// Serial.println(fbdo.errorReason());
// }
// if (trigger_robot) Firebase.setBool(fbdo, "/bins/" + bin_id + "/trigger_robot", false); // Reset trigger
}
// Log waste level to history array
FirebaseJson waste_entry;
waste_entry.add("level", waste_level);
waste_entry.add("timestamp", simulate_timestamp());
// Firebase.pushJSON(fbdo, "/wards/" + ward_id + "/waste_history", &waste_entry);
// Log AQI to history array
FirebaseJson aqi_entry;
aqi_entry.add("aqi", aqi);
aqi_entry.add("timestamp", simulate_timestamp());
// Firebase.pushJSON(fbdo, "/wards/" + ward_id + "/aqi_history", &aqi_entry);
// Log disinfectant level to history array
FirebaseJson disinfectant_entry;
disinfectant_entry.add("level", disinfectant_level);
disinfectant_entry.add("timestamp", simulate_timestamp());
// Firebase.pushJSON(fbdo, "/wards/" + ward_id + "/disinfectant_history", &disinfectant_entry);
// Mock other variables for analytics (e.g., bin area concentration as weight / volume)
float volume = waste_level / 100.0 * 100; // Mock volume in liters
float concentration = weight / volume;
FirebaseJson concentration_entry;
concentration_entry.add("concentration", concentration);
concentration_entry.add("timestamp", simulate_timestamp());
// Firebase.pushJSON(fbdo, "/wards/" + ward_id + "/bin_concentration_history", &concentration_entry);
}
delay(1000); // 1-second loop delay
}
// Function definitions
void initializeFirebase()
{
config.api_key = API_KEY;
config.database_url = DATABASE_URL;
Firebase.begin(&config, &auth);
}
String simulate_timestamp()
{
sim_time += 5; // Increment simulated time by 5 seconds
unsigned long total_seconds = sim_time;
unsigned long hours = total_seconds / 3600;
unsigned long minutes = (total_seconds % 3600) / 60;
unsigned long seconds = total_seconds % 60;
char buffer[25];
snprintf(buffer, sizeof(buffer), "2025-09-04T%02lu:%02lu:%02luZ", hours, minutes, seconds);
return String(buffer);
}
void connectWifi()
{
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.println("Connecting to WiFi...");
}
Serial.println("WiFi connected!");
initializeFirebase();
}
void callibrate_scale()
{
scale.begin(LOADCELL_DT, LOADCELL_SCK);
// Scale calibration (mock)
scale.set_scale(2280.f); // Adjust based on real calibration
scale.tare(); // Reset to 0
}
void setServo(int angle)
{
myServo.write(angle);
}