Circuit diagram of an ESP32-CAM based parking system with IR sensors and servo.

How to Build an IoT Smart Parking System with Arduino & ESP32

An IoT smart parking system uses connected sensors and microcontrollers to automatically detect available parking slots and show the count on a display and on a cloud dashboard. IR (infrared) obstacle sensors sit at the entry and exit gates: when a car blocks a sensor, the controller updates the free-slot count, opens the barrier gate, and sends the new count to the cloud. A driver can then check how many spaces are free before reaching the parking lot.

This guide builds the full system in two parts: an Arduino UNO reads the IR sensors, drives the servo gate and the LCD display, and an ESP32 sends the slot count to ThingSpeak over Wi-Fi. It is a popular final year project for students in Pakistan because it combines sensors, displays, motor control and IoT in one working model.

IoT smart parking system circuit diagram — Arduino UNO, ESP32, IR sensors, servo gate and LCD.

How the System Works

  1. Entry sensor — when a car arrives at the entry gate, the IR sensor detects it, the free-slot count drops by one, and the servo opens the barrier for a second.
  2. Exit sensor — when a car leaves through the exit gate, the count goes back up by one and the barrier opens again.
  3. Display — the 16×2 LCD always shows the free slots, or “PARKING FULL” when none are left.
  4. Cloud — the Arduino sends the count over serial to the ESP32, which uploads it to ThingSpeak. Anyone with the ThingSpeak link can see the parking availability online.

The count changes only when a car arrives at a sensor — not while it sits there. The sketch watches for the moment the sensor switches, so a car waiting at the gate is counted once, not again and again.

Main Components Needed

ComponentPrice / link
Arduino UNO R3 DIPArduino UNO R3 DIP ATmega328P with USB Cable — Rs 1,200
ESP32 development board (Wi-Fi + Bluetooth)ESP32 30 Pin WiFi + Bluetooth Development Board — Rs 1,100
IR obstacle sensor module × 2 (entry + exit)IR Sensor Module — Infrared Obstacle Detection — Rs 115 each
SG90 micro servo motor (barrier gate)SG90 9G Micro Servo Motor for Arduino & Robotics — Rs 300
LCD1602 16×2 display with I2C moduleLCD1602 16×2 Display with I2C Module — Rs 660
MB102 breadboard (for testing on the bench)MB102 Breadboard 830 Points — Rs 250
40-pin jumper wires40-Pin Jumper Wires 30cm — Rs 180
5V USB power supply / power bankUse any 5V USB supply (no QKZEE listing)
Cardboard or foam board, toy carsFor the parking model base

An ESP32-CAM can replace the plain ESP32 if you also want a camera at the gate — it is optional and there is no QKZEE listing for it; the build below uses the plain ESP32 board.

Wiring

IR Sensors → Arduino

IR sensor pinArduino pin
Entry OUTD2
Exit OUTD3
Both VCC5V
Both GNDGND

IR obstacle modules output LOW when they detect something in front of them. The sketch uses the Arduino’s internal pull-up resistors (INPUT_PULLUP), so no extra resistors are needed.

Servo Gate → Arduino

Servo wireArduino pin
Signal (orange / yellow)D4
Power (red)5V
Ground (brown / black)GND

The small SG90 runs from the UNO’s 5V pin in this model. For a bigger servo, power it from a separate 5V 1A supply (join its GND to the Arduino GND) — the UNO’s 5V pin cannot feed a large servo.

LCD Display → Arduino

LCD pinArduino pin
VCC5V
GNDGND
SDAA4
SCLA5

The I2C LCD needs only two data wires (SDA/SCL) plus power. Its I2C address is usually 0x27 — if the display stays blank, try 0x3F (see Troubleshooting).

ESP32 Link → Arduino

ESP32 pinArduino pin
RX2 (GPIO16)UNO TX (D1) — through a 1k + 2k voltage divider
GNDUNO GND

The UNO sends the slot count as a text line (slots:3) over its serial TX pin. The UNO’s TX is 5V, but the ESP32 RX2 pin is 3.3V logic — the divider is required: UNO TX → 1k resistor → ESP32 RX2, and ESP32 RX2 → 2k resistor → GND. Join the grounds: without a common GND the serial link will not work. The ESP32 is powered by its own USB 5V cable.

All modules share the 5V + GND rails on the breadboard.

Required Libraries

Install this one from the Arduino IDE Library Manager (Sketch → Include Library → Manage Libraries):

  • LiquidCrystal I2C by Frank de Brabander

Servo and Wire are built into the Arduino IDE — no install needed. On the ESP32 side, WiFi is built into the ESP32 board package.

Complete Arduino Code

/*
  IoT Smart Parking — ARDUINO UNO side
  Reads two IR sensors (entry D2, exit D3), drives the servo gate (D4)
  and the I2C LCD, and sends the slot count to the ESP32 as "slots:N".
  The count changes only when a car ARRIVES at a sensor (edge detection),
  so a car waiting at the gate is counted once, not again and again.
  Servo: 0 = gate open, 100 = gate closed.
*/

