ESP32 Obstacle Alarm With Auto, Debug and Web-Controlled Manual Modes

by Ku_aman in Circuits > Microcontrollers

23 Views, 0 Favorites, 0 Comments

ESP32 Obstacle Alarm With Auto, Debug and Web-Controlled Manual Modes

WhatsApp Image 2026-09-30 at 6.01.56 PM.jpeg
WhatsApp Image 2026-09-30 at 6.01.55 PM.jpeg
In this project I built an obstacle alarm using an ESP32. An IR sensor and an HC-SR04 ultrasonic sensor measure how close an object is, and a buzzer and LED warn you with faster beeps as the object gets closer.
The code is fully non-blocking (no delay()), and the system has three modes: Auto, Debug and Manual. In Manual mode the ESP32 hosts a small web page, so you can control the alarm from your phone.

Video: https://www.youtube.com/shorts/TN3ATCxotLs

Demo Online Link: https://app.cirkitdesigner.com/project/fec9b56d-e9db-426b-89ee-a721e4b73853

Supplies

- ESP32 Dev Module

- HC-SR04 ultrasonic sensor

- IR obstacle sensor module

- Passive buzzer

- LED (any colour)

- 220 ohm resistor (for LED)

- 1k ohm and 2k ohm resistors (voltage divider for Echo pin)

- Breadboard

- Jumper wires

- USB data cable

Note : Use a passive buzzer, because the code uses tone() to make different sounds.

How the Alarm Works

The IR sensor tells if there is an object in front, and the ultrasonic sensor measures the distance. The ESP32 combines both readings and picks one of four states.

State Condition Buzzer

SAFE

  1. No object, distance above 80 cm
  2. Off

WARNING

  1. Object, 20 to 80 cm
  2. Slow beep

DANGER

  1. Object, 20 cm or less
  2. Fast beep

SENSOR_ERROR

  1. No echo, or the sensors disagree
  2. Low warning tone

The system has three modes:

  1. Auto: sensors control everything.
  2. Debug: same as Auto, but prints all sensor data.
  3. Manual: you set the state yourself from Serial Monitor or a web page.

Wiring the Circuit

circuit_image.png

Connect the components as shown in the diagram and table.

Component ESP32 pin

Buzzer (+)

GPIO 23

LED (+) through 220 ohm resistor

GPIO 22

IR sensor OUT

GPIO 21

HC-SR04 Trig

GPIO 19

HC-SR04 Echo

GPIO 18 (through voltage divider)

VCC / GND of sensors

Power as per module, common GND



Important: the HC-SR04 Echo pin outputs 5V, but ESP32 pins are 3.3V. Use a voltage divider (1k and 2k resistors) on the Echo pin to protect the ESP32.

Setting Up Arduino IDE for ESP32

  1. Install Arduino IDE.
  2. Open Tools → Board → Boards Manager, search "esp32" (by Espressif) and install.
  3. Select Tools → Board → ESP32 Dev Module.
  4. Connect the ESP32 and select the correct Port.
  5. Open Serial Monitor and set baud rate to 115200.

Note: "If the port does not show up, try another USB cable or install the CP210x / CH340 driver."

Code Part 1: Reading Sensors and Finding the State

The readSensors() function triggers the ultrasonic sensor and measures the echo time with pulseIn(). A 30 ms timeout is used, so the code never waits forever if the sensor is disconnected. Distance is calculated as duration * 0.034 / 2.

The updateState() function combines the IR reading and the distance to pick one of the four states.

void readSensors() {
ir_val = !digitalRead(ir);

digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

duration = pulseIn(echoPin, HIGH, 30000);
distanceCm = duration * 0.034 / 2;
}

void updateState() {
if (duration == 0) {
curr_state = SENSOR_ERROR;
} else if (ir_val && distanceCm <= 20) {
curr_state = DANGER;
} else if (ir_val && distanceCm > 20 && distanceCm <= 80) {
curr_state = WARNING;
} else if (!ir_val && distanceCm > 80) {
curr_state = SAFE;
} else {
curr_state = SENSOR_ERROR;
}
}

Code Part 2: Non-Blocking Beeping (No Delay)

Using delay() freezes the whole program, so the sensors and serial input stop working while the buzzer beeps. Instead, this code uses millis(). Every loop it checks: has enough time passed? If yes, it toggles the buzzer and LED.

WARNING beeps every 300 ms, DANGER every 100 ms with a higher tone, and SENSOR_ERROR uses a lower tone.

void beepUpdate(int freq, unsigned long interval) {
if (millis() - lastToggle >= interval) {
lastToggle = millis();
beepOn = !beepOn;
if (beepOn) {
digitalWrite(led, HIGH);
tone(buzzer, freq);
} else {
digitalWrite(led, LOW);
noTone(buzzer);
}
}
}

