Community project
Garage Approach Alert
David Wertz
Published August 5, 2026 · Updated August 11, 2026
Generated with AIThe Garage Approach Alert uses two LD2410 24GHz millimeter-wave radar sensors to detect motion in a garage entryway from two different distances. One sensor monitors the far zone toward the house, while the other watches the near zone at the garage door, providing early warning of approaching vehicles or people. This guide includes a wiring diagram, complete parts list, ESP32 firmware with a web dashboard, and step-by-step assembly instructions to get the dual-radar station up and running.
The project creates a local WiFi access point that displays real-time presence detection from both radar zones on a mobile-friendly web interface. Builders will learn how to integrate multiple presence sensors with an ESP32, configure independent detection zones, and create a responsive status dashboard—all without requiring cloud connectivity or external services.
Wiring diagram
Interactive · read-only
Pan and zoom to explore the wiring. Remix the project to edit it in your own workspace.
Parts list
Bill of materials| Component | Qty | Notes |
|---|---|---|
| LD2410 24GHz mmWave Radar Presence SensorFar approach zone | 1 | Hi-Link 24GHz FMCW mmWave radar module for human presence detection, capable of detecting both stationary (still, lying in bed) and moving targets within configurable range gates. Communicates over UART at 256000 baud (default). Operates from 5V supply; UART TX pin outputs at 5V logic requiring level shifting to 3.3V for ESP32-S3 RX. Also exposes an OUT pin (binary presence indicator) and supports Bluetooth configuration on some variants. |
| LD2410 24GHz mmWave Radar Presence SensorNear approach zone | 1 | Hi-Link 24GHz FMCW mmWave radar module for human presence detection, capable of detecting both stationary (still, lying in bed) and moving targets within configurable range gates. Communicates over UART at 256000 baud (default). Operates from 5V supply; UART TX pin outputs at 5V logic requiring level shifting to 3.3V for ESP32-S3 RX. Also exposes an OUT pin (binary presence indicator) and supports Bluetooth configuration on some variants. |
Assembly
7 stepsKeep the camera board accessible
Place the AI Thinker ESP32-CAM inside the garage where USB power can reach it and where its antenna has a clear path to the phone/computer used for the local status page. The camera itself is not used by this simplified detector, but its fixed camera pins must remain unused.
- Tip: Use a stable 5 V USB supply; two LD2410 modules can draw substantial current at startup.
- Tip: Do not enclose the ESP32-CAM antenna in metal.
Mount the far radar
Mount radar_far at the house-side portion of the normal walking route, aimed across the route rather than straight down it. Keep the front radar area clear of metal, foil insulation, and large wiring bundles.
- Tip: Mount in a dry location or non-metallic plastic enclosure.
- Tip: Begin with a narrow, controlled sensing zone to reduce false triggers.
- ⚠ The LD2410 detects presence, not a person's identity.
Mount the near radar
Mount radar_near near the garage-side end of the route, aimed across the final approach. Keep its detection field away from the road, moving garage equipment, and trees if possible.
- Tip: Separate the two sensor fields as much as practical so they represent distinct zones.
Make the shared power connections
Connect both radar VCC pins to the ESP32-CAM 5 V/VIN rail and connect both radar GND pins to ESP32-CAM GND. All three devices must share the same ground.
- Tip: Use short, secure power wiring and a USB supply with comfortable current margin.
- ⚠ Do not power either radar from the ESP32-CAM 3.3 V pin; the LD2410 requires 5 V.
Wire the two status outputs
Connect radar_far OUT directly to ESP32-CAM GPIO16. Connect radar_near OUT directly to ESP32-CAM GPIO17. The LD2410 OUT output is 3.3 V logic, so no divider or level shifter is used.
- Tip: Check the silkscreen labels carefully: use OUT, not TX.
- Tip: Keep these signal wires away from the radar antenna face where possible.
- ⚠ Do not apply 5 V to GPIO16 or GPIO17.
- ⚠ Leave the radar TX and RX pins insulated and unconnected in this build.
Inspect before powering
Verify that each radar has VCC to 5 V, GND to GND, far OUT to GPIO16, and near OUT to GPIO17. Confirm there are no connections to the ESP32-CAM camera pins or to GPIO0.
- Tip: A paper label on each sensor—FAR and NEAR—helps avoid swapping zones later.
- ⚠ GPIO0 is used for boot/programming and must not be tied to a radar signal.
Power the completed station
Connect the ESP32-CAM to its USB power source only after completing the inspection. The board, both radars, and their shared ground will power together.
- Tip: After deployment, connect a phone or computer to the Garage-Approach Wi-Fi network and open 192.168.4.1 to view the two zones.
Pin assignments
Board wiring reference| Pin | Connection | Type |
|---|---|---|
| 5V | radar_far VCC | power |
| GND | radar_far GND | ground |
| GPIO 16 | radar_far OUT | digital |
| 5V | radar_near VCC | power |
| GND | radar_near GND | ground |
| GPIO 17 | radar_near OUT | digital |
| EXT | radar_far TX → Leave insulated and unconnected in normal operation | uart |
| EXT | radar_far RX → Leave insulated and unconnected in normal operation | uart |
| EXT | radar_near TX → Leave insulated and unconnected in normal operation | uart |
| EXT | radar_near RX → Leave insulated and unconnected in normal operation | uart |
Firmware
ESP32#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
// Forward declarations
String statusMessage();
void handleStatus();
constexpr int RADAR_FAR_PIN = 16;
constexpr int RADAR_NEAR_PIN = 17;
constexpr unsigned long HOLD_MS = 5000;
const char *AP_SSID = "Garage-Approach";
const char *AP_PASSWORD = "garagealert";
WebServer server(80);
bool farActive = false;
bool nearActive = false;
unsigned long farLastSeen = 0;
unsigned long nearLastSeen = 0;
const char PAGE[] PROGMEM = R"HTML(
<!doctype html><html><head><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Garage Approach</title><style>
body{margin:0;background:#10151b;color:#eef3f8;font-family:Arial,sans-serif;text-align:center}main{max-width:520px;margin:auto;padding:26px 18px}h1{font-size:1.7rem;margin:.2em}p,small{color:#aab8c5}#state{font-weight:bold;font-size:1.4rem;margin:22px 0;padding:16px;border-radius:12px;background:#1b252f}.zones{display:flex;gap:14px}.zone{flex:1;background:#1b252f;border-radius:14px;padding:22px 8px;font-size:1.05rem}.dot{width:55px;height:55px;border-radius:50%;margin:13px auto;background:#34414c}.on{background:#ff3939;box-shadow:0 0 25px #ff2020}small{display:block;margin-top:26px}</style></head><body><main>
<h1>Garage Approach Radar</h1><p>LD2410 two-zone presence monitor</p><div id="state">Loading...</div><div class="zones"><div class="zone">FAR / HOUSE SIDE<div id="far" class="dot"></div><span id="farText">-</span></div><div class="zone">NEAR / GARAGE<div id="near" class="dot"></div><span id="nearText">-</span></div></div><small>Updates when a zone state changes.</small></main><script>
let previous='';async function poll(){try{let d=await (await fetch('/status')).json();let key=JSON.stringify(d);if(key!==previous){previous=key;document.getElementById('far').className='dot '+(d.far?'on':'');document.getElementById('near').className='dot '+(d.near?'on':'');document.getElementById('farText').textContent=d.far?'DETECTED':'CLEAR';document.getElementById('nearText').textContent=d.near?'DETECTED':'CLEAR';document.getElementById('state').textContent=d.message;}}catch(e){document.getElementById('state').textContent='Connection lost';}}poll();setInterval(poll,500);</script></body></html>
)HTML";
String statusMessage() {
if (nearActive) return "PERSON NEAR GARAGE";
if (farActive) return "APPROACH DETECTED";
return "ALL CLEAR";
}
void handleStatus() {
String json = "{\"far\":" + String(farActive ? "true" : "false") + ",\"near\":" + String(nearActive ? "true" : "false") + ",\"message\":\"" + statusMessage() + "\"}";
server.send(200, "application/json", json);
}
void setup() {
pinMode(RADAR_FAR_PIN, INPUT);
pinMode(RADAR_NEAR_PIN, INPUT);
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_SSID, AP_PASSWORD);
server.on("/", HTTP_GET, []() { server.send_P(200, "text/html", PAGE); });
server.on("/status", HTTP_GET, handleStatus);
server.onNotFound([]() { server.send(404, "text/plain", "Not found"); });
server.begin();
}
void loop() {
const unsigned long now = millis();
if (digitalRead(RADAR_FAR_PIN) == HIGH) farLastSeen = now;
if (digitalRead(RADAR_NEAR_PIN) == HIGH) nearLastSeen = now;
farActive = (now - farLastSeen) < HOLD_MS;
nearActive = (now - nearLastSeen) < HOLD_MS;
server.handleClient();
}“Deploy to device” opens this project in Schematik, where you can flash it to your board over USB.
Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.