#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);   // I2C address 0x27 (try 0x3F if blank)
Servo gateServo;

const int irEntry = 2;
const int irExit = 3;
const int TOTAL_SLOTS = 4;

int slots = TOTAL_SLOTS;
bool entryWasLow = false;
bool exitWasLow = false;

void setup() {
  Serial.begin(9600);
  pinMode(irEntry, INPUT_PULLUP);
  pinMode(irExit, INPUT_PULLUP);
  gateServo.attach(4);
  gateServo.write(100);   // gate closed
  lcd.init();
  lcd.backlight();
  updateDisplay();
  sendSlots();
}

void loop() {
  bool entryLow = digitalRead(irEntry) == LOW;
  bool exitLow = digitalRead(irExit) == LOW;

  // Car just arrived at the entry gate
  if (entryLow && !entryWasLow) {
    if (slots > 0) {
      slots--;
      openGate();
    } else {
      Serial.println("Parking Full");
    }
    updateDisplay();
    sendSlots();
  }

  // Car just arrived at the exit gate
  if (exitLow && !exitWasLow) {
    if (slots < TOTAL_SLOTS) slots++;
    openGate();
    updateDisplay();
    sendSlots();
  }

  entryWasLow = entryLow;
  exitWasLow = exitLow;
  delay(50);
}

void openGate() {
  gateServo.write(0);     // open
  delay(1000);
  gateServo.write(100);   // close
}

void updateDisplay() {
  lcd.clear();
  lcd.setCursor(0, 0);
  if (slots == 0) {
    lcd.print("PARKING FULL");
  } else {
    lcd.print("Slots free: ");
    lcd.print(slots);
  }
  lcd.setCursor(0, 1);
  lcd.print("Smart Parking");
}

void sendSlots() {
  Serial.print("slots:");
  Serial.println(slots);
}

Complete ESP32 Code (ThingSpeak)

/*
  IoT Smart Parking — ESP32 side
  Receives "slots:N" lines from the Arduino on Serial2 (RX2 = GPIO16)
  and uploads the slot count to ThingSpeak field1 over Wi-Fi.
  Arduino TX (5V) -> 1k + 2k divider -> ESP32 RX2 (3.3V). Common GND.
*/

#include <WiFi.h>

const char* ssid = "Your_SSID";
const char* password = "Your_PASS";
const char* host = "api.thingspeak.com";
String apiKey = "YOUR_API_KEY";

void setup() {
  Serial.begin(9600);   // USB monitor
  Serial2.begin(9600, SERIAL_8N1, 16, 17);   // RX2 = GPIO16 from Arduino TX
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}

void loop() {
  if (Serial2.available()) {
    String data = Serial2.readStringUntil('\n');
    data.trim();
    if (data.startsWith("slots:")) {
      int slots = data.substring(6).toInt();
      sendToThingSpeak(slots);
    }
  }
}

void sendToThingSpeak(int slots) {
  if (WiFi.status() != WL_CONNECTED) return;
  WiFiClient client;
  if (!client.connect(host, 80)) return;
  String url = "/update?api_key=" + apiKey + "&field1=" + String(slots);
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  client.stop();
}

What the Code Does

  • The Arduino sketch reads both IR sensors every 50 ms and reacts only to the moment a sensor switches from HIGH to LOW — that is one car arriving. A car sitting in front of a sensor does not keep changing the count.
  • On entry with a free slot, the count drops, the gate opens for one second and closes. On entry with no free slot, the gate stays shut and the serial monitor prints “Parking Full”.
  • The LCD always shows the free slots, or “PARKING FULL” on the first line.
  • After every change, the Arduino sends one line — slots:3, for example — over serial. The ESP32 reads that line on Serial2, takes the number after slots:, and sends it to ThingSpeak field1 with a plain HTTP GET request. You can watch the count rise and fall on your ThingSpeak channel chart.
  • The Arduino’s Serial goes to the USB monitor AND to the ESP32 at the same time, so the Serial Monitor still shows the slots:N lines while the system runs.

How to Make the Parking Model

Step 1: Build the Model Base

Cut a parking lot from cardboard or foam board with 4 marked slots, an entry lane and an exit lane. Mount the two IR sensors at the entry and exit gates, facing across the lane so a passing car breaks the beam.

Step 2: Mount the Gate

Fix the SG90 servo at the entry gate with a small cardboard barrier arm on its horn. At 0° the arm is up (open), at 100° it is down (closed).

Step 3: Wire the Modules

Wire the sensors, servo, LCD and ESP32 link as in the tables above. Join all grounds together. Fit the 1k + 2k divider between the UNO TX and the ESP32 RX2.

Step 4: Upload Both Sketches

Upload the Arduino sketch to the UNO and the ESP32 sketch to the ESP32 board. Put your own Wi-Fi name, password and ThingSpeak API key in the ESP32 sketch first (create a free ThingSpeak account and channel with one field).

