#include <ESP32Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PubSubClient.h>
#include <WiFi.h>
//LiquidCrystal_I2C lcd(0x27, 20, 4); // LCD size parameters
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4);
Servo myservo;
const char* ssid = "Wokwi-GUEST" ;//wifi ssid
const char* password = "";
const char* mqtt_server = "test.mosquitto.org"; //MQTT broker
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
#define carEntry 25
#define carExit 33
#define trigPin1 2
#define echoPin1 15
#define trigPin2 4
#define echoPin2 16
#define trigPin3 5
#define echoPin3 17
#define trigPin4 18
#define echoPin4 19
#define trigPin5 0
#define echoPin5 23
#define servoPin 14
#define ledPin 13
int S1 = 0, S2 = 0, S3 = 0, S4 = 0, S5 = 0;
int slot = 5;
int openPosition = 0; // servo open position
int closePosition = 90; // servo close position
int carSize = 0;
int parkingSpace = 0;
long totalTimeParked = 0;
long totalToPay = 0;
long lastPaymentUpdate = 0; // Variable to store the last time the payment was updated
long duration, distance; // Declaration of duration and distance variables
unsigned long entryTimes[5] = {0, 0, 0, 0, 0}; // Array to store entry times for each parking slot
// string s1_value;
void setup() {
//Serial.begin(9600);
Serial.begin(115200);
//setup_wifi();
//client.setServer(mqtt_server,1883);
//client.setCallback(callback);
pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);
pinMode(trigPin2, OUTPUT);
pinMode(echoPin2, INPUT);
pinMode(trigPin3, OUTPUT);
pinMode(echoPin3, INPUT);
pinMode(trigPin4, OUTPUT);
pinMode(echoPin4, INPUT);
pinMode(trigPin5, OUTPUT);
pinMode(echoPin5, INPUT);
pinMode(ledPin, OUTPUT);
myservo.attach(servoPin); // servo pin
myservo.write(90);
pinMode(carEntry, INPUT);
pinMode(carExit, INPUT);
//lcd.begin(20, 4);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 1);
lcd.print(" Car parking ");
lcd.setCursor(0, 2);
lcd.print(" System ");
delay(2000);
lcd.clear();
// Read_Sensor();
int total = S1 + S2 + S3 + S4 + S5;
slot = slot - total;
for (int i = 0; i < 5; i++) {
entryTimes[i] = 0; // Initialize entry times to 0
}
setup_wifi();
client.setServer(mqtt_server,1883);
client.setCallback(callback);
}
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
String string;
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
string+=((char)payload[i]);
}
Serial.print(string);
if (topic ="/ThinkIOT/Servo-nodered") /// esp32 subscribe topic
Serial.print(" ");
int status = string.toInt();
int pos = map(status, 1, 100, 0, 180);
Serial.println(pos);
myservo.write(pos);
delay(15);
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("IotCarParkingClient")) {
Serial.println("connected");
client.subscribe("/ThinkIOT/Servo-nodered");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}}
}
// void loop() {
// if (!client.connected()) {
// reconnect();
// }
// client.loop();
// }
void publishParkingData() {
if (!client.connected()) {
reconnect();
}
String payload = String(totalTimeParked) + "," +
String(S1) + "," +
String(S2) + "," +
String(S3) + "," +
String(S4) + "," +
String(S5) + "," +
String(parkingSpace) + "," +
String(totalToPay);
// client.publish("/ThinkIOT/parking/data", payload.c_str());
}
void loop() {
Read_Sensor();
lcd.setCursor(0, 1);
if (S1 == 1) {
lcd.print("S1:Full ");
} else {
lcd.print("S1:Empty");
}
lcd.setCursor(10, 1);
if (S2 == 1) {
lcd.print("S2:Full ");
} else {
lcd.print("S2:Empty");
}
lcd.setCursor(0, 2);
if (S3 == 1) {
lcd.print("S3:Full ");
} else {
lcd.print("S3:Empty");
}
lcd.setCursor(10, 2);
if (S4 == 1) {
lcd.print("S4:Full ");
} else {
lcd.print("S4:Empty");
}
lcd.setCursor(0, 3);
if (S5 == 1) {
lcd.print("S5:Full ");
} else {
lcd.print("S5:Empty");
}
/*
**************************************************************************************
CAR ENTRY
**************************************************************************************
*/
if (checkIR(carEntry) == HIGH) {
digitalWrite(13, HIGH);
// Determine car size
carSize = getCarSize(); // Function to get the car size
// Check available parking space based on car size
parkingSpace = findParkingSpace(carSize);
if (parkingSpace != -1) {
entryTimes[parkingSpace - 1] = millis(); // Record entry time for the assigned slot
//lcd.setCursor(0, 0);
if(parkingSpace == 5) { // for electric vehicles (EV)
lcd.setCursor(0, 0);
lcd.print("Park in S");
lcd.print(parkingSpace);
lcd.print(" (EV Car) ");
} else {
lcd.setCursor(0, 0);
lcd.print("Park in S");
lcd.print(parkingSpace);
lcd.print(" ");
}
myservo.write(openPosition); // open the gate
delay(4000); // wait for a short time to avoid rapid changes
} else {
//lcd.setCursor(0, 3);
lcd.setCursor(0, 0);
lcd.print("Parking full! ");
delay(4000); // wait for a short time to avoid rapid changes
myservo.write(closePosition); // close the gate
}
} else {
digitalWrite(13, LOW);
myservo.write(closePosition); // close the gate
}
delay(1000);
/*
**************************************************************************************
CAR EXIT
**************************************************************************************
*/
if (checkIR(carExit) == HIGH) {
digitalWrite(13, HIGH);
// Randomly select a parked car for exit
//int parkedCar = random(1, 6); // Random number between 1 and 5 (number of parking slots)
carSize = getCarSize(); // Function to get the car size
lcd.setCursor(0, 0);
lcd.print("Car " + String(carSize) + " Exiting");
delay(2000);
//Serial.println("Car " + String(parkedCar) + " Exiting");
if (S1 == 1 && carSize == 1) {
totalTimeParked = (millis() - entryTimes[0]) / 1000.0;
if(totalTimeParked > 20) {
//totalToPay = 20;
totalToPay = calculateTotalPayment(totalTimeParked);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S1 Exit Time:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes ");
lcd.setCursor(0, 2);
lcd.print("Total To Pay: $" + String(totalToPay) + " ");
delay(5000);
//lcd.clear();
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S1 Exit Time:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes ");
lcd.setCursor(0, 2);
lcd.print("Goodbye");
delay(5000);
//lcd.clear();
}
delay(4000); // wait for a short time to avoid rapid changes
myservo.write(180); // close the gate
S1 = 0; // Mark slot as empty
lcd.clear();
publishParkingData();
} else if (S2 == 1 && carSize == 2) {
totalTimeParked = (millis() - entryTimes[1]) / 1000.0;
if(totalTimeParked > 20) {
//totalToPay = 20;
totalToPay = calculateTotalPayment(totalTimeParked);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S2 Total Time Parked:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes ");
lcd.setCursor(0, 2);
lcd.print("Total: $" + String(totalToPay) + " ");
delay(5000);
publishParkingData();
//lcd.clear();
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Total Time Parked:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes");
lcd.setCursor(0, 2);
lcd.print("Goodbye");
delay(5000);
publishParkingData();
//lcd.clear();
}
delay(4000); // wait for a short time to avoid rapid changes
myservo.write(180); // close the gate
S2 = 0; // Mark slot as empty
lcd.clear();
publishParkingData();
} else if (S3 == 1 && carSize == 3) {
totalTimeParked = (millis() - entryTimes[2]) / 1000.0;
if(totalTimeParked > 20) {
//totalToPay = 20;
totalToPay = calculateTotalPayment(totalTimeParked);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S3 Total Time Parked:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes");
lcd.setCursor(0, 2);
lcd.print("Total: $" + String(totalToPay) + " ");
delay(5000);
//lcd.clear();
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S3 Total Time Parked:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes");
lcd.setCursor(0, 2);
lcd.print("Goodbye");
delay(5000);
//lcd.clear();
}
delay(4000); // wait for a short time to avoid rapid changes
myservo.write(180); // close the gate
S3 = 0; // Mark slot as empty
lcd.clear();
publishParkingData();
} else if (S4 == 1 && carSize == 4) {
totalTimeParked = (millis() - entryTimes[3]) / 1000.0;
if(totalTimeParked > 20) {
//totalToPay = 20;
totalToPay = calculateTotalPayment(totalTimeParked);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S4 Total Time Parked:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes");
lcd.setCursor(0, 2);
lcd.print("Total: $" + String(totalToPay) + " ");
delay(5000);
//lcd.clear();
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S4 Total Time Parked:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes ");
lcd.setCursor(0, 2);
lcd.print("Goodbye");
delay(5000);
//lcd.clear();
}
delay(4000); // wait for a short time to avoid rapid changes
myservo.write(180); // close the gate
S4 = 0; // Mark slot as empty
lcd.clear();
publishParkingData();
} else if (S5 == 1 && carSize == 5) {
totalTimeParked = (millis() - entryTimes[4]) / 1000.0;
if(totalTimeParked > 20) {
//totalToPay = 20;
totalToPay = calculateTotalPayment(totalTimeParked);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S5 Total Time Parked:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes");
lcd.setCursor(0, 2);
lcd.print("Total: $" + String(totalToPay) + " ");
delay(5000);
//lcd.clear();
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S5 Total Time Parked:");
lcd.setCursor(0, 1);
lcd.print(String(totalTimeParked) + " Minutes");
lcd.setCursor(0, 2);
lcd.print("Goodbye");
delay(5000);
//lcd.clear();
}
delay(4000); // wait for a short time to avoid rapid changes
myservo.write(180); // close the gate
S5 = 0; // Mark slot as empty
lcd.clear();
publishParkingData();
} else {
lcd.setCursor(0, 0);
lcd.print("No car to exit. ");
}
delay(4000); // wait for a short time to avoid rapid changes
digitalWrite(13, LOW);
myservo.write(closePosition); // close the gate
} else {
digitalWrite(13, LOW);
myservo.write(closePosition); // close the gate
}
// Update payment every 20 minutes
if (millis() - lastPaymentUpdate >= 20 * 60 * 1000) {
totalToPay += 20;
lastPaymentUpdate = millis();
}
// SEND DATA VIA MQTT HERE TO NODERED
// We'll send:
//1. totalTimeParked
//2. S1,S2,S3,S4,S5 (Occupancy status of the various car slots)
//3. parkingSpace
//4. totalToPay
Serial.println("S1: " + String((S1 == 1) ? "FULL" : "EMPTY"));
if(S1 == 1){
client.publish("/ThinkIOT/parking/S1", "Full");
}
else{
client.publish("/ThinkIOT/parking/S1", "Empty");
}
Serial.println("S2: " + String((S2 == 1) ? "FULL" : "EMPTY"));
if(S2 == 1){
client.publish("/ThinkIOT/parking/S2", "Full");
}
else{
client.publish("/ThinkIOT/parking/S2", "Empty");
}
Serial.println("S3: " + String((S3 == 1) ? "FULL" : "EMPTY"));
if(S3 == 1){
client.publish("/ThinkIOT/parking/S3", "Full");
}
else{
client.publish("/ThinkIOT/parking/S3", "Empty");
}
Serial.println("S4: " + String((S4 == 1) ? "FULL" : "EMPTY"));
if(S4 == 1){
client.publish("/ThinkIOT/parking/S4", "Full");
}
else{
client.publish("/ThinkIOT/parking/S4", "Empty");
}
Serial.println("S5: " + String((S5 == 1) ? "FULL" : "EMPTY"));
if(S5 == 1){
client.publish("/ThinkIOT/parking/S5", "FALSE");
}
else{
client.publish("/ThinkIOT/parking/S5", "Empty");
}
Serial.println("Vehicle Type: " + String(carSize));
Serial.println("Total Time Parked: " + String(totalTimeParked) + " Minutes");
Serial.println("Total To Pay: $" + String(totalToPay));
client.publish("/ThinkIOT/parking/data", std::to_string(carSize).c_str());
client.publish("/ThinkIOT/parking/time", std::to_string(totalTimeParked).c_str());
client.publish("/ThinkIOT/parking/pay", std::to_string(totalToPay).c_str());
carSize = 0;
totalTimeParked = 0;
totalToPay = 0;
if (!client.connected()) {
reconnect();
}
client.loop();
delay(3000);
}
// Function to calculate the total payment based on elapsed time
int calculateTotalPayment(long elapsedMinutes) {
// Assuming $20 for the first 20 minutes and an additional $20 for every subsequent 20 minutes
return 20 * ((elapsedMinutes / 20));
}
void Read_Sensor() {
S1 = checkCar(trigPin1, echoPin1);
S2 = checkCar(trigPin2, echoPin2);
S3 = checkCar(trigPin3, echoPin3);
S4 = checkCar(trigPin4, echoPin4);
S5 = checkCar(trigPin5, echoPin5);
}
int checkCar(int trigPin, int echoPin) {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2;
if (distance < 20) { // Assuming 20 cm as the threshold for car detection
return 1;
} else {
return 0;
}
}
int checkIR(int irPin) {
return digitalRead(irPin);
}
int getCarSize() {
// Simulate determining the vehicle type and size
if (random(1, 6) == 5) { // Electric vehicle
int evalSize = random(1, 4); // Returns a random number between 1 and 3 for electric vehicle size
// 1 = Small electric vehicle
// 2 = Medium-sized electric vehicle
// 3 = Large electric vehicle
lcd.setCursor(0, 0);
lcd.print("Electric Veh: " + String(evalSize));
delay(2000);
//Serial.println("Electric Vehicle : " + String(evalSize));
if (evalSize == 1) { // Small electric vehicle parking space only
return 5;
} else {
return -1; // No space for any other size of electric vehicle
}
} else { // Regular car
return random(1, 5); // Returns a random number between 1 and 4 for regular car size
// 1 = Small car
// 2 = Medium-sized car
// 3 = Large car
// 4 = Very large car
}
}
int findParkingSpace(int carSize) {
// Mechanism to find an available parking space based on car size
lcd.setCursor(0, 0);
if(carSize != -1) {
lcd.print("car size: " + String(carSize) + " ");
} else {
lcd.print("Parking Unavailable! " );
}
delay(2000);
//Serial.println("car size: " + String(carSize));
if (carSize <= 4) { // Regular vehicles
if (carSize == 1 && S1 == 0) { // small regular vehicle
return 1;
} else if (carSize == 2 && S2 == 0) { // medium-sized regular vehicle
return 2;
} else if (carSize == 3 && S3 == 0) { // large regular vehicle
return 3;
} else if (carSize == 4 && S4 == 0) { // very large regular vehicle
return 4;
}
} else if (carSize == 5) { // Electric vehicles
// Direct medium-sized electric vehicles to spot 5 (we do not have spots for other sizes of electric vehicles)
if (S5 == 0) {
return 5;
}
}
return -1; // No available parking space for the given car size
}