Smart Parking System - Wireless Sensor Network Mini Project

Smart Parking System


Introduction 


Parking problems are not uncommon, especially for big cities. By 2023, market spending for smart parking products and services is expected to grow at a CAGR of 14% and surpass $3.8B according to an IoT Analytics report. The growth of market spending is good news because it will force people to try to find a solution to these traffic problems instead of taking no action.

The problem is quite obvious. But a bigger question is what can technology do to solve it? Is there any way to solve the problem?

In recent years an efficient design of a Wireless Sensor Network has become a leading area of research. A Sensor is a device that responds and detects some type of input from both the physical or environmental conditions, such as pressure, heat, light, etc. The output of the sensor is generally an electrical signal that is transmitted to a controller for further processing.

This smart parking solution is built which will use an ultrasonic sensor to detect vehicle presence and trigger the gate to open or close automatically. The ESP8266 NodeMCU will be used here as the main controller to control all the peripherals attached to it.

ESP8266 is the most popular controller to build IoT based applications as it has inbuilt support for Wi-Fi to connect to the internet. 

In this Smart Parking System, we will send data to the web server for looking up the availability of space for vehicle parking. Here we are using Google Sheets as a database to get the parking availability data.

Components Required


Hardware Requirements 


  • ESP8266 NodeMCU 

  • Ultrasonic Sensor

  • RFID Module

  • DC Servo Motor

  • IR Sensors

  • 16x2 i2c LCD Display

  • Jumpers


Software Requirements

  • Arduino IDE

  • Google Sheets


Circuit Diagram: 


Circuit diagram for this IoT based vehicle parking system is given below. It involves two NodeMCU,two IR sensors, two servo motors, one ultrasonic sensor and two 16x2 LCD.

Here the ESP8266 will control the complete process and also send the parking availability information to Google Firebase so that it can be monitored from anywhere in the world over the internet. Two IR sensors are used at entry and exit gate to detect the presence of car and automatically open or close the gate. IR Sensor is used to detect any object by sending and receiving the IR rays, learn more about IR sensor here.


Two servos will act as entry and exit gate and they rotate to open or close the gate. Finally an Ultrasonic sensor is used to detect if the parking slot is available or occupied and send the data to ESP8266 accordingly.


Working:



Here the ESP8266 will control the complete process and also send the parking availability information to Google Sheets so that it can be monitored from anywhere in the world over the internet. 


The IR sensors and RFID Reader  will be placed in the parking  slots that will  encounter the  presence  of the  cars inside the parking  slots. One IR  sensor and one RFID Reader  will be  placed  beside  the main entrance of the parking lot and exit of parking lot.Ultrasonic sensor are placed at every parking area to detect the presence of vehicles.As soon as the sensors get the presence of a car in front of the entrance, it will send signal to the ESP8266 to  check if  there  is an  empty  slot inside  the parking  lot.  


When NodeMCU  acknowledges  that there is an empty slot or more then it will send a signal to the  dc servo  motor which will open  the main entrance. On  the other hand if NodeMCU encounters no empty slots at the time of a car trying to make an entrance, the  gate will not open.


This is how the availability of parking can be tracked online on Firebase as shown in the snapshot below:

Getting Data for Smart Parking System using the ESP8266 NodeMC



Finally an Ultrasonic sensor is used to detect if the parking slot is available or occupied and send the data to ESP8266 accordingly.



CODE

#include <ESP8266WiFi.h>

#include <Servo.h>

#include <LiquidCrystal_I2C.h>

#include <Wire.h>

#includeRFID.h>

#include<SPI.h>

#include<LiquidCrystal.h>



#define WIFI_SSID "CircuitDigest"                    // input your home or public wifi name 

#define WIFI_PASSWORD "circuitdigest101"          //password for Wifi

String Available = "";                                                  //availability string

String fireAvailable = "";


LiquidCrystal_I2C lcd(0x27, 16, 2);         //i2c display address 27 and 16x2 lcd display

Servo myservo;                          //servo as gate

Servo myservos;                               //servo as gate

int Empty;                            //available space integer

int allSpace = 90;

int countYes = 0;

int carEnter = D0;                      // entry sensor 

int carExited = D4;                   //exi sensor

int TRIG = D7;                  //ultrasonic trig  pin

int ECHO = D8;                // ultrasonic echo pin

int led = D3;                 // spot occupancy signal

int pos;

int pos1;


long duration, distance;     


