OVERVIEW
We are building a Sound-controlled RGB smart lamp using the ESP32 with a sound detector sensor. This smart lamp lets you control RGB Neopixel LEDs by sound cues such as claps or taps detected by the sensor. The 0.96-inch OLED display provides real-time feedback on the lamp’s status, such as color and brightness. A passive buzzer gives an audible beep whenever the lamp changes color, providing confirmation of the action. The ESP32 processes the sound input locally, enabling hands-free control to turn the light on/off, change colors, and activate lighting effects, all without needing an internet connection.
HARDWARE USED
SOFTWARE USED
- Arduino IDE
APPLICATION DISCUSSION
ESP32 :
ESP-32 is a development board that is built around the powerful ESP32 system on a chip microcontroller. It is a development platform with a programmer, Serial-to-USB module, voltage regulator, and several peripherals. The most relevant: it combines WiFi and Bluetooth wireless capabilities and it’s dual-core for more complex tasks that demand to multitask.
NEOPIXEL RING RGB LED:
The NeoPixel Ring RGB LED is a circular array of individually addressable RGB LEDs controlled using a single data line. Each LED can produce millions of colors by mixing red, green, and blue light with 8-bit PWM control. It allows for dynamic lighting effects such as color transitions, animations, and visual indicators. The ring is powered by 5V and controlled by a microcontroller like the ESP32 using libraries such as Adafruit NeoPixel. Its compact design makes it ideal for wearable tech, smart lamps, and interactive displays.
SOUND DETECTOR SENSOR:
OLED:
The 0.96 inch OLED is a small and low-power display that can be used to display text, graphic images, or sensory data. This display used organic light-emitting diode (OLED) technology. This means that each pixel emits its own light without needing a backlight. This also means they provide lots of contrast and rich colors, with low power, and a nice wide viewing angles. It uses the SSD1306 driver chip that controls the operation of each of the pixels. It uses either I2C or serial (SPI) to communicate with the microcontroller (NodeMCU or Arduino). I2C is typically what is used, as it requires less wiring.
PASSIVE BUZZER:
A passive buzzer is an electronic component that produces sound when an external signal, usually a square wave from a microcontroller, drives it. Unlike an active buzzer, it does not have a built-in oscillator, so the frequency and tone of the sound can be controlled by the input signal. This flexibility allows it to generate different pitches, tones, or even simple melodies. It is commonly used in alarms, timers, and notification systems. Because it requires a driving circuit, it is more versatile but slightly harder to use than an active buzzer.
HARDWARE SETUP
- NEOPIXEL RING:
- GPIO 5 -> NEOPIXEL DATA PIN
- GND -> GND
- 5V -> POWER
- SOUND DETECTOR SENSOR
- GPIO 34 -> ANALOG OUTPUT
- GND -> GND
- 3.3V -> POWER
- OLED
- GPIO 21 -> SDA
- GPIO 22 -> SCL
- 3.3V -> POWER
- GND -> GND
- BUZZER
- GPIO 25 -> SIGNAL
- GND -> GND
SOFTWARE SET UP
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_NeoPixel.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define LED_PIN 5
#define NUM_LEDS 16
Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
#define MIC_PIN 34
#define BUZZER_PIN 25
const int CLAP_SENSITIVITY = 500;
const unsigned long CLAP_DEBOUNCE = 250;
const unsigned long CLAP_WINDOW = 500;
unsigned long lastClapTime = 0;
int clapCount = 0;
unsigned long lastClapDetected = 0;
int mode = 0;
unsigned long lastRainbowUpdate = 0;
const unsigned long rainbowInterval = 20;
uint16_t rainbowIndex = 0;
long ambientNoiseSum = 0;
int ambientNoiseCount = 0;
const int AMBIENT_CALIBRATION_SAMPLES = 500;
int adaptiveThreshold = 0;
const int CALIBRATION_DELAY = 10;
void setup() {
Serial.begin(115200);
delay(1000);
strip.begin();
strip.setBrightness(100);
strip.show();
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED init failed");
while (1);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println("Calibrating...");
display.display();
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
calibrateAmbientNoise();
}
void calibrateAmbientNoise() {
display.clearDisplay();
display.setCursor(0, 0);
display.println("Calibrating...");
display.println("Please be quiet.");
display.display();
ambientNoiseSum = 0;
ambientNoiseCount = 0;
for (int i = 0; i < AMBIENT_CALIBRATION_SAMPLES; i++) {
int sample = analogRead(MIC_PIN);
ambientNoiseSum += sample;
ambientNoiseCount++;
delay(CALIBRATION_DELAY);
}
int ambientNoiseAverage = ambientNoiseSum / ambientNoiseCount;
adaptiveThreshold = ambientNoiseAverage + CLAP_SENSITIVITY;
Serial.print("Ambient Noise Average: ");
Serial.println(ambientNoiseAverage);
Serial.print("Adaptive Threshold set to: ");
Serial.println(adaptiveThreshold);
display.clearDisplay();
display.setCursor(0, 0);
display.println("Clap Detection Ready!");
display.print("Threshold: ");
display.println(adaptiveThreshold);
display.display();
}
void loop() {
int volume = analogRead(MIC_PIN);
unsigned long currentTime = millis();
if (volume > adaptiveThreshold && (currentTime - lastClapTime > CLAP_DEBOUNCE)) {
lastClapTime = currentTime;
clapCount++;
lastClapDetected = currentTime;
Serial.print("Clap detected! Value: ");
Serial.print(volume);
Serial.print(" | Clap count: ");
Serial.println(clapCount);
}
if (clapCount > 0 && (currentTime - lastClapDetected > CLAP_WINDOW)) {
Serial.print("Clap sequence ended with ");
Serial.print(clapCount);
Serial.println(" clap(s).");
switch (clapCount) {
case 1: mode = 1; break;
case 2: mode = 2; break;
case 3: mode = 3; break;
case 4: mode = 4; break;
case 5: mode = 5; break;
case 6: mode = 0; break;
default: mode = 0; break;
}
updateState(mode);
clapCount = 0;
}
if (mode == 5) {
if (currentTime - lastRainbowUpdate > rainbowInterval) {
lastRainbowUpdate = currentTime;
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i * 256 / strip.numPixels() + rainbowIndex) & 255));
}
strip.show();
rainbowIndex++;
if (rainbowIndex >= 256) rainbowIndex = 0;
}
}
}
void updateState(int newMode) {
mode = newMode;
display.clearDisplay();
display.setCursor(0, 0);
strip.clear();
switch (mode) {
case 0:
strip.show();
display.println("Clap 6: Turn OFF");
break;
case 1:
setColor(255, 255, 255);
display.println("Clap 1: White");
break;
case 2:
setColor(255, 0, 0);
display.println("Clap 2: Red");
break;
case 3:
setColor(0, 0, 255);
display.println("Clap 3: Blue");
break;
case 4:
setColor(0, 255, 0);
display.println("Clap 4: Green");
break;
case 5:
display.println("Clap 5: Rainbow");
break;
}
display.display();
beepBuzzer();
}
void setColor(uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < NUM_LEDS; i++) {
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
}
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
void beepBuzzer() {
tone(BUZZER_PIN, 3000, 150);
delay(300);
noTone(BUZZER_PIN);
}
CODE BREAKDOWN
-
Wire.h-
For I2C communication, used by the OLED display. -
Adafruit_GFX.h-
The core graphics library for the display. -
Adafruit_SSD1306.h-
The specific driver for the SSD1306 OLED display. -
Adafruit_NeoPixel.h-
The driver for the Neo-Pixel RGB LEDs. -
setup()
- initializes the components. It starts the serial communication, sets up the Neo-Pixel strip, and initializes the OLED display. -
calibrateAmbientNoise()
- measure the average sound level in the room to create an adaptive sound threshold for detecting claps. -
loop()-
continuously reads the sound sensor's value. It compares the current sound level to the adaptive threshold. -
CLAP_DEBOUNCE
andCLAP_WINDOW-
are crucial for ensuring that a single clap isn't counted multiple times and that a sequence of claps (like two or three) is counted as one event. The code waits for a briefCLAP_WINDOW
to pass after the last clap before processing the totalCLAP_COUNT.
-
UpdateState()-
changes the Neo-Pixel's color and updates the OLED display based on the number of claps. One clap sets the LEDs to white, two claps to red, and so on. Six claps turn them off. Five claps activate a rainbow animation. -
SetColor()-
sets all the LEDs to a single, solid color. -
Wheel()-
is a helper used to generate the color sequence for the rainbow animation.
Other Functions:
-
calibrateAmbientNoise()-
This function measures the surrounding noise level to set an initial noise threshold, making the clap detector more reliable in different environments. -
beepBuzzer()-
This function plays a short tone on a passive buzzer to provide audible feedback when the mode changes.
VIDEO DEMONSTRATION
DOCUMENTATIONS
Sound-controlled RGB smart lamp Output:
Clap 1 - White (ON)
Clap 2 - Red
Clap 3 - Blue
Clap 4 - Green
Clap 5 - Rainbow
Clap 6 - OFF
CONCLUSION
This project is a functional prototype of a sound-controlled smart lamp that uses an ESP32 to process audio input from a sound sensor. The system allows a user to control the lighting without physical interaction, relying on specific sound cues like claps.
This is an operating prototype of an interactive smart lighting system activated by a clap. It clearly shows how to interface many hardware elements an input sound sensor, a user feedback OLED display, and an addressable LED strip for output all into one integrated device. The strength of the system is in its implementation of an adaptive calibration procedure. This feature enables the device to monitor and compensate for the ambient noise levels in its environment, making the clap-detection process accurate and consistent. Through linking special clap sequences to various operations, like changing the color of the LED or enabling a rainbow effect, the project offers an easy, intuitive, and hand-free way of controlling the light. In the end, the project is a successful integration of hardware and software to develop a usable smart home application, demonstrating basic principles of embedded systems and providing a clear direction for potential future growth and development.
REFERENCES
-
ESP32 + Sound Detector Sensor for Sound-Activated LED Control
PROJECT AUTHORS
- Glydelle Arellano
- Arcel Alfaro