// ===============================
// Definitions Section
// ===============================
// Blynk credentials
#define BLYNK_TEMPLATE_ID "TMPL2Pd9fVAbn" // Template ID for Blynk app
#define BLYNK_TEMPLATE_NAME "Smart Trash Bin" // Template name for Blynk app
#define BLYNK_AUTH_TOKEN "4pw1TfheUYey7-GJLZAbWz0GF76GiTlo" // Auth token for Blynk app
// WiFi credentials
#define WIFI_NAME "Wokwi-GUEST" // WiFi network name (SSID)
#define WIFI_PASSWORD "" // WiFi password
// Virtual Pins for Blynk App
#define BIN_STATUS_VIRTUAL_PIN V0 // Virtual pin for bin status (full/empty)
#define TRASH_OPEN_VIRTUAL_PIN V1 // Virtual pin for opening the trash bin
#define MESSAGE_DISPLAY_VIRTUAL_PIN V3 // Virtual pin for displaying messages
// Pin Definitions for Hardware
#define TRIG_PIN_1 4 // Ultrasonic 1 Trigger Pin (for person detection)
#define ECHO_PIN_1 16 // Ultrasonic 1 Echo Pin (for person detection)
#define TRIG_PIN_2 17 // Ultrasonic 2 Trigger Pin (for person detection)
#define ECHO_PIN_2 2 // Ultrasonic 2 Echo Pin (for person detection)
#define TRIG_PIN_3 12 // Ultrasonic 3 Trigger Pin (for bin full detection)
#define ECHO_PIN_3 14 // Ultrasonic 3 Echo Pin (for bin full detection)
#define TRIG_PIN_4 32 // Ultrasonic 4 Trigger Pin (for bin full detection)
#define ECHO_PIN_4 34 // Ultrasonic 4 Echo Pin (for bin full detection)
#define SERVO_PIN 15 // Servo Motor Pin (to open/close the bin)
#define RED_LED_PIN 13 // Red LED Pin (for bin full indication)
#define SD_CS 5 // SD card Pin
// ===============================
// Includes Section
// ===============================
#include <ESP32Servo.h> // Include library to control the servo motor
#include "RTClib.h" // Include RTC library for time functions
#include <WiFi.h> // Include WiFi library for ESP32
#include <WiFiClient.h> // Include WiFiClient library for ESP32
#include <BlynkSimpleEsp32.h> // Include Blynk library for ESP32
#include <SD.h> // Include SD Card library
// ===============================
// Variables Section
// ===============================
char auth[] = BLYNK_AUTH_TOKEN; // Store the Blynk authentication token
char ssid[] = WIFI_NAME; // Store the WiFi SSID
char pass[] = WIFI_PASSWORD; // Store the WiFi password
RTC_DS1307 rtc; // Create RTC object for timekeeping
BlynkTimer timer; // Blynk Timer for scheduling tasks
String message; // Variable to store messages
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; // Days of the week
Servo trashBinServo; // Servo object to control trash bin servo
// Ultrasonic Sensor Variables
long duration1, distance1; // For first ultrasonic sensor
long duration2, distance2; // For second ultrasonic sensor
long duration3, distance3; // For third ultrasonic sensor
long duration4, distance4; // For Fourth ultrasonic sensor
int switchState = 0; // To store the switch state from Blynk
bool isOpen = true; // Flag to store if the bin is open
bool isFull = true; // Flag to store if the bin is full
bool isOpenNow = true; // Flag to store the bin status now (opened/closed)
bool isFullNow = false; // Flag to store the bin status now (full /empty)
// ===============================
// Setup Section
// ===============================
void setup() {
// Initialize Serial Monitor for debugging
Serial.begin(115200); // Start serial communication at 115200 baud rate
Serial.println("Initializing...");
// Initialize the ultrasonic sensors
pinMode(TRIG_PIN_1, OUTPUT); // Set the first ultrasonic trigger pin to output
pinMode(ECHO_PIN_1, INPUT); // Set the first ultrasonic echo pin to input
pinMode(TRIG_PIN_2, OUTPUT); // Set the second ultrasonic trigger pin to output
pinMode(ECHO_PIN_2, INPUT); // Set the second ultrasonic echo pin to input
pinMode(TRIG_PIN_3, OUTPUT); // Set the third ultrasonic trigger pin to output (for bin full detection)
pinMode(ECHO_PIN_3, INPUT); // Set the third ultrasonic echo pin to input (for bin full detection)
pinMode(TRIG_PIN_4, OUTPUT); // Set the Fourth ultrasonic trigger pin to output (for bin full detection)
pinMode(ECHO_PIN_4, INPUT); // Set the Fourth ultrasonic echo pin to input (for bin full detection)
pinMode(RED_LED_PIN, OUTPUT); // Set the red LED pin to output
// Attach the servo motor to its pin
trashBinServo.attach(SERVO_PIN); // Attach the servo to pin 15
trashBinServo.write(0); // Set the servo to 0 degrees (initially closed)
// SD Card Initilaize
if (!SD.begin(SD_CS)) {
Serial.println("SD Card failed!");
} else {
Serial.println("SD Card initialized.");
}
// Initialize RTC (Real-Time Clock)
if (!rtc.begin()) { // Check if the RTC is connected properly
Serial.println("Couldn't find RTC"); // Print error message if RTC is not found
Serial.flush(); // Flush any remaining data
abort(); // Stop execution if RTC is not found
}
// Connect to WiFi
WiFi.begin(ssid, pass); // Start connecting to WiFi with provided credentials
while (WiFi.status() != WL_CONNECTED) { // Wait until the WiFi is connected
delay(1000); // Wait for 1 second
Serial.println("Wifi not connected..."); // Print message when WiFi is not connected
}
Serial.println("Wifi connected!"); // Print message when WiFi is connected
// Initialize Blynk
Blynk.begin(auth, ssid, pass); // Start the Blynk application with the provided authentication token, WiFi SSID, and password
}
// ===============================
// Main Loop Section
// ===============================
void loop() {
// Run Blynk library
Blynk.run(); // Process any Blynk actions
// Get distance readings from ultrasonic sensors
distance1 = getDistance(TRIG_PIN_1, ECHO_PIN_1); // Get distance from the first sensor
distance2 = getDistance(TRIG_PIN_2, ECHO_PIN_2); // Get distance from the second sensor
distance4 = getDistance(TRIG_PIN_4, ECHO_PIN_4); // Get distance from the second sensor
distance3 = getDistance(TRIG_PIN_3, ECHO_PIN_3); // Get distance from the third sensor (bin full)
// If a person is detected (distance < 30 cm), open the trash bin
if (distance1 < 30 || distance2 < 30 || distance4 < 30 ) {
Blynk.virtualWrite(TRASH_OPEN_VIRTUAL_PIN, 1); // Set the virtual pin to open the trash bin in Blynk app
openBin(); // Open the trash bin by rotating the servo
if(!isFullNow){
isOpenNow = true;
}
else{
isOpenNow = false;
}
} else {
Blynk.virtualWrite(TRASH_OPEN_VIRTUAL_PIN, 0); // Set the virtual pin to close the trash bin in Blynk app
closeBin(); // Close the trash bin by rotating the servo
isOpenNow = false;
}
// Get the distance from the third ultrasonic sensor (bin full detection)
// If the bin is full (distance < 10 cm), turn on the red LED and display the status
if (distance3 >= 10) {
if(!isFull){
message = getTimeAndPrint("Trash is empty."); // Prepare message with time and status
Blynk.virtualWrite(MESSAGE_DISPLAY_VIRTUAL_PIN, message.c_str()); // Display message in Blynk app
logToSDCard(message); // write message to data.cv file
isFull = true;
}
Blynk.virtualWrite(BIN_STATUS_VIRTUAL_PIN, 0); // Set virtual pin to indicate bin is empty in Blynk app
digitalWrite(RED_LED_PIN, LOW); // Turn off red LED (bin is not full)
}
else if (distance3 < 10 && (false == isOpenNow)){
if(isFull){
message = getTimeAndPrint("Trash is full."); // Prepare message with time and status
Blynk.virtualWrite(MESSAGE_DISPLAY_VIRTUAL_PIN, message.c_str()); // Display message in Blynk app
logToSDCard(message); // write message to data.cv file
isFull = false;
}
Blynk.virtualWrite(BIN_STATUS_VIRTUAL_PIN, 1); // Set virtual pin to indicate bin is full in Blynk app
digitalWrite(RED_LED_PIN, HIGH); // Turn on red LED (indicates that the bin is full)
}
else { // distance3 < 10 && (true == isOpenNow)
/*Do Nothing*/
}
delay(200); // Delay for 200 milliseconds for stability
}
// ===============================
// Functions Section
// ===============================
// Function to calculate the distance using the ultrasonic sensor
long getDistance(int trigPin, int echoPin) {
digitalWrite(trigPin, LOW); // Set trigger pin low to start the measurement
delayMicroseconds(2); // Wait for 2 microseconds to stabilize
digitalWrite(trigPin, HIGH); // Send a 10-microsecond pulse to the trigger pin
delayMicroseconds(10);
digitalWrite(trigPin, LOW); // Stop sending pulse by setting trigger pin low
// Measure the duration of the pulse from the echo pin
long duration = pulseIn(echoPin, HIGH); // Measure the pulse duration from echo pin
long distance = (duration / 2) * 0.0344; // Calculate distance in cm using the duration
return distance; // Return the calculated distance
}
// Function to open the trash bin (rotate the servo motor)
void openBin() {
if(isOpen){
message = getTimeAndPrint("Trash is open."); // Prepare message with time and status
Blynk.virtualWrite(MESSAGE_DISPLAY_VIRTUAL_PIN, message.c_str()); // Display message in Blynk app
logToSDCard(message); // write message to data.cv file
isOpen = false;
}
trashBinServo.write(90); // Rotate servo to 90 degrees (open the trash bin)
delay(4000); // Keep the bin open for 4 seconds before closing
}
// Function to close the trash bin (rotate the servo motor back)
void closeBin() {
if(!isOpen){
message = getTimeAndPrint("Trash is closed"); // Prepare message with time and status
Blynk.virtualWrite(MESSAGE_DISPLAY_VIRTUAL_PIN, message.c_str()); // Display message in Blynk app
logToSDCard(message); // write message to data.cv file
isOpen = true;
}
trashBinServo.write(0); // Rotate servo to 0 degrees (close the trash bin)
}
// Function to get the current time and return it as a string
String getTimeAndPrint(String Operation) {
delay(1000); // Wait for 1 second before getting the time from the RTC
DateTime now = rtc.now(); // Get the current time from RTC
int hour12 = now.hour() % 12; // Convert the hour to 12-hour format
if (hour12 == 0) hour12 = 12; // Convert hour 0 to 12 (AM/PM format)
String ampm = (now.hour() >= 12) ? "PM" : "AM"; // Determine if it's AM or PM
// Construct the time string in a readable format
String timeString = String(now.year(), DEC) + "/" +
String(now.month(), DEC) + "/" +
String(now.day(), DEC) + " (" +
daysOfTheWeek[now.dayOfTheWeek()] + ") " +
String(hour12, DEC) + ":";
if (now.minute() < 10) {
timeString += "0"; // Add leading zero for minutes less than 10
}
timeString += String(now.minute(), DEC) + ":";
if (now.second() < 10) {
timeString += "0"; // Add leading zero for seconds less than 10
}
timeString += String(now.second(), DEC) + " " + ampm + " --> " + Operation; // Add AM/PM
// Print the time to Serial Monitor
Serial.print("Current time: ");
Serial.println(timeString);
return timeString; // Return the time string
}
// Define a function to log a message to the SD card
void logToSDCard(String message) {
// Open the file "data.csv" in append mode, to add new data at the end of the file
File dataFile = SD.open("/data.csv", FILE_APPEND);
// Check if the file was successfully opened
if (dataFile) {
// Write the message to the file followed by a new line
dataFile.println(message);
// Close the file after writing the data
dataFile.close();
// Print a message to the Serial Monitor to confirm that data was saved
Blynk.virtualWrite(MESSAGE_DISPLAY_VIRTUAL_PIN, "Data saved to SD Card.");
Serial.println("Data saved to SD Card.");
} else {
// If the file could not be opened, print an error message to the Serial Monitor
Blynk.virtualWrite(MESSAGE_DISPLAY_VIRTUAL_PIN, "Error opening file!");
Serial.println("Error opening file!");
}
}
// Blynk virtual pin write handler for controlling bin
BLYNK_WRITE(V2) {
switchState = param.asInt(); // Read the value from the virtual pin
if (switchState == 1) { // If switch is ON
Blynk.virtualWrite(TRASH_OPEN_VIRTUAL_PIN, 1); // Open the trash bin in Blynk app
openBin(); // Open the trash bin
} else { // If switch is OFF
Blynk.virtualWrite(TRASH_OPEN_VIRTUAL_PIN, 0); // Close the trash bin in Blynk app
closeBin(); // Close the trash bin
}
}