Step 5: Test with a Toy Car

Push a toy car through the entry gate and watch the LCD count drop and the gate open. Push it out through the exit gate and watch the count rise. Check the ThingSpeak chart updates too.

Testing the System

  1. Test the sensors first. Open the Serial Monitor at 9600 baud and wave your hand in front of the entry sensor — the monitor should print slots:3 and the LCD should show “Slots free: 3”. If nothing happens, check the sensor wiring and that its onboard LED changes when you block it.
  2. Test the gate. On entry the servo should swing open for one second and close. If it only twitches, its power is too weak — give it a separate 5V supply.
  3. Test the exit. Trigger the exit sensor — the count should rise by one and the gate should open. If it rises past 4, the edge detection is working but the cap is wrong — check slots < TOTAL_SLOTS.
  4. Test the cloud. Open your ThingSpeak channel after a few cars — field1 should plot the slot count over time. If the chart stays flat, check the ESP32 Wi-Fi connection and the API key.

Troubleshooting

  • LCD shows nothing: check the I2C address — most modules use 0x27, some use 0x3F. Change the address in the sketch. Also check SDA → A4 and SCL → A5, and that the backlight is on.
  • Sensor never triggers: the IR module’s onboard LED should change when you block it. If it does not, adjust the small potentiometer on the module (sensitivity) and check VCC is 5V.
  • Count drops again and again while a car waits at the gate: the edge detection is not running — check that entryWasLow / exitWasLow are updated at the end of loop() as in the sketch above.
  • Gate opens but the count does not change: the Arduino is not sending, or the ESP32 is not receiving. Check the divider (UNO TX → 1k → ESP32 RX2, RX2 → 2k → GND) and the common GND. The Serial Monitor should show slots:N lines — if it does, the Arduino side is fine and the fault is on the ESP32 side.
  • ThingSpeak never updates: check the Wi-Fi name and password, the API key, and that the ESP32 is connected (add a Serial.println(WiFi.localIP()) after the connection loop to confirm). ThingSpeak’s free account allows one update every 15 seconds — faster updates are ignored.
  • Servo only twitches: it needs more current than the UNO’s 5V pin can give. Power it from a separate 5V 1A supply and join the grounds.

Applications

  • School and college projects — sensors, display, motor control and IoT in one build.
  • Final year projects — a live cloud dashboard is easy to demonstrate to judges.
  • Smart-city demos — shows how a real parking system counts and reports spaces.
  • A base for your own version — add a slot sensor per parking bay, an RFID entry, or a buzzer when the lot is full.

Where to Buy the Components

The Arduino UNO, ESP32 board, IR sensors, SG90 servo, I2C LCD, breadboard and jumper wires are available at QKZEE Technologies, Shop 20, 1st Floor, Al-Khalil Center, Hall Road, Lahore, and online at qkzeetech.com with delivery all over Pakistan — see the links above. A 5V USB power supply is not listed on the shop — any phone charger or power bank works.

Still Stuck?

If the count does not change, or ThingSpeak never updates, message us — tell us what the Serial Monitor shows and which step you are on, and we will help you find the fault.

FAQs

Why two boards — can the ESP32 do everything alone?

Yes — the ESP32 has enough GPIO and Wi-Fi built in, so a single-board version is possible and simpler. This guide keeps the two-board design because the Arduino handles the sensors, servo and LCD while the ESP32 handles only the cloud, which is easier to debug one part at a time.

Why does the count change only when a car arrives, not while it waits?

The sketch uses edge detection: it reacts only to the moment the sensor switches from HIGH to LOW. Without it, a car waiting at the gate would be counted again every 50 ms.

What is the 1k + 2k divider for?

The Arduino TX pin sends 5V, but the ESP32 RX2 pin is 3.3V logic. The divider drops the signal to about 3.3V. Without it the ESP32 may read garbage or be damaged over time.

Do I need a ThingSpeak account?

Only for the cloud part. The parking system — sensors, gate, LCD — works fully without it. Create a free ThingSpeak account and channel (one field) only when you want the online dashboard.

Can I add one sensor per parking slot?

Yes. Give each slot its own IR sensor on its own digital pin, count how many read LOW, and show that as the occupied count. The entry/exit gate logic stays the same.

Why is the gate closed at 100° and open at 0°?

That is the convention used in this sketch — the servo horn’s rest position is 100° (arm down). If your barrier arm sits the other way, swap the two angles.

Conclusion

Building an IoT smart parking system brings together IR sensing, a servo gate, an LCD display and cloud reporting in one project. Wire the sensors on D2/D3, the servo on D4, the LCD on A4/A5, link the ESP32 through the divider, upload both sketches, and test it with a toy car before showing it to anyone. With the code in this guide, students in Pakistan can demonstrate a working system and explain every part of it — from the sensor beam to the ThingSpeak chart — to their teachers and judges.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *