Bluetooth Low Energy (BLE) Beacon System using esp32

ESP32 BLE Beacon Smart Parking System | Wokwi Tutorial | MakeMindz

What Are We Building?

This project transforms an ESP32 DevKit into a full smart parking controller. Three ultrasonic sensors detect vehicles in each slot, a servo motor acts as a barrier gate, an I2C LCD shows real-time availability, and the ESP32's built-in Bluetooth broadcasts parking data via iBeacon protocol — all without any external WiFi or Bluetooth modules.

🔌

Built-in WiFi & BLE

No external modules needed — saves cost and PCB space.

📱

Web Dashboard

Beautiful responsive interface accessible from any browser.

🔁

RESTful API

JSON endpoints for app and cloud integration.

15× Faster

240MHz dual-core vs Arduino's 16MHz single-core.

💾

260× More RAM

520KB vs 2KB — handles BLE stacks and JSON easily.

🌐

IoT Ready

Cloud integration and OTA updates built-in.

Arduino UNO

CPU Speed16 MHz
RAM2 KB
BluetoothNone
WiFiNone

⭐ ESP32 DevKit

CPU Speed240 MHz
RAM520 KB
BluetoothBLE 4.2
WiFi802.11 b/g/n

What You Need (Virtual in Wokwi)

🔌
ESP32 DevKit V1Main controller with built-in BLE & WiFi
🔴
HC-SR04 Ultrasonic ×3Detect vehicles in each parking slot
📺
I2C LCD 16×2Show availability and BLE status
⚙️
Servo Motor (Gate)Barrier gate — opens 90° on entry
🟢
Green LEDs ×3Slot availability indicators
🔴
Red LED ×1Parking full indicator
📴
Blue LED ×1BLE connection status
🔔
BuzzerEntry, full alert, and BLE beep
👉
Push Buttons ×3SCAN, BEACON, GATE controls
220Ω Resistors ×5LED current protection

Three Control Buttons

🔍
SCAN
Pin 32
Scan for nearby BLE devices within RSSI range.
📴
BEACON
Pin 33
Toggle iBeacon / discoverable mode.
🚪
GATE
Pin 34
Manually trigger gate open if slots available.

Bluetooth Features

GATT Server — 3 Characteristics

Status Characteristic

Real-time availability: Available:3/3,Gate:CLOSED

...b7f5-ea07361b26a8
Slots Characteristic

Individual status: S1:0,S2:1,S3:0

...b7f5-ea07361b26a9
Control Characteristic

Send: OPEN, CLOSE, BEEP, or STATUS

...b7f5-ea07361b26aa

iBeacon Protocol

The ESP32 broadcasts parking availability as an iBeacon. The Major byte encodes (availableSlots << 8) | totalSlots, so any phone within range can read slot count without connecting.

TechnologyBattery Life
⭐ BLE Beacon5+ years
Cellular1–3 months
Classic Bluetooth2–4 weeks
WiFi2–5 days

📱 Mobile Native: No app installation required for beacon detection. Supports iOS/Android natively, Web Bluetooth for browsers, and background scanning.

Connect via nRF Connect App

1

Download nRF Connect (iOS/Android)

2

Scan for "ESP32_Parking"

3

Connect to the device

4

Explore services and characteristics

5

Write "OPEN" to Control Characteristic

6

Gate opens remotely! 🎉

Wiring Reference

ComponentPin/SignalESP32 Pin
Ultrasonic 1TRIG / ECHOD13 / D12
Ultrasonic 2TRIG / ECHOD14 / D27
Ultrasonic 3TRIG / ECHOD26 / D25
I2C LCDSDA / SCLD21 / D22
Servo GateSIGD15
LED Slot 1 (Green)Anode → 220ΩD16
LED Slot 2 (Green)Anode → 220ΩD17
LED Slot 3 (Green)Anode → 220ΩD18
LED Full (Red)Anode → 220ΩD19
LED BLE (Blue)Anode → 220ΩD2
Buzzer+D23
BTN SCANINPUT_PULLUPD32
BTN BEACONINPUT_PULLUPD33
BTN GATEINPUT_PULLUPD34 (input only)
LCD / UltrasonicsVCCVIN / 3V3
All GNDsGNDGND.1 / GND.2