void decision() {
switch (curr_state) {
case SAFE:
noTone(buzzer);
digitalWrite(led, LOW);
beepOn = false;
break;
case WARNING: beepUpdate(1000, 300); break;
case DANGER: beepUpdate(2000, 100); break;
case SENSOR_ERROR: beepUpdate(500, 300); break;
}
}

Code Part 3: Auto and Debug Modes

Press a in Serial Monitor for Auto mode. It reads the sensors, runs the alarm and prints only when the state changes.

Press d for Debug mode. It prints the full IR value, echo duration and distance every 200 ms, which is useful for testing and calibration.

void autoMode() {
if (millis() - lastRead >= 200) {
lastRead = millis();
readSensors();
updateState();
if (curr_state != prev_state) {
prev_state = curr_state;
printAuto();
}
}
decision();
}

void debugMode() {
if (millis() - lastRead >= 200) {
lastRead = millis();
readSensors();
updateState();
printDebug();
if (curr_state != prev_state) {
prev_state = curr_state;
Serial.print("State: ");
Serial.println(stateName());
}
}
decision();
}
void handleSerial() {
while (Serial.available()) {
char c = Serial.read();

if (c == 'a' && mode != MODE_AUTO) setMode(MODE_AUTO);
else if (c == 'd' && mode != MODE_DEBUG) setMode(MODE_DEBUG);
else if (c == 'm' && mode != MODE_MANUAL) setMode(MODE_MANUAL);

else if (mode == MODE_MANUAL) {
if (c == '1') curr_state = SAFE;
else if (c == '2') curr_state = WARNING;
else if (c == '3') curr_state = DANGER;
else if (c == '4') curr_state = SENSOR_ERROR;
else continue;
Serial.print("Serial se State: ");
Serial.println(stateName());
}
}
}

Code Part 4: Manual Mode With a Web Page

Press m for Manual mode. The ESP32 connects to WiFi and starts a web server. The IP address is printed in Serial Monitor. Open it in a browser on the same WiFi network (2.4 GHz).

The page has two buttons to switch to Auto or Debug mode, and four buttons to set the state: SAFE, WARNING, DANGER, SENSOR_ERROR. You can also use keys 1 to 4 in Serial Monitor.

WiFi and the web server run only in Manual mode. When you leave Manual mode, both are turned off.

void manualMode() {
if (WiFi.status() == WL_CONNECTED) {
if (!ipPrinted) {
ipPrinted = true;
Serial.print("Open : http://");
Serial.println(WiFi.localIP());
}
server.handleClient();
} else if (!wifiFailPrinted && millis() - wifiStart > 15000) {
wifiFailPrinted = true;
Serial.println("WiFi not connected (please check ssid/password or 2.4GHz). Serial monitor will still work.");
}

decision();
}

void sendPage() {
String html = page;
html.replace("%STATE%", stateName());
for (int i = 0; i < 4; i++) {
html.replace("%C" + String(i) + "%", (curr_state == i) ? "cur" : "");
}
server.send(200, "text/html", html);
}

void handleRoot() { sendPage(); }

void handleState() {
if (server.hasArg("s")) {
int s = server.arg("s").toInt();
if (s >= 0 && s <= 3) {
curr_state = (SystemState)s;
Serial.print("Web to State: ");
Serial.println(stateName());
}
}
server.sendHeader("Location", "/");
server.send(303);
}

void handleMode() {
if (server.hasArg("m")) {
String m = server.arg("m");
if (m == "auto") { pendingMode = MODE_AUTO; modeChangePending = true; }
if (m == "debug") { pendingMode = MODE_DEBUG; modeChangePending = true; }
}

server.send(200, "text/html",
"<html><body style='font-family:Arial;text-align:center'>"
"<h2>Mode changed</h2><p>Manual page is closed now.</p></body></html>");
}

void startWeb() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
wifiStart = millis();
ipPrinted = false;
wifiFailPrinted = false;
server.begin();
webActive = true;
Serial.println("WiFi connecting...");
}

For other functions if left, see the attached .ino code file.

Uploading and Testing

Upload the code. If you see "Connecting......" press the BOOT button on the ESP32 until upload starts. Open Serial Monitor at 115200 baud and test each mode.

Test: move your hand slowly towards the sensors and watch the state change from SAFE to WARNING to DANGER.

Downloads

Troubleshooting

  1. COM port not showing: try another cable (data cable), install CP210x/CH340 driver.
  2. Nothing in Serial Monitor: set baud rate to 115200 and press the EN button.
  3. WiFi does not connect: ESP32 supports only 2.4 GHz WiFi; check name and password.
  4. tone not declared: update the ESP32 board package.
  5. Buzzer just clicks: you may be using an active buzzer, use a passive one.
  6. Always SENSOR_ERROR: check Echo wiring and voltage divider, IR sensor pin.