void setup() {

  delay(1000);

  Serial.begin (9600);     // serial debugging

  Wire.begin(D2, D1);       // i2c start

  myservo.attach(D6);      // servo pin to D6

  myservos.attach(D5);       // servo pin to D5

  pinMode(TRIG, OUTPUT);      // trig pin as output 

  pinMode(ECHO, INPUT);         // echo pin as input

  pinMode(led, OUTPUT);         // spot indication

  pinMode(carExited, INPUT);    // ir as input

  pinMode(carEnter, INPUT);     // ir as input


  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);           //try to connect with wifi

  Serial.print("Connecting to ");

  Serial.print(WIFI_SSID);                          // display ssid

  while (WiFi.status() != WL_CONNECTED) {

    Serial.print(".");                          // if not connected print this

    delay(500);

  }

  Serial.println();

  Serial.print("Connected to ");

  Serial.println(WIFI_SSID);

  Serial.print("IP Address is : ");

  Serial.println(WiFi.localIP());                                            //print local IP address



  lcd.begin();                           //begin lcd

  lcd.home();                            

  lcd.setCursor(0, 0);                      // 0th row and 0thh column

  lcd.print("Welcome,Show Your Card Here");    

}


void loop() {

//Check if any RFID Tags Detected or not?

if(rfid.isCard() )

{

//if RFID Tag is detected, check for the Unique ID,

//and print it on the Serial Window

if(rfid.readCardSerial() )

{

lcd.clear();

lcd.print(&quot;UNIQUE ID is:- &quot;);

delay(500);

lcd.setCursor(0,1); //Set LCD Cursor to Second Row, First Character


  digitalWrite(TRIG, LOW);         // make trig pin low

  delayMicroseconds(2);

  digitalWrite(TRIG, HIGH);        // make trig pin high

  delayMicroseconds(10);

  digitalWrite(TRIG, LOW);

  duration = pulseIn(ECHO, HIGH);

  distance = (duration / 2) / 29.1;      // take distance in cm


    Serial.print("Centimeter: ");

    Serial.println(distance);


  int carEntry = digitalRead(carEnter);      // read ir input

  if (carEntry == HIGH) {                     // if high then count and send data

    countYes++;                             //increment count

    Serial.print("Car Entered = " ); Serial.println(countYes );

    lcd.setCursor(0, 1);

    lcd.print("Car Entered");

    for (pos = 140; pos >= 45; pos -= 1) {        // change servo position

      myservos.write(pos);                       

      delay(5);

    }

    delay(2000);


    for (pos = 45; pos <= 140; pos += 1) {       // change servo position

      // in steps of 1 degree

      myservos.write(pos);

      delay(5);

    }


    Sheet.pushString("/Parking Status/", Available );    // send string to Google Sheet

    lcd.clear();

  }

  int carExit = digitalRead(carExited);              //read exit ir sensor

  if (carExit == HIGH) {                            //if high then count and send

    countYes--;                                    //decrement count

    Serial.print("Car Exited = " ); Serial.println(countYes);

    lcd.setCursor(0, 1);

    lcd.print("Car Exited");

    for (pos1 = 140; pos1 >= 45; pos1 -= 1) {         // change servo position

      myservo.write(pos1);

      delay(5);

    }

    delay(2000);


    for (pos1 = 45; pos1 <= 140; pos1 += 1) {            // change servo position

      // in steps of 1 degree

      myservo.write(pos1);

      delay(5);

    }

    Firebase.pushString("/Parking Status/", fireAvailable );  // send string to firebase

    lcd.clear();

  }

  if (distance < 6) {                      //if distance is less than 6cm then on led 

        Serial.println("Occupied ");

    digitalWrite(led, HIGH);

  }


  if (distance > 6) {                        //if distance is greater than 6cm then off led 

        Serial.println("Available ");

    digitalWrite(led, LOW);

  }


  Empty = allSpace - countYes;         //calculate available data

 

  Available = String("Available= ") + String(Empty) + String("/") + String(allSpace);       

// convert the int to string

  fireAvailable = String("Available=") + String(Empty) + String("/") + String(allSpace);


  lcd.setCursor(0, 0);

  lcd.print(Available);                 //print available data to lcd


}


CODE for RFID:

#include <SPI.h>

#include <MFRC522.h>

#include <ESP8266WiFi.h>


#include <WiFiClientSecure.h>

#include <LiquidCrystal_I2C.h>


LiquidCrystal_I2C lcd(0x27, 16, 2);

#define SS_PIN D4

#define RST_PIN D0    // Configurable, see typical pin layout above


MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance

#define BUZZ_PIN D8

#define GATE_PIN D3

const char* host = "script.google.com";

const int httpsPort = 443;

const char* fingerprint  = "46 B2 C3 44 9C 59 09 8B 01 B6 F8 BD 4C FB 00 74 91 2F EF F6"; // for https



//***********Things to change*******************

const char* ssid = "";

const char* password = "";

String GOOGLE_SCRIPT_ID = ""; // Replace by your GAS service id

const String unitName = "headquarter"; // any name without spaces and special characters

//***********Things to change*******************

uint64_t openGateMillis = 0;

WiFiClientSecure client;


void LcdClearAndPrint(String text)

{

  lcd.clear();

  lcd.setCursor(0, 0);

  lcd.print(text);

}



void Siren()

{

  for (int hz = 440; hz < 1000; hz++) {

    tone(BUZZ_PIN, hz, 50);

    delay(5);

  }


  for (int hz = 1000; hz > 440; hz--) {

    tone(BUZZ_PIN, hz, 50);

    delay(5);

  }

  digitalWrite(BUZZ_PIN, LOW);

}



void Beep()

{

  for (int i = 0; i < 1000; i++)

  {

    analogWrite(BUZZ_PIN, i);

    delayMicroseconds(50);

  }

  digitalWrite(BUZZ_PIN, LOW);

}


void Beep2()

{

  tone(BUZZ_PIN, 1000, 30);

  delay(300);

  digitalWrite(BUZZ_PIN, LOW);

}


void setup() {



  pinMode(GATE_PIN, OUTPUT);

  pinMode(BUZZ_PIN, OUTPUT);

  digitalWrite(GATE_PIN, LOW);

  digitalWrite(BUZZ_PIN, LOW);

  


  Serial.begin(921600); 


  


  lcd.begin(); // Init with pin default ESP8266 or ARDUINO

// lcd.begin(0, 2); //ESP8266-01 I2C with pin 0-SDA 2-SCL

// Turn on the blacklight and print a message.

  lcd.backlight();

  LcdClearAndPrint("Loading");


  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);


  Serial.println("Started");

  Serial.print("Connecting");

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

    Serial.print(".");

  }


  // Initialize serial communications with the PC

  while (!Serial);    

// Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)

  SPI.begin();      // Init SPI bus

  mfrc522.PCD_Init();   // Init MFRC522

  delay(4);       // Optional delay. Some board do need more time after init to be ready, see Readme

  mfrc522.PCD_DumpVersionToSerial();  // Show details of PCD - MFRC522 Card Reader details

  Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));

  LcdClearAndPrint("Ready");

}

