Table of Contents
System Overview
Smart parking systems reduce traffic congestion and driver frustration by guiding vehicles directly to available spots. Our system uses ultrasonic sensors to detect occupancy and provides real-time data to drivers via a mobile app.
- Reduce parking search time by 40-60%
- Lower carbon emissions from circling vehicles
- Improve customer experience
- Enable dynamic pricing based on demand
- Collect parking usage analytics
- Support reservation systems
System Architecture
[Ultrasonic Sensors] â [ESP32 Nodes] â [WiFi] â [Azure IoT Hub]
â
[Azure Functions]
â
[Cosmos DB]
â
[Mobile App]
Hardware Components
Per Parking Space Node
- ESP32 DevKit: WiFi-enabled microcontroller
- HC-SR04 Ultrasonic Sensor: Distance measurement (2-400cm)
- LED Indicator: Red/Green status LED
- Lithium Battery: 18650 with charging circuit
- Solar Panel (optional): 5V for outdoor charging
- Waterproof Enclosure: IP65 rated for outdoor use
Gateway/Concentrator
- Raspberry Pi 4: Central gateway (optional)
- 4G/LTE Module: Cellular backhaul
- Entry Display: LED matrix showing available spots
HC-SR04 Specifications
| Parameter | Value |
|---|---|
| Operating Voltage | 5V DC |
| Range | 2cm - 400cm |
| Accuracy | Âą3mm |
| Beam Angle | 15 degrees |
| Current Draw | 15mA (active), <50ΞA (sleep) |
Sensor Installation
Mounting Guidelines
- Height: Mount 2-3 meters above ground (ceiling or pole)
- Position: Center of parking space
- Angle: Point directly downward (90°)
- Avoid: Near walls, pipes, or other obstacles
Distance Calibration
// Typical distances for parking detection
Empty space distance: 250cm (sensor height)
Occupied space distance: 100-150cm (car height)
Threshold: 180cm (midpoint)
if (distance < threshold) {
status = OCCUPIED;
} else {
status = AVAILABLE;
}
Wiring Diagram
ESP32 HC-SR04
â
âââ 5V â VCC
âââ GND â GND
âââ GPIO5 â Trig
âââ GPIO18 â Echo
ESP32 LED (via transistor)
â
âââ GPIO23 â Base (via 1k resistor)
âââ LED + â Collector
âââ LED - â GND
- Use UV-resistant enclosures
- Add conformal coating to PCBs
- Include desiccant packs to prevent condensation
- Mount sensors under protective covers
- Use stainless steel hardware
ESP32 Firmware
Complete firmware for parking space monitoring:
#include <WiFi.h>
#include <AzureIoTHub.h>
#include <ArduinoJson.h>
// WiFi credentials
const char* ssid = "PARKING_WIFI";
const char* password = "your_password";
// Azure IoT Hub connection string
static const char* connectionString = "HostName=your-hub.azure-devices.net;DeviceId=parking-space-001;SharedAccessKey=your-key";
// Pins
#define TRIG_PIN 5
#define ECHO_PIN 18
#define LED_GREEN 23
#define LED_RED 22
// Parking space configuration
const int SPACE_ID = 1;
const int DISTANCE_THRESHOLD = 180; // cm
void setup() {
Serial.begin(115200);
// Initialize pins
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_RED, OUTPUT);
// Connect to WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
// Initialize Azure IoT
IoTHubClient_Init(connectionString);
}
void loop() {
// Measure distance
int distance = measureDistance();
// Determine occupancy
bool occupied = distance < DISTANCE_THRESHOLD;
// Update LED indicators
if (occupied) {
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_GREEN, LOW);
} else {
digitalWrite(LED_RED, LOW);
digitalWrite(LED_GREEN, HIGH);
}
// Send to Azure IoT Hub
sendTelemetry(distance, occupied);
// Sleep for 30 seconds
esp_sleep_enable_timer_wakeup(30000000);
esp_deep_sleep_start();
}
int measureDistance() {
// Send 10Ξs pulse
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Read echo pulse duration
long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms timeout
// Convert to distance (cm)
int distance = duration * 0.034 / 2;
// Filter invalid readings
if (distance == 0 || distance > 400) {
return 999; // Invalid reading
}
return distance;
}
void sendTelemetry(int distance, bool occupied) {
StaticJsonDocument<256> doc;
doc["space_id"] = SPACE_ID;
doc["distance"] = distance;
doc["occupied"] = occupied;
doc["timestamp"] = millis();
doc["battery"] = readBattery();
char jsonBuffer[256];
serializeJson(doc, jsonBuffer);
IoTHubClient_SendEvent(jsonBuffer);
Serial.printf("Space %d: %s (%d cm)\n",
SPACE_ID,
occupied ? "OCCUPIED" : "AVAILABLE",
distance);
}
int readBattery() {
int adc = analogRead(35);
float voltage = adc * (3.3 / 4095.0) * 2;
return (int)(voltage * 100);
}
Azure IoT Integration
Set up cloud infrastructure for parking data:
Azure Resources
- IoT Hub: Device connectivity and messaging
- Functions: Serverless processing
- Cosmos DB: NoSQL database for telemetry
- SignalR Service: Real-time updates to app
- App Service: Mobile backend API
Azure Function for Processing
using Microsoft.Azure.Devices.Shared;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
public class ParkingEvent
{
public int space_id { get; set; }
public int distance { get; set; }
public bool occupied { get; set; }
public long timestamp { get; set; }
public int battery { get; set; }
}
[FunctionName("ProcessParkingEvent")]
public static async Task Run(
[EventHubTrigger("parking-events", Connection = "EventHubConnection")]
string eventHubMessage,
[CosmosDB(
databaseName: "ParkingDB",
collectionName: "ParkingEvents",
ConnectionStringSetting = "CosmosDBConnection",
CreateIfNotExists = true)]
IAsyncCollector<ParkingEvent> outputEvents,
ILogger log)
{
var parkingEvent = JsonConvert.DeserializeObject<ParkingEvent>(eventHubMessage);
// Store in Cosmos DB
await outputEvents.AddAsync(parkingEvent);
// Update current state
await UpdateParkingState(parkingEvent);
// Send real-time update via SignalR
await SendSignalRUpdate(parkingEvent);
log.LogInformation($"Processed event for space {parkingEvent.space_id}");
}
private static async Task UpdateParkingState(ParkingEvent evt)
{
// Update latest state document
var state = new {
space_id = evt.space_id,
occupied = evt.occupied,
last_updated = DateTime.UtcNow
};
// Upsert to Cosmos DB
}
IoT Hub Message Routing
// Route parking events to Event Hub
SELECT *
FROM IoTHubMessages
WHERE $level = 'parking'
// Route alerts (low battery) to Service Bus
SELECT *
FROM IoTHubMessages
WHERE battery < 350
Mobile App Development
React Native app for drivers:
Parking Map Component
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
import * as signalR from '@microsoft/signalr';
const ParkingMap = () => {
const [parkingSpaces, setParkingSpaces] = useState([]);
useEffect(() => {
// Connect to SignalR for real-time updates
const connection = new signalR.HubConnectionBuilder()
.withUrl('https://your-api.azurewebsites.net/parkingHub')
.build();
connection.on('ParkingUpdate', (data) => {
setParkingSpaces(prev =>
prev.map(space =>
space.id === data.space_id
? { ...space, occupied: data.occupied }
: space
)
);
});
connection.start();
// Fetch initial state
fetchParkingData();
}, []);
const fetchParkingData = async () => {
const response = await fetch('https://your-api.azurewebsites.net/api/parking');
const data = await response.json();
setParkingSpaces(data);
};
return (
<MapView
style={styles.map}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
}}
>
{parkingSpaces.map(space => (
<Marker
key={space.id}
coordinate={{
latitude: space.latitude,
longitude: space.longitude,
}}
pinColor={space.occupied ? 'red' : 'green'}
/>
))}
</MapView>
);
};
Deployment Tips
Power Management
- Use deep sleep between readings (30s - 1min intervals)
- Solar panels: 5V 1W per node
- Battery: 18650 (3000mAh) for 2+ weeks backup
- Enable power saving mode on WiFi
Network Design
- Ensure WiFi coverage throughout parking area
- Use mesh networking for large lots
- Consider LoRaWAN for very large areas
- Install cellular backup for critical systems
Entry Display Board
[Raspberry Pi] â [LED Matrix Display]
â
[Azure IoT Hub]
â
Query: SELECT COUNT(*) FROM Spaces WHERE occupied = false
â
Display: "AVAILABLE: 47 SPACES"
- License plate recognition for reserved spots
- Dynamic pricing based on occupancy
- Reservation system with time limits
- EV charging station integration
- Handicap spot monitoring
- Predictive availability (ML forecasting)
Next Steps
Expand your smart parking system:
- Add camera-based verification
- Implement payment integration
- Connect to city-wide parking platform
- Add EV charging station monitoring
- Implement predictive analytics for demand
Related Articles:
Fleet Tracking with GPS |
Smart Home Monitoring
Useful Tools:
GPS Distance Calculator |
All IoT Tools