⚠️ Important: ESP32 pin D34 is input-only — do not use it as output. The GATE button on D34 works perfectly for input with INPUT_PULLUP. Ultrasonics are powered from VIN (5V), not 3.3V.

💡 I2C LCD address: The LCD uses address 0x27. If your hardware LCD doesn't respond, try 0x3F. In Wokwi this is handled automatically.

Run in Wokwi

1

Create ESP32 Project

Go to wokwi.com, click New Project, and select ESP32 DevKit V1.

2

Paste diagram.json

Open the diagram.json tab in Wokwi and paste the JSON from the section below. All components wire instantly.

3

Paste sketch.ino

Copy the full Arduino code into Wokwi's code editor. All required libraries are pre-installed in Wokwi.

4

Click ▶ Start

The blue LED lights up indicating BLE is active. LCD shows Free:3/3 ADV. Serial Monitor displays the BLE startup log.

5

Test Controls

Press SCAN to find BLE devices, BEACON to toggle iBeacon mode, GATE to open the servo gate. Move ultrasonic sensor distance sliders to simulate parked cars.

diagram.json

Paste this into your Wokwi project's diagram.json tab to instantly wire the entire circuit — ESP32, 3 ultrasonic sensors, I2C LCD, servo, 5 LEDs, buzzer, and 3 buttons.

diagram.json — ESP32 BLE Parking System
{
  "version": 1,
  "author": "ESP32 BLE Parking",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-esp32-devkit-v1", "id": "esp32", "top": 0,    "left": 0,      "attrs": {} },
    { "type": "wokwi-lcd1602",         "id": "lcd1",  "top": -150, "left": 115.2,  "attrs": { "pins": "i2c" } },
    { "type": "wokwi-hc-sr04", "id": "ultrasonic1", "top": -267.3, "left": -176.9, "attrs": { "distance": "400" } },
    { "type": "wokwi-hc-sr04", "id": "ultrasonic2", "top": -296.1, "left": 24.7,   "attrs": { "distance": "400" } },
    { "type": "wokwi-hc-sr04", "id": "ultrasonic3", "top": -257.7, "left": 197.5,  "attrs": { "distance": "400" } },
    { "type": "wokwi-servo",    "id": "servo1", "top": 140,   "left": -144,   "attrs": {} },
    { "type": "wokwi-led", "id": "led1", "top": 280, "left": -140, "attrs": { "color": "green", "label": "Slot 1" } },
    { "type": "wokwi-led", "id": "led2", "top": 280, "left": -50,  "attrs": { "color": "green", "label": "Slot 2" } },
    { "type": "wokwi-led", "id": "led3", "top": 280, "left": 40,   "attrs": { "color": "green", "label": "Slot 3" } },
    { "type": "wokwi-led", "id": "led4", "top": 280, "left": 130,  "attrs": { "color": "red",   "label": "Full"  } },
    { "type": "wokwi-led", "id": "led5", "top": 280, "left": 220,  "attrs": { "color": "blue",  "label": "BLE"   } },
    { "type": "wokwi-resistor", "id": "r1", "top": 318, "left": -144.8, "rotate": 90, "attrs": { "value": "220" } },
    { "type": "wokwi-resistor", "id": "r2", "top": 318, "left": -54.8,  "rotate": 90, "attrs": { "value": "220" } },
    { "type": "wokwi-resistor", "id": "r3", "top": 318, "left": 35.2,   "rotate": 90, "attrs": { "value": "220" } },
    { "type": "wokwi-resistor", "id": "r4", "top": 318, "left": 125.2,  "rotate": 90, "attrs": { "value": "220" } },
    { "type": "wokwi-resistor", "id": "r5", "top": 318, "left": 215.2,  "rotate": 90, "attrs": { "value": "220" } },
    { "type": "wokwi-buzzer", "id": "bz1", "top": 140, "left": 336, "attrs": {} },
    { "type": "wokwi-pushbutton", "id": "btn1", "top": 390, "left": -115.2, "attrs": { "color": "green", "label": "SCAN"   } },
    { "type": "wokwi-pushbutton", "id": "btn2", "top": 390, "left": 0,      "attrs": { "color": "blue",  "label": "BEACON" } },
    { "type": "wokwi-pushbutton", "id": "btn3", "top": 390, "left": 115.2, "attrs": { "color": "red",   "label": "GATE"   } }
  ],
  "connections": [
    [ "esp32:TX0", "$serialMonitor:RX", "", [] ],
    [ "esp32:RX0", "$serialMonitor:TX", "", [] ],
    [ "lcd1:GND", "esp32:GND.1", "black",  ["h0"] ],
    [ "lcd1:VCC", "esp32:3V3",   "red",    ["h0"] ],
    [ "lcd1:SDA", "esp32:D21",   "blue",   ["h0"] ],
    [ "lcd1:SCL", "esp32:D22",   "yellow", ["h0"] ],
    [ "ultrasonic1:VCC",  "esp32:VIN",   "red",    ["h0"] ],
    [ "ultrasonic1:GND",  "esp32:GND.1", "black",  ["h0"] ],
    [ "ultrasonic1:TRIG", "esp32:D13",   "orange", ["h0"] ],
    [ "ultrasonic1:ECHO", "esp32:D12",   "purple", ["h0"] ],
    [ "ultrasonic2:VCC",  "esp32:VIN",   "red",    ["h0"] ],
    [ "ultrasonic2:GND",  "esp32:GND.1", "black",  ["h0"] ],
    [ "ultrasonic2:TRIG", "esp32:D14",   "orange", ["h0"] ],
    [ "ultrasonic2:ECHO", "esp32:D27",   "purple", ["h0"] ],
    [ "ultrasonic3:VCC",  "esp32:VIN",   "red",    ["h0"] ],
    [ "ultrasonic3:GND",  "esp32:GND.1", "black",  ["h0"] ],
    [ "ultrasonic3:TRIG", "esp32:D26",   "orange", ["h0"] ],
    [ "ultrasonic3:ECHO", "esp32:D25",   "purple", ["h0"] ],
    [ "servo1:V+",  "esp32:VIN",   "red",    ["h0"] ],
    [ "servo1:GND", "esp32:GND.2", "black",  ["h0"] ],
    [ "servo1:SIG", "esp32:D15",   "orange", ["h0"] ],
    [ "led1:A", "r1:1",      "green",  ["v0"] ],
    [ "r1:2",   "esp32:D16", "green",  ["v0"] ],
    [ "led1:C", "esp32:GND.1", "black", ["v0"] ],
    [ "led2:A", "r2:1",      "green",  ["v0"] ],
    [ "r2:2",   "esp32:D17", "green",  ["v0"] ],
    [ "led2:C", "esp32:GND.1", "black", ["v0"] ],
    [ "led3:A", "r3:1",      "green",  ["v0"] ],
    [ "r3:2",   "esp32:D18", "green",  ["v0"] ],
    [ "led3:C", "esp32:GND.1", "black", ["v0"] ],
    [ "led4:A", "r4:1",      "red",    ["v0"] ],
    [ "r4:2",   "esp32:D19", "red",    ["v0"] ],
    [ "led4:C", "esp32:GND.1", "black", ["v0"] ],
    [ "led5:A", "r5:1",      "blue",   ["v0"] ],
    [ "r5:2",   "esp32:D2",  "blue",   ["v0"] ],
    [ "led5:C", "esp32:GND.2", "black", ["v0"] ],
    [ "bz1:1", "esp32:D23",   "orange", ["h0"] ],
    [ "bz1:2", "esp32:GND.2", "black",  ["h0"] ],
    [ "btn1:1.l", "esp32:D32",   "green", ["h0"] ],
    [ "btn1:2.l", "esp32:GND.1", "black", ["h0"] ],
    [ "btn2:1.l", "esp32:D33",   "blue",  ["h0"] ],
    [ "btn2:2.l", "esp32:GND.1", "black", ["h0"] ],
    [ "btn3:1.l", "esp32:D34",   "red",   ["h0"] ],
    [ "btn3:2.l", "esp32:GND.1", "black", ["h0"] ]
  ],
  "dependencies": {}
}