byte readCard[4];


void HandleDataFromGoogle(String data)

{

  int ind = data.indexOf(":");

  String access = data.substring(0, ind);

  int nextInd = data.indexOf(":", ind + 1);

  String name = data.substring(ind + 1, nextInd);

  String text = data.substring(nextInd + 1, data.length());


  Serial.println(name);

  LcdClearAndPrint(name);

  lcd.setCursor(0, 1);

  lcd.print(text);

  if (access=="-1")

  {

    lcd.print(" " + String("denied"));

    Siren(); 

    LcdClearAndPrint("Ready");

  }

  else if(access=="any")

  {

    

    lcd.print(" " + String("go in"));

    OpenGate();

  }

  else if (access=="fridge")

  {

    

    lcd.print(" " + String("take it"));

    OpenGate();

  }


}


void OpenGate()

{

  openGateMillis = millis()+5000;

  digitalWrite(GATE_PIN, HIGH);

  Beep();

  delay(100);

  Beep();

}


void CloseGate()

{

  openGateMillis = 0;

  digitalWrite(GATE_PIN, LOW);

  Beep2();

  LcdClearAndPrint("Ready");

}


void loop() {

  if (openGateMillis > 0 && openGateMillis < millis())

  {

    CloseGate();

  }



  if (!mfrc522.PICC_IsNewCardPresent()) {

    return;

  }


  // Select one of the cards

  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when 

idle.

  if (!mfrc522.PICC_ReadCardSerial()) {

    return;

  }

  Serial.println(F("Scanned PICC's UID:"));

  String uid = "";

  for (uint8_t i = 0; i < 4; i++) {  //

    readCard[i] = mfrc522.uid.uidByte[i];

    Serial.print(readCard[i], HEX);

    uid += String(readCard[i],HEX);

  }

  Serial.println("");


  Beep();

  LcdClearAndPrint("Please wait...");

  String data = sendData("id=" + unitName + "&uid=" + uid,NULL);

  HandleDataFromGoogle(data);



  mfrc522.PICC_HaltA();

}



