Build a parking sensor that tells Blynk if the spot is free

An ultrasonic sensor on the garage wall guides the driver with green, yellow and red lights, and the Blynk app shows whether the parking spot is free or taken.
  • Level:Advanced
  • Duration: 1 h 10 min
  • Ages 12+
  • Platform: ESP32

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Build a parking sensor that tells Blynk if the spot is free – EEMENTOR STEM™ lesson

Parking in a tight garage is easier with a guide. This sensor sits on the wall in front of the parking spot, at bumper height. As the car comes closer, the light changes from green to yellow to red: stop! At the same time the ESP32 tells Blynk whether the spot is taken, so you can check from anywhere whether the car is home, and get a notification when it arrives or leaves. A spot in a shared garage, a bike rack, or a toy car garage on your desk work the same way.

What you'll learn

  • How to measure distance with the ultrasonic sensor on the ESP32 safely
  • How to turn a distance into a traffic light
  • How to decide "occupied" only when the reading is steady
  • How to send different Blynk events for different changes

What you need

  • ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
  • Ultrasonic sensor HC-SR04 (ESP32 IoT Starter Kit)
  • 3 resistors, 10 kΩ, for the voltage divider (ESP32 IoT Starter Kit)
  • Green, yellow and red LEDs and 3 resistors, 220 Ω (ESP32 IoT Starter Kit)
  • Long jumper wires or a length of cable
  • A free Blynk account and the Blynk IoT app on a phone
  • A 2.4 GHz Wi-Fi network
  • The printed parts from the 3D printing box below (wall mount), or the cardboard version described there
  • Breadboard and jumper wires (ESP32 IoT Starter Kit)

Wiring

Breadboard wiring diagram: Build a parking sensor that tells Blynk if the spot is free
Breadboard view. Check each connection against the wiring table below.
From To
Ultrasonic VCC 5V
Ultrasonic Trig ESP32 GPIO 26
Ultrasonic Echo 10 kΩ resistor, then ESP32 GPIO 27
ESP32 GPIO 27 Two 10 kΩ resistors in a row, then GND
Ultrasonic GND GND
ESP32 GPIO 25 220 Ω resistor, then the green LED's long leg
ESP32 GPIO 33 220 Ω resistor, then the yellow LED
ESP32 GPIO 32 220 Ω resistor, then the red LED
All LED short legs GND

Protect the ESP32

The HC-SR04 runs on 5 V and answers with 5 V on its Echo pin, but the ESP32's pins are made for 3.3 V. Three equal 10 kΩ resistors fix that: one from Echo to the ESP32 pin, and two in a row from the ESP32 pin to GND. The pin then sees two thirds of 5 V, about 3.3 V. The radar capstone explains it in detail.

Set up Blynk

In the Blynk console, create a new template called Parking Spot (hardware ESP32, connection type Wi-Fi) and add these datastreams. Lesson 1 of this path shows each step in detail.

Virtual pin Name Data type Range Phone widget
V0 Distance Integer 0–400 Gauge
V1 Spot String – Label
V2 Taken Integer 0–1 LED

Then open the template's Events & Notifications tab, add an event with the code car_arrived (name: Car arrived) and turn on push notifications for it. The event code must match the sketch exactly.

Save the template, create a new device from it and copy its three BLYNK_… lines. In the phone app, open the device, tap the wrench icon and add a Gauge (V0), a Label (V1) and an LED (V2). Link each widget to its datastream.

Add a second event with the code car_left (name: Car left) and turn on notifications for it too.

Example screen for: Build a parking sensor that tells Blynk if the spot is free
Example screen with sample values. Yours may look different.

The sketch

Replace the three BLYNK_… lines at the top with the ones from your device's Device info page, and add your Wi-Fi name and password (2.4 GHz only). The BLYNK_… lines must stay above #include <BlynkSimpleEsp32.h>.

Measure the distance from the wall to the bumper when the car is parked just right, and put it into STOP_CM.

#define BLYNK_TEMPLATE_ID "YOUR_TEMPLATE_ID"
#define BLYNK_TEMPLATE_NAME "Parking Spot"
#define BLYNK_AUTH_TOKEN "YOUR_AUTH_TOKEN"
#define BLYNK_PRINT Serial          // show connection messages in the Serial Monitor

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

