How noisy is your classroom or bedroom? The high-sensitivity sound sensor turns sound into a changing voltage, and the ESP32 measures how much it changes. A web page on your phone shows a live bar that jumps when you talk or clap.
What you'll learn
- How to measure sound loudness from an analog signal
- How a web page can update itself with JavaScript
- How to send data as JSON
What you need
- ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
- High-sensitivity sound sensor module (45-in-1 Sensor Kit)
- A 2.4 GHz Wi-Fi network
- Breadboard and jumper wires (ESP32 IoT Starter Kit)
Wiring

| From | To |
|---|---|
| Sound module AO | ESP32 GPIO 34 |
| Sound module G | GND |
| Sound module + | 3V3 |
| Sound module DO | Not used |
Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.
The sketch
Replace YOUR_WIFI_NAME and YOUR_WIFI_PASSWORD with your own network details (2.4 GHz only). Open the Serial Monitor at 115200 baud to see the address, then open it on a phone or computer on the same Wi-Fi.
#include <WiFi.h>
#include <WebServer.h>
const char* WIFI_NAME = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const int SOUND_PIN = 34;
WebServer server(80);
// Loudness = difference between the highest and lowest reading in 50 ms
int measureLevel() {
int lowest = 4095, highest = 0;
unsigned long start = millis();
while (millis() - start < 50) {
int v = analogRead(SOUND_PIN);
if (v < lowest) lowest = v;
if (v > highest) highest = v;
}
return highest - lowest; // 0 (silent) to about 4095
}
const char PAGE[] = R"rawliteral(
<!DOCTYPE html><html><head><meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'><title>Sound level</title></head>
<body style='font-family:sans-serif;padding:16px'>
<h1>Sound level</h1>
<div style='height:40px;background:#eee;border-radius:8px;overflow:hidden'>
<div id='bar' style='height:100%;width:0;background:#DE544A;transition:width .2s'></div></div>
<p id='value'>-</p>
<script>
async function update() {
const r = await fetch('/level');
const d = await r.json();
const pct = Math.min(100, Math.round(d.level / 20));
document.getElementById('bar').style.width = pct + '%';
document.getElementById('value').textContent = 'Level: ' + d.level;
}
setInterval(update, 250);
</script></body></html>
)rawliteral";
void setup() {
Serial.begin(115200);
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) delay(500);
Serial.print("Open http://");
Serial.println(WiFi.localIP());
server.on("/", []() { server.send(200, "text/html", PAGE); });
server.on("/level", []() {
server.send(200, "application/json", "{\"level\":" + String(measureLevel()) + "}");
});
server.begin();
}
void loop() {
server.handleClient();
}
How it works
Sound makes the microphone's voltage wobble up and down around a middle value. The louder the sound, the bigger the wobble, so the sketch measures the difference between the highest and lowest reading over 50 ms. The web page asks the ESP32 for that number four times a second using fetch(), and the ESP32 answers in JSON, a simple text format for data. Only the bar changes, so the page doesn't reload.
Try this next
- Turn the bar green, yellow or red depending on the level.
- Keep the highest level of the last minute and show it on the page.
- Use GPIO 26 to light an LED when it gets too loud, as a "quiet please" sign.
Troubleshooting
- The bar barely moves: turn the module's knob to change the microphone's sensitivity.
- The bar is always full: turn the knob the other way.
- The page doesn't open: make sure your phone is on the same Wi-Fi network.