String sendData(String params, char* domain) {

  //google scripts requires two get requests 

  bool needRedir = false;

  if (domain == NULL)

  {

    domain=(char*)host;

    needRedir = true;

    params = "/macros/s/" + GOOGLE_SCRIPT_ID + "/exec?" + params;

  }

  

  Serial.println(*domain);

  String result = "";

  client.setInsecure();

  Serial.print("connecting to ");

  Serial.println(host);

  if (!client.connect(host, httpsPort)) {

    Serial.println("connection failed");

    return "";

  }


  if (client.verify(fingerprint, domain)) {

  }


  Serial.print("requesting URL: ");

  Serial.println(params);


  client.print(String("GET ") + params + " HTTP/1.1\r\n" +

    "Host: " + domain + "\r\n" +

    "Connection: close\r\n\r\n");


  Serial.println("request sent");

  while (client.connected()) {


    String line = client.readStringUntil('\n');

    //Serial.println(line);

    if (needRedir) {


    int ind = line.indexOf("/macros/echo?user");

    if (ind > 0)

    {

      Serial.println(line);

      line = line.substring(ind);

      ind = line.lastIndexOf("\r");

      line = line.substring(0, ind);

      Serial.println(line);

      result = line;

    }

    }


    if (line == "\r") {

      Serial.println("headers received");

      break;

    }

  }

  while (client.available()) {

    String line = client.readStringUntil('\n');

    if(!needRedir)

    if (line.length() > 5)

      result = line;

    //Serial.println(line);

    

    }

  if (needRedir)

    return sendData(result, "script.googleusercontent.com");

  else return result;

}

CODE for GoogleScript.js:

var timeZone="CST";

var dateTimeFormat="dd/MM/yyyy HH:mm:ss";

var logSpreadSheetId="";


function sendEmail(message, id) {

    var subject = 'Something wrong with ' + id;

    MailApp.sendEmail(emailAddress, subject, message);


}


function doGet(e) {

   var access="-1";

      var text='go home';

      var name='Who are you?';

  var json;

  var error="idk";

    Logger.log(JSON.stringify(e)); // view parameters

    var result = 'Ok'; // assume success

    if (e.parameter == 'undefined') {

        result = 'No Parameters';

    } else {


        var uid = '';

        var onlyPing=false;

        var id = 'headquarter';

        var error = '';

        for (var param in e.parameter) {


            var value = stripQuotes(e.parameter[param]);


            switch (param) {

                case 'uid':

                    uid = value;

                    break;

                case 'id':

                    id = value;

                    break;

       

                default:

                    result = "unsupported parameter";

            }

        }

      

     

      var sheet=SpreadsheetApp.getActive().getActiveSheet();

     

      var data = sheet.getDataRange().getValues();

    if (data.length == 0)

        return;

    for (var i = 0; i < data.length; i++) {


        if (data[i][0] ==uid)

        {

          name=data[i][1];

          access=data[i][2];

          text=data[i][3];

          break;

        }

       

    }

      

      

      addLog(uid,id,name,access);

       

    

       }

//     json = {

//    'access':access, 

//    'name': name,

//    'text':text,     

//    'error':error}

     

     result=(access+":"+name+":"+text);

  return ContentService.createTextOutput(result);

//  return ContentService.createTextOutput(JSON.stringify(json)

 ).setMimeType(ContentService.MimeType.JSON); 

}



function addLog(uid,entrance, name,result) {

    

    var spr=SpreadsheetApp.openById(logSpreadSheetId);

    var sheet = spr.getSheets()[0];

    var data = sheet.getDataRange().getValues();

   

    var pos = sheet.getLastRow() + 1;


    var rowData = [];

  rowData[0] = Utilities.formatDate(new Date(), timeZone, dateTimeFormat);

  rowData[4]=entrance;

  rowData[1] = uid;

  rowData[2] = name;

  rowData[3] = result;

    var newRange = sheet.getRange(pos, 1, 1, rowData.length);

    newRange.setValues([rowData]);



}




/**

 * Remove leading and trailing single or double quotes

 */

function stripQuotes(value) {

    return value.replace(/^["']|['"]$/g, "");

}


Summary of project:

In a nutshell, Smart Parking is a parking solution that can include in-ground Smart Parking sensors, cameras or counting sensors. These devices are usually embedded into parking spots or positioned next to them to detect whether parking bays are free or occupied. 


Using the project we can track the record of cars entered in a parking lot as well as see if there are any available slots in the parking lot.



Comments