sketch.ino

Complete ESP32 BLE parking system code. All BLE libraries are pre-installed in Wokwi for ESP32. For real hardware, install via Arduino Library Manager.

sketch.ino — ESP32 BLE Parking System
/*
 * ESP32 BLE BEACON SMART PARKING SYSTEM
 * MakeMindz IoT & Connectivity Project
 *
 * Features:
 * - BLE Beacon Broadcasting (iBeacon protocol)
 * - BLE Scanner for detecting nearby devices
 * - GATT Server for data exchange
 * - 3 Parking Slots with Ultrasonic Sensors
 * - Real-time BLE advertisement updates
 * - Proximity-based access control
 */

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <BLEBeacon.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32Servo.h>

// ── BLE UUIDs ────────────────────────────────
#define SERVICE_UUID      "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHAR_STATUS_UUID  "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define CHAR_SLOTS_UUID   "beb5483e-36e1-4688-b7f5-ea07361b26a9"
#define CHAR_CONTROL_UUID "beb5483e-36e1-4688-b7f5-ea07361b26aa"
#define BEACON_UUID       "e2c56db5-dffb-48d2-b060-d0f5a71096e0"

// ── Pin Definitions ──────────────────────────
#define TRIG1 13  #define ECHO1 12
#define TRIG2 14  #define ECHO2 27
#define TRIG3 26  #define ECHO3 25
#define LED_SLOT1  16  #define LED_SLOT2 17
#define LED_SLOT3  18  #define LED_FULL  19
#define LED_BLE    2   #define SERVO_PIN 15
#define BUZZER_PIN 23
#define BTN_SCAN   32  #define BTN_BEACON 33
#define BTN_GATE   34  // Input-only pin

LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo barrierGate;

BLEServer *pServer          = NULL;
BLECharacteristic *pCharStatus  = NULL;
BLECharacteristic *pCharSlots   = NULL;
BLECharacteristic *pCharControl = NULL;
BLEAdvertising    *pAdvertising = NULL;

bool slot1Occupied = false;
bool slot2Occupied = false;
bool slot3Occupied = false;
int  availableSlots = 3;
const int totalSlots = 3;
const int THRESHOLD_DISTANCE = 15; // cm
bool gateOpen = false;
unsigned long gateOpenTime  = 0;
const unsigned long GATE_AUTO_CLOSE = 3000;
const int GATE_CLOSED = 0, GATE_OPEN = 90;
bool bleConnected  = false;
bool bleBeaconMode = true;
int  rssiThreshold = -70;
unsigned long totalEntries = 0;

void handleBLEEntry(); void closeGate();
void openGate();      void updateBLEStatus();

class ServerCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* s) {
    bleConnected = true;
    digitalWrite(LED_BLE, HIGH);
    lcd.clear(); lcd.setCursor(0,0); lcd.print("BLE CONNECTED!");
    digitalWrite(BUZZER_PIN, HIGH); delay(100);
    digitalWrite(BUZZER_PIN, LOW);  delay(1000);
  }
  void onDisconnect(BLEServer* s) {
    bleConnected = false;
    digitalWrite(LED_BLE, LOW);
    delay(500); pAdvertising->start();
  }
};

class ControlCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *c) {
    String val = c->getValue().c_str();
    if (val == "OPEN")   handleBLEEntry();
    else if (val == "CLOSE")  closeGate();
    else if (val == "BEEP") {
      digitalWrite(BUZZER_PIN, HIGH); delay(200);
      digitalWrite(BUZZER_PIN, LOW);
    }
    else if (val == "STATUS") updateBLEStatus();
  }
};

class ScanCallbacks: public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice d) {
    Serial.print("Device: "); Serial.print(d.getName().c_str());
    Serial.print(" RSSI: "); Serial.println(d.getRSSI());
    if (d.getRSSI() > rssiThreshold) {
      Serial.println("In proximity!");
      digitalWrite(BUZZER_PIN, HIGH); delay(100);
      digitalWrite(BUZZER_PIN, LOW);
    }
  }
};

void setup() {
  Serial.begin(115200);
  lcd.init(); lcd.backlight();
  lcd.setCursor(0,0); lcd.print("BLE PARKING");
  lcd.setCursor(0,1); lcd.print("Starting...");

  pinMode(TRIG1,OUTPUT); pinMode(ECHO1,INPUT);
  pinMode(TRIG2,OUTPUT); pinMode(ECHO2,INPUT);
  pinMode(TRIG3,OUTPUT); pinMode(ECHO3,INPUT);
  pinMode(LED_SLOT1,OUTPUT); pinMode(LED_SLOT2,OUTPUT);
  pinMode(LED_SLOT3,OUTPUT); pinMode(LED_FULL,OUTPUT);
  pinMode(LED_BLE,OUTPUT);   pinMode(BUZZER_PIN,OUTPUT);
  pinMode(BTN_SCAN,INPUT_PULLUP);
  pinMode(BTN_BEACON,INPUT_PULLUP);
  pinMode(BTN_GATE,INPUT_PULLUP);

  barrierGate.attach(SERVO_PIN);
  barrierGate.write(GATE_CLOSED);
  testLEDs();
  initializeBLE();

  lcd.clear(); lcd.setCursor(0,0); lcd.print("SYSTEM READY!");
  lcd.setCursor(0,1); lcd.print("BLE Active");
  delay(2000);
  printHelp();
}