char ssid[] = "YOUR_WIFI_NAME";
char pass[] = "YOUR_WIFI_PASSWORD";

const int TRIG_PIN = 26, ECHO_PIN = 27;
const int GREEN_PIN = 25, YELLOW_PIN = 33, RED_PIN = 32;
const int STOP_CM = 40;            // red from here: the car is parked
const int SLOW_CM = 100;           // yellow from here
const int TAKEN_CM = 150;          // anything closer than this counts as a car
const unsigned long STEADY = 10000;   // must stay the same for 10 s

BlynkTimer timer;
int distance = 400;
bool taken = false;
bool candidate = false;
unsigned long candidateSince = 0;

int measureCm() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  long us = pulseIn(ECHO_PIN, HIGH, 30000);
  return us == 0 ? 400 : min(us / 58, 400L);
}

void lights() {
  bool near = distance < TAKEN_CM;
  digitalWrite(GREEN_PIN, near && distance >= SLOW_CM);
  digitalWrite(YELLOW_PIN, near && distance >= STOP_CM && distance < SLOW_CM);
  digitalWrite(RED_PIN, near && distance < STOP_CM);
}

void measure() {
  // the median of three readings ignores a single wrong echo
  int a = measureCm(), b = measureCm(), c = measureCm();
  distance = max(min(a, b), min(max(a, b), c));
  lights();

  bool nowTaken = distance < TAKEN_CM;
  if (nowTaken != candidate) {
    candidate = nowTaken;
    candidateSince = millis();
  }
  if (candidate != taken && millis() - candidateSince > STEADY) {
    taken = candidate;
    Blynk.virtualWrite(V1, taken ? "Taken" : "Free");
    Blynk.virtualWrite(V2, taken ? 1 : 0);
    if (taken) Blynk.logEvent("car_arrived", "The car is parked.");
    else Blynk.logEvent("car_left", "The parking spot is free.");
  }
}

void report() {
  Blynk.virtualWrite(V0, distance);
}

BLYNK_CONNECTED() {
  Blynk.virtualWrite(V1, taken ? "Taken" : "Free");
  Blynk.virtualWrite(V2, taken ? 1 : 0);
}

void setup() {
  Serial.begin(115200);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(YELLOW_PIN, OUTPUT);
  pinMode(RED_PIN, OUTPUT);
  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
  timer.setInterval(250L, measure);      // fast for the lights
  timer.setInterval(2000L, report);      // slower for the app
}

void loop() {
  Blynk.run();
  timer.run();
}

How it works

The lights need quick updates, four times a second, while the app only needs a new distance every two seconds. Two BlynkTimer intervals keep those jobs apart, so the sketch doesn't flood Blynk with messages.

An ultrasonic echo sometimes bounces off the wrong thing, and one wild reading could switch the light to red for a moment. The sketch takes three readings and uses the middle one, the median, which ignores a single outlier.

A person walking past shouldn't count as a car arriving. The spot only changes to "Taken" or "Free" when the new state has lasted for 10 seconds. Until then, the change is only a candidate. This trick appears in many sensors that must not raise false alarms.

Try this next

  • Make the red LED blink when the car is closer than 20 cm: too far!
  • Count how many times the car leaves each day and show it in Blynk.
  • Use two sensors for a double garage and show both spots in the app.

Troubleshooting

  • The device shows "Offline" in the app: check the Serial Monitor at 115200 baud. "Invalid auth token" means the BLYNK_AUTH_TOKEN line is wrong; if it never connects, check the Wi-Fi name and password, and that your network is 2.4 GHz.
  • The distance is always 400: check VCC on 5V, Trig on GPIO 26 and the voltage divider on GPIO 27.
  • It says "Taken" with no car: the sensor sees something closer than 150 cm, like a bike. Make TAKEN_CM smaller.
  • No notifications: check that both events exist with exactly the codes car_arrived and car_left, with notifications on.
  • A printed part is too tight or too loose: printers differ by a few tenths of a millimetre. Sand or file a tight hole, and fix a loose part with a drop of hot glue or a strip of tape.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

ESP32 IoT Starter Kit | Arduino IDE Compatible | Free Tutorials $57.00

Shop the kit