#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include "addons/TokenHelper.h"
#include "addons/RTDBHelper.h"
#include <time.h>
#include <Wire.h>
// Firebase project credentials
#define FIREBASE_PROJECT_ID "sampleProjectID"
#define FIREBASE_API_KEY "sampleAPIKEY"
// User Credentials
#define USER_EMAIL "[email protected]"
#define USER_PASSWORD "samplePW"
// Initialize the lcd instance
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Fill in the blank to create a new record in the cloud Firestore database
const String package_record_name = "Sample Package Identifier"; // Package name
// Mobile Phone Hotspot Connection
const char* ssid = "SampleDevice";
const char* password = "SamplePW";
// Define Firebase Data object, Auth and Config
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
// States and pins configuration
const int RGB_RED = 34;
const int RGB_GREEN = 35;
const int RGB_BLUE = 32;
const int TRIGGER = 17;
const int ECHO = 16;
const int SIGNAL = 19;
const int BUZZER = 23;
// State declaration for the different type of states in the system
enum State {
START,
IDLE,
CREATE_RECORD,
MONITORING,
VERIFICATION,
PACKAGE_VERIFIED,
ALERT
};
// Set initial state to START
State current_state = START;
// Variables for timing
unsigned long detectionStartTime = 0;
const unsigned long detectionDuration = 30000; // 30 seconds
unsigned long verificationStartTime = 0;
const unsigned long verificationTimeout = 60000; // 60 seconds
String package_document_id = "";
void changeState(State newState);
void changeRGBColor(int red, int green, int blue);
bool packageDetected();
long getDistance();
bool motionDetected();
String getFormattedTime();
String getFormattedDate();
void createRecordInFirebase();
void checkVerificationStatus();
void setup() {
lcd.begin();
lcd.backlight();
Wire.begin(21, 22);
Serial.begin(115200);
// WiFi connection
WiFi.begin(ssid, password);
unsigned long startAttemptTime = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 10000) {
delay(500);
Serial.print(".");
}
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Failed to connect to WiFi. Restarting...");
ESP.restart();
}
Serial.println("Connected to WiFi");
// Firebase initialization
config.api_key = FIREBASE_API_KEY;
config.database_url = "https://" FIREBASE_PROJECT_ID "-default-rtdb.firebaseio.com/";
auth.user.email = USER_EMAIL;
auth.user.password = USER_PASSWORD;
config.token_status_callback = tokenStatusCallback;
Firebase.begin(&config, &auth);
// Set time via NTP, as required for x.509 validation
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
// GPIO Pin setups
pinMode(RGB_RED, OUTPUT);
pinMode(RGB_GREEN, OUTPUT);
pinMode(RGB_BLUE, OUTPUT);
pinMode(TRIGGER, OUTPUT);
pinMode(ECHO, INPUT);
pinMode(SIGNAL, INPUT);
pinMode(BUZZER, OUTPUT);
}
void loop() {
if (Firebase.ready() && (millis() - verificationStartTime > 60000 || verificationStartTime == 0)) {
verificationStartTime = millis();
Serial.println("Firebase Token Refreshed");
}
switch (current_state) {
case START:
changeRGBColor(0, 0, 255);
lcd.clear();
lcd.print("Initiating System...");
delay(5000);
changeState(IDLE);
break;
case IDLE:
lcd.clear();
lcd.print("Idle Mode");
if (packageDetected()) {
if (detectionStartTime == 0) {
detectionStartTime = millis();
} else if (millis() - detectionStartTime >= detectionDuration) {
lcd.clear();
lcd.print("Package Detected!!");
delay(3000);
changeState(CREATE_RECORD);
}
} else {
detectionStartTime = 0;
}
break;
case CREATE_RECORD:
lcd.clear();
lcd.print("Creating Record...");
createRecordInFirebase();
changeState(MONITORING);
break;
case MONITORING:
lcd.clear();
lcd.print("Monitoring Package...");
if (motionDetected()) {
lcd.clear();
lcd.print("Verify Pickup");
changeState(VERIFICATION);
}
delay(5000);
break;
case VERIFICATION:
lcd.clear();
lcd.print("Verifying Pickup...");
checkVerificationStatus();
delay(5000);
break;
case PACKAGE_VERIFIED:
lcd.clear();
lcd.print("Collect Package");
while (current_state == PACKAGE_VERIFIED) {
long distance = getDistance();
if (distance > 20) {
changeState(IDLE);
break;
}
delay(500);
}
break;
case ALERT:
changeRGBColor(255, 0, 0);
lcd.clear();
lcd.print("Package Stolen!!!");
// Add alert logic (e.g., sound alarm, send notification)
delay(5000);
changeState(IDLE);
break;
}
}
void changeState(State newState) {
current_state = newState;
Serial.print("Moving to state ");
Serial.println(newState);
}
void changeRGBColor(int red, int green, int blue) {
analogWrite(RGB_RED, red);
analogWrite(RGB_GREEN, green);
analogWrite(RGB_BLUE, blue);
}
long getDistance() {
digitalWrite(TRIGGER, LOW);
delayMicroseconds(2);
digitalWrite(TRIGGER, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGGER, LOW);
long duration = pulseIn(ECHO, HIGH);
return duration * 0.034 / 2;
}
bool packageDetected() {
long distance = getDistance();
return (distance > 0 && distance <= 20);
}
bool motionDetected() {
return digitalRead(SIGNAL) == HIGH;
}
String getFormattedTime() {
time_t now = time(nullptr);
struct tm* timeInfo = localtime(&now);
char timeString[10];
strftime(timeString, sizeof(timeString), "%H:%M", timeInfo);
return String(timeString);
}
String getFormattedDate() {
time_t now = time(nullptr);
struct tm* timeInfo = localtime(&now);
char dateString[20];
strftime(dateString, sizeof(dateString), "%d %B %Y", timeInfo);
return String(dateString);
}
void createRecordInFirebase() {
if (Firebase.ready()) {
FirebaseJson content;
// Get the current date and time
String currentDate = getFormattedDate();
String currentTime = getFormattedTime();
// Set the fields for the package record
content.set("fields/Date_Delivered/stringValue", currentDate);
content.set("fields/Package_ID/stringValue", package_record_name);
content.set("fields/System_Alerted/stringValue", "No");
content.set("fields/Time_Delivered/stringValue", currentTime);
content.set("fields/Verification_Complete/stringValue", "No");
// Generate a unique document ID
package_document_id = "samplesigmacreationID_" + String(millis());
Serial.print("Creating record... ");
if (Firebase.Firestore.createDocument(&fbdo, FIREBASE_PROJECT_ID, "" /* databaseId can be (default) or empty */, "Package_Records/" + package_document_id, content.raw())) {
Serial.println("Success");
lcd.print("Record Created");
delay(2000);
} else {
Serial.println("Failed");
Serial.println(fbdo.errorReason());
lcd.print("Create Failed");
delay(2000);
}
} else {
Serial.println("Firebase not ready");
}
}
void checkVerificationStatus() {
if (Firebase.ready()) {
Serial.println("Checking verification status...");
if (Firebase.Firestore.getDocument(&fbdo, FIREBASE_PROJECT_ID, "", "Package_Records/" + package_document_id, "")) {
Serial.println("Document retrieved successfully");
Serial.println(fbdo.payload());
FirebaseJson json;
json.setJsonData(fbdo.payload());
FirebaseJsonData jsonData;
if (json.get(jsonData, "fields/Verification_Complete/stringValue")) {
String verificationStatus = jsonData.stringValue;
if (verificationStatus == "Yes") {
Serial.println("Package verification complete");
lcd.print("Verification Complete");
delay(2000);
changeState(PACKAGE_VERIFIED);
} else {
Serial.println("Package verification incomplete");
lcd.print("Verification Incomplete");
delay(2000);
changeState(ALERT);
}
} else {
Serial.println("Failed to get verification status from JSON");
}
} else {
Serial.print("Error getting document: ");
Serial.println(fbdo.errorReason());
}
} else {
Serial.println("Firebase not ready");
}
}