void initializeBLE() {
  BLEDevice::init("ESP32_Parking");
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new ServerCallbacks());

  BLEService *svc = pServer->createService(SERVICE_UUID);

  pCharStatus = svc->createCharacteristic(CHAR_STATUS_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
  pCharStatus->addDescriptor(new BLE2902());

  pCharSlots = svc->createCharacteristic(CHAR_SLOTS_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
  pCharSlots->addDescriptor(new BLE2902());

  pCharControl = svc->createCharacteristic(CHAR_CONTROL_UUID,
    BLECharacteristic::PROPERTY_WRITE);
  pCharControl->setCallbacks(new ControlCallbacks());

  svc->start();
  pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  setBeacon();
  BLEDevice::startAdvertising();
  Serial.println("BLE Started: ESP32_Parking");
  digitalWrite(LED_BLE, HIGH); delay(500);
  digitalWrite(LED_BLE, LOW);
}

void setBeacon() {
  BLEBeacon beacon = BLEBeacon();
  beacon.setManufacturerId(0x4C00);
  beacon.setProximityUUID(BLEUUID(BEACON_UUID));
  beacon.setMajor((availableSlots << 8) | totalSlots);
  beacon.setMinor(0x0001);
  beacon.setSignalPower(-59);

  BLEAdvertisementData advData;
  advData.setFlags(0x04);
  std::string sd = "";
  sd += (char)26; sd += (char)0xFF;
  sd += beacon.getData().c_str();
  advData.addData(sd.c_str());
  pAdvertising->setAdvertisementData(advData);
}

void loop() {
  checkParkingSlots();
  updateLCD();
  updateLEDs();

  if (bleConnected) {
    updateBLEStatus();
    static unsigned long lastBlink = 0;
    if (millis() - lastBlink > 500) {
      digitalWrite(LED_BLE, !digitalRead(LED_BLE));
      lastBlink = millis();
    }
  }

  if (digitalRead(BTN_SCAN) == LOW) {
    delay(50);
    if (digitalRead(BTN_SCAN) == LOW) {
      startBLEScan();
      while(digitalRead(BTN_SCAN)==LOW);
    }
  }
  if (digitalRead(BTN_BEACON) == LOW) {
    delay(50);
    if (digitalRead(BTN_BEACON) == LOW) {
      toggleBeaconMode();
      while(digitalRead(BTN_BEACON)==LOW);
    }
  }
  if (digitalRead(BTN_GATE) == LOW) {
    delay(50);
    if (digitalRead(BTN_GATE) == LOW) {
      handleEntry();
      while(digitalRead(BTN_GATE)==LOW);
    }
  }

  if (gateOpen && (millis() - gateOpenTime > GATE_AUTO_CLOSE))
    closeGate();

  static unsigned long lastBeaconUpdate = 0;
  if (bleBeaconMode && millis() - lastBeaconUpdate > 5000) {
    setBeacon(); lastBeaconUpdate = millis();
  }
  delay(200);
}

long getDistance(int trig, int echo) {
  digitalWrite(trig, LOW); delayMicroseconds(2);
  digitalWrite(trig, HIGH); delayMicroseconds(10);
  digitalWrite(trig, LOW);
  return pulseIn(echo, HIGH, 30000) * 0.034 / 2;
}

void checkParkingSlots() {
  slot1Occupied = (getDistance(TRIG1,ECHO1) < THRESHOLD_DISTANCE);
  slot2Occupied = (getDistance(TRIG2,ECHO2) < THRESHOLD_DISTANCE);
  slot3Occupied = (getDistance(TRIG3,ECHO3) < THRESHOLD_DISTANCE);
  availableSlots = !slot1Occupied + !slot2Occupied + !slot3Occupied;
  if (availableSlots == 0) alertParkingFull();
}

void updateLCD() {
  lcd.clear();
  lcd.print("Free:"); lcd.print(availableSlots);
  lcd.print("/");    lcd.print(totalSlots);
  lcd.print(bleConnected ? " BLE" : " ADV");
  lcd.setCursor(0,1);
  lcd.print("S1:"); lcd.print(slot1Occupied?"X":"O");
  lcd.print(" S2:"); lcd.print(slot2Occupied?"X":"O");
  lcd.print(" S3:"); lcd.print(slot3Occupied?"X":"O");
}

void updateLEDs() {
  digitalWrite(LED_SLOT1, !slot1Occupied);
  digitalWrite(LED_SLOT2, !slot2Occupied);
  digitalWrite(LED_SLOT3, !slot3Occupied);
  digitalWrite(LED_FULL, availableSlots == 0);
}

void updateBLEStatus() {
  if (!bleConnected) return;
  String st = "Available:" + String(availableSlots) + "/" + String(totalSlots);
  st += ",Gate:" + String(gateOpen ? "OPEN" : "CLOSED");
  pCharStatus->setValue(st.c_str()); pCharStatus->notify();
  String sl = "S1:" + String(slot1Occupied?"1":"0") +
              ",S2:" + String(slot2Occupied?"1":"0") +
              ",S3:" + String(slot3Occupied?"1":"0");
  pCharSlots->setValue(sl.c_str()); pCharSlots->notify();
}

void openGate() {
  if (!gateOpen) { barrierGate.write(GATE_OPEN); gateOpen = true; gateOpenTime = millis(); }
}
void closeGate() {
  if (gateOpen)  { barrierGate.write(GATE_CLOSED); gateOpen = false; }
}
void handleEntry() {
  totalEntries++;
  if (availableSlots > 0) {
    openGate(); lcd.clear(); lcd.print("WELCOME!");
    digitalWrite(BUZZER_PIN,HIGH); delay(200); digitalWrite(BUZZER_PIN,LOW);
    delay(1500);
  } else {
    lcd.clear(); lcd.print("PARKING FULL");
    for (int i=0;i<3;i++) {
      digitalWrite(BUZZER_PIN,HIGH); delay(200);
      digitalWrite(BUZZER_PIN,LOW);  delay(200);
    }
  }
}
void handleBLEEntry() {
  if (availableSlots > 0) {
    openGate(); lcd.clear(); lcd.print("BLE ENTRY");
    digitalWrite(BUZZER_PIN,HIGH); delay(100); digitalWrite(BUZZER_PIN,LOW);
  }
}
void startBLEScan() {
  lcd.clear(); lcd.print("BLE SCANNING...");
  BLEScan* scan = BLEDevice::getScan();
  scan->setAdvertisedDeviceCallbacks(new ScanCallbacks());
  scan->setActiveScan(true);
  BLEScanResults* found = scan->start(5, false);
  lcd.clear(); lcd.print("Found:"); lcd.print(found->getCount());
  delay(2000); scan->clearResults();
}
void toggleBeaconMode() {
  bleBeaconMode = !bleBeaconMode;
  lcd.clear(); lcd.print(bleBeaconMode ? "BEACON" : "DISCOVERABLE");
  digitalWrite(BUZZER_PIN,HIGH); delay(100); digitalWrite(BUZZER_PIN,LOW);
  if (bleBeaconMode) setBeacon();
  delay(2000);
}
void alertParkingFull() {
  static unsigned long lastAlert = 0;
  if (millis() - lastAlert > 5000) {
    for(int i=0;i<2;i++){
      digitalWrite(LED_FULL,HIGH);delay(200);
      digitalWrite(LED_FULL,LOW); delay(200);
    }
    digitalWrite(LED_FULL,HIGH); lastAlert = millis();
  }
}
void testLEDs() {
  digitalWrite(LED_SLOT1,HIGH);digitalWrite(LED_SLOT2,HIGH);
  digitalWrite(LED_SLOT3,HIGH);digitalWrite(LED_FULL,HIGH);
  digitalWrite(LED_BLE,HIGH); delay(500);
  digitalWrite(LED_SLOT1,LOW);digitalWrite(LED_SLOT2,LOW);
  digitalWrite(LED_SLOT3,LOW);digitalWrite(LED_FULL,LOW);
  digitalWrite(LED_BLE,LOW);
}
void printHelp() {
  Serial.println("SCAN(32) | BEACON(33) | GATE(34)");
}
ESP32 BLE BEACON PARKING SYSTEM
BLE Started: ESP32_Parking
Service: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
System Ready!
SCAN(32) | BEACON(33) | GATE(34)
Slot 1: OCCUPIED
BLE CLIENT CONNECTED!
BLE Command: OPEN GATE

Simulate in Wokwi

Pre-wired circuit with all components. Click Start Simulation, then use buttons and ultrasonic sliders to test the full parking system.

Open in Wokwi Simulator

No hardware needed. Full ESP32 BLE simulation with I2C LCD, servo gate, ultrasonic sensors, and button controls.

▶ Launch Wokwi ↗
🧪 What to test in the simulator:
  1. Click Start — blue LED lights up, LCD shows Free:3/3 ADV.
  2. Press GATE (red) — servo rotates to 90° (open), buzzer beeps, LCD shows "WELCOME!".
  3. Wait 3 seconds — gate auto-closes back to 0°.
  4. Set an ultrasonic sensor distance to <15cm — its LED turns off and slot shows "X".
  5. Press SCAN (green) — LCD shows "BLE SCANNING..." and Serial Monitor lists found devices.
  6. Press BEACON (blue) — toggles between BEACON and DISCOVERABLE mode.
  7. Occupy all 3 slots — red FULL LED flashes and buzzer alerts.

Where Can You Deploy This?

🏪
Shopping MallsMulti-floor parking with beacon network
✈️
AirportsLong-term parking with BLE payment
🌏
Smart CitiesStreet parking availability mapping
🏠
ResidentialSecure access via smartphone
🏢
OfficesEmployee parking management
🎉
EventsTemporary parking with mobile tickets

Comments

try for free