
${\color{#ff0000}S}{\color{#ff6e00}m}{\color{#ffdd00}a}{\color{#b2ff00}r}{\color{#48ff00}t}\ {\color{#00ff26}M}{\color{#00ff95}u}{\color{#00fbff}s}{\color{#0091ff}i}{\color{#0022ff}c}\ {\color{#4d00ff}L}{\color{#b700ff}a}{\color{#ff00d9}m}{\color{#ff006a}p} $
Table of Contents
Thinking it over, it was a shame to waste so much power on a simple task of turning a lamp on and off.
So what should I add to truly leverage the ESP32 and end up with a more complete and functional product?
Watching my wife cook while listening to music on her phone, which she would leave anywhere, the idea came to me: give the lamp an audio system (Bluetooth speaker). I told her, wouldn't it be great to cook while listening to music without having to leave your phone somewhere random? You'll be able to control the lamp and stream music from your phone via Bluetooth to the lamp, having music in the kitchen.
If I already have a lamp that plays music, why not make it more cheerful and add colors?
To do this, I added a Neopixel strip that is also controlled via the web from your phone, offering lighting effects including effects that sync with the music the lamp is playing.
Still not satisfied, I added a temperature and humidity sensor to display that data on the web interface embedded in the ESP32.
Since I live in a country where power outages are very common, and I had the ability to play music through the lamp, why not take advantage of it?
I implemented a dual power supply system (mains and battery) that allows you to keep controlling the lamp via the web and listen to music after a power outage. Of course, I couldn't use the Neopixels since they consume too much power.
- Control the lamp on/off from your mobile phone.
- Play music through the lamp via Bluetooth from your mobile phone.
- Control the Neopixel strip for different lighting effects.
- Monitor battery charge and usage.
- Monitor temperature and humidity.
- Web-based control of the Bluetooth speaker's physical buttons.
- Embedded web interface for real-time control from any mobile device.
Place a video of SML in action here
The ESP32 was chosen for this project because of its power, number of analog inputs, and Wi-Fi connectivity. It features dual power supply, using a 5V power source and a 3.7V battery. A protected charger handles battery charging, and a DC-DC step-up converter boosts the battery voltage to 5V to power the ESP32 and all modules except the Neopixel strip, which is always powered from the mains supply.
A dual relay module controls the LED lamp and the Bluetooth module. A DHT22 sensor measures temperature and humidity. Additional components implement supporting circuits.
For audio playback, I used one of those common portable Bluetooth speakers that can be found very cheap, like the one in the image below.
Required components:
- ESP32, any variant
- Battery charger module, TP4056 5V 1A with protection
- Mini DC-DC step-up booster MT3608
- 5V power supply
- Dual relay module
- WS2812B Neopixel LED strip, 24 LEDs
Note: The number of LEDs depends on the lamp size and power supply capacity. You can change this value in the code.
- LiPo 3.7V battery or 18650 3.7V Li-Ion
- Temperature and humidity sensor DHT22
- Resistors:
- 5 x 1K
- 3 x 10K
- 2 x 4.7K
- 1 x 220 ohm
- Capacitors:
- 2 x 0.1 uF
- 1 x 1 uF /10v
- Diodes:
- 2 x 1N4148
- 1 x 1N581x Schottky
- MOSFET transistors
- 1 x P-Channel MOSFET
- 3 x N-Channel MOSFET
-
Bluetooth speaker control board with its speaker
-
LED lamp to transform
Note: For this project I used a circular LED lamp, considering it more aesthetic and elegant. You can use any lamp that suits your needs and taste.
Below is a table showing the ESP32 pins to connect and their designations.
| ESP32 PINS | NAME | FUNCTION |
|---|---|---|
4- D4 |
STRIP_PIN |
LED strip control |
5- D5 |
VOLUMENUP_PIN |
V+/FF Bluetooth button |
18- D18 |
SWITCH_PIN |
Bluetooth power control |
19- D19 |
VOLUMENDOWN_PIN |
V-/REW Bluetooth button |
21- D21 |
PLAY_PIN |
Play/Pause Bluetooth button |
23- D23 |
DHTPIN |
DHT sensor control |
32- D32 |
LAMP_PIN |
Lamp power control |
33- D33 |
ADC_PIN |
Battery monitor |
34- D34 |
CHARGE_PIN |
Charging signal |
35- D35 |
FULL_CHARGE_PIN |
Full charge signal |
36- VP |
AUDIO_IN_PIN |
Audio input |
Note: Since Wi-Fi is enabled on the ESP32, you cannot use any ADC2 pins for analog readings.
The following schematic illustrates the power connections for the project.
Note: The output voltage of the lamp's power supply that feeds the high-brightness white LEDs is not the one shown in the schematic; it is much higher. It is not important to know it for this project.
π You can find the schematic here. β
For a better understanding of the dual power supply (load sharing) used, here is the following diagram.
When 5V power is applied, this circuit turns off the MOSFET and stops current flow from the battery to the load (DC-DC module), effectively disconnecting the battery. As long as the
The chosen MOSFET must have the lowest possible RDS(on) to minimize power loss, must handle the current your circuit draws from the battery, and must have a VGS(th) between 0V and -2.4V.
The diode prevents current from flowing from the battery back to the 5V power supply. It must be a Schottky diode that can handle the maximum current draw of the loads. The RG resistor (10K) ensures the MOSFET turns on and connects the battery to the load when the 5V power supply is removed.
The DC-DC boost converter must be adjusted so its output voltage is 5V whether powered from mains or battery.
To monitor the battery voltage, place a resistive voltage divider at the output of the TP4056 charger module and connect its output to pin D33 of the ESP32.
With the excellent library by danilopinotti/Battery18650Stats, the battery voltage is read and expressed as a percentage. Since batteries in use don't always reach the ideal 4.2V maximum, danilopinotti's library didn't give practical values. So I modified the library to include configurable maximum and minimum voltage values in its parameters for more accurate percentage readings.
The TP4056 module has 2 indicator LEDs β one to indicate charging
As shown in the diagram, if pins 6 or 7 output more than 0V, the LEDs are off and diode (D17) does not conduct, so 3.3V reaches the ESP32 input. When the module is charging or the battery is fully charged, there will be a logic low on those pins. The corresponding LED turns on and diode (D17) conducts, reflecting a low level on the ESP32 pin. In code, this is represented by the variables
During testing I faced another challenge: when the Bluetooth speaker is turned on, the volume is always at half. This seems to be normal behavior for these Bluetooth speakers, so to control the volume we need to use the physical buttons. But since the lamp will be in an inaccessible location, we can't. And even if we turn up our phone volume to max, we may not achieve the desired level. So how can we remotely control physical buttons?
Analyzing the schematic of some common Bluetooth speakers on the market (Chinese ones), I noticed the buttons switch to ground (GND) on an IC pin. This makes it easy to emulate a button using the ESP32. The following diagram shows the solution.
The solution basically uses MOSFETs as simple switches β when activated, they ground the Bluetooth IC pin. In this Bluetooth speaker model, each button has dual functions depending on the press duration, which is also emulated in code. We only need to control 3 buttons: Volume+(FF), Volume-(REW), and Play(Pause). By controlling the pulse duration to the MOSFET gate in code, we simulate the button press duration.
The diagram also shows how to sample audio from the module's audio output. A voltage divider circuit is implemented, and the signal passes through a resistor and electrolytic capacitor to pin D36(VP).
As seen in the power connection diagram earlier, turning the Bluetooth module on and off is done through a relay (IN2) controlled by the ESP32 from pin D18.
Finally, the DHT22 temperature and humidity sensor connects to pin D23. This sensor can be powered with 5V or 3V, so there's no issue choosing either. For better temperature and humidity monitoring, it is recommended that the sensor be exposed to the outside air.
Here are some photos of the finished lamp:
The project essentially boils down to controlling the lamp via the web from any connected device. The ESP32 stays in station mode, waiting for another device to enter AP (portable hotspot) mode with the correct credentials to connect. Why did I choose station mode?
On the web interface, you'll notice Wi-Fi signal strength indicators in the bottom right corner showing the connection quality between your device and the lamp. This can only be achieved if the ESP32 is in station mode.
The ESP32 creates an asynchronous server (ESPAsyncWebServer), meaning it can handle multiple clients simultaneously (8) and sends data in JSON format via WebSocket. With this setup, up to 8 devices connected to the lamp receive real-time updates, and changes are reflected on all devices simultaneously.
The ESP32 hosts an embedded website in SPIFFS memory; the web content is in the project's
Three objects are created:
StripLedβ Neopixel strip controlLedβ ESP32 onboard LED controlBatteryβ Battery control and monitoring
The remaining libraries handle lighting effects and music-synchronized effects (VU), along with the web server, battery monitoring, and DHT22 sensor. Below are the most important variables you may need to adjust.
- Debug variables
#define DEBUGLEVELβ set to DEBUGLEVEL_DEBUGGING for serial debug output#define DHTβ comment out with (//) to hide DHT22 messages#define BATTERYβ comment out with (//) to hide battery monitoring messages
Note: Some debug messages, such as connection and web service info, are mandatory.
- Neopixel strip variables
#define N_PIXELSβ number of LEDs in your stripint brightnessβ initial brightness (default 130, a bit over half brightness)
- Battery management variables
#define MAXVβ Maximum voltage when battery is fully charged#define MINVβ Minimum voltage to start charging (default 3.2V)
Note: For accuracy, charge the battery using the TP4056 module. When the full charge LED turns on, measure the battery voltage and use that as the maximum value. For the minimum value, the DC-DC step-up module specifications state that to achieve 5V output, the input must be at least 2V. However, 3.2V is recommended for safety.
- Web variables
const unsigned long refreshβ delay for sending information (default 3 seconds)
Note: The project currently uses PlatformIO as its development environment. The
platformio.inifile in the project root contains all build configuration, dependencies, and serial port settings.
- VS Code with the PlatformIO extension
- Or PlatformIO Core via command line
# Compile the project
pio run
# Upload firmware to ESP32
pio run --target upload
# Monitor serial port
pio device monitor
# Clean build files
pio run --target cleanThe HTML, CSS, JS, and image files are in the data/ folder and are stored in the ESP32's LittleFS (SPIFFS). After modifying any web files:
pio run --target uploadfsIn src/config/debug_config.h you can control which messages appear on the serial port:
| Macro | Description |
|---|---|
DEBUGLEVEL_DEBUGGING |
Enables all debugging |
#define DHT |
Shows DHT22 sensor messages |
#define BATTERY |
Shows battery monitoring messages |
#define DEBUG_POWER_MANAGEMENT |
Shows power manager state transitions |
The ESP32 runs an asynchronous web server (ESPAsyncWebServer) with real-time WebSocket communication. It supports up to 8 simultaneous clients, and changes are reflected instantly on all connected devices (ideal for family control).
The interface is organized into 8 tabs accessible from the sidebar (or bottom bar on mobile):
Main lamp control:
- On/Off for the main LED lamp
- On/Off for the Neopixel strip
- Color picker with color wheel (iro.js)
- Brightness slider for the Neopixel strip
- Light effects (see Effects section)
Bluetooth speaker control:
- Play / Pause
- Volume + / Volume -
- Fast Forward / Rewind
- On/Off for the Bluetooth module
- VU effects β music visualization
Real-time LED strip preview via a canvas updated over WebSocket (~30 FPS). Displays the 24 LEDs interpolated as 33 virtual LEDs with two view modes:
- Strip β horizontal linear layout
- Circle β circular layout (simulates the lamp's real shape)
- Quick config button for the active effect
- FPS indicator and stream status
DHT22 sensor data:
- Temperature (Β°C)
- Relative humidity (%)
- Updates every 3 seconds
Detailed battery status:
- Charge percentage
- Current voltage
- Status: charging / fully charged / discharging
- Historical voltage graph
- Visual power source indicator (AC or battery)
Advanced configuration panel:
- Themes: SML Classic, WLED Dark, Midnight AMOLED
- WiFi: change SSID and password without re-flashing firmware
- Firmware Update: direct link to ElegantOTA
- System Info: uptime, free heap, WiFi RSSI, firmware version, MAC and IP address
- Connected clients: list of active WebSocket connections
- Activity logs: record of actions performed from the web interface
Quick reference guide for all lamp features.
Project information, version, and links.
The project includes over 40 visual effects organized into categories. Access them from the Lamp tab β Effects section.
| Category | Description |
|---|---|
| β Favorites | Your favorite effects (star-marked) |
| π Playlist | Custom playlist for random mode |
| π§ Fundamentals | Base effects: solid, flash, fade |
| π Moving | Motion effects: dot, comet, sinelon, scan |
| β‘ Dynamics | Dynamic effects: fire, lightning, aurora, popcorn |
| π¨ Patterns | Patterns: rainbow, theater chase, sweep, dissolve |
| π‘οΈ States | Status effects: battery, temperature |
| π Random | Random mode (see next section) |
In addition to traditional visual effects, there are VU effects that react to audio playing through the Bluetooth speaker. They are located in the Music tab and activate automatically when there's audio input. Examples include:
- Rainbow VU β multi-colored bars in sync with the music
- Ripple VU β concentric waves reacting to the rhythm
- Frequency Spectrum β equalizer-style visualization
- Single click/tap β selects and activates the effect
- Second click/tap (on the same active effect) β opens the configuration panel where you can adjust:
- Speed β effect speed
- Color β palette or primary color
- Intensity β brightness or effect intensity
- Effect-specific parameters
The lamp can cycle through effects automatically without intervention. There are two modes:
Cycles through visual effects on the Neopixel strip with configurable duration per effect.
Selection modes:
- All β any available effect
- Favorites β only your star-marked effects
- Categories β choose one or more specific categories
- Playlist β custom sequence that you order yourself
Similar to above but with VU effects (music visualization). Ideal for leaving the lamp in ambient music mode.
- Duration per effect β how long each effect stays active (configurable)
- On/Off from the Random FX or Random VU card in the effects list
- Preview of the current effect in the Peek panel
The ESP32 implements an automatic power management system with a state machine that detects the power source and optimizes consumption.
| State | Power Source | WiFi | CPU | Neopixel | Consumption |
|---|---|---|---|---|---|
| AC_MODE | Mains | Always ON | 240 MHz | On | ~180 mA |
| BATTERY_CONNECTING | Battery | 10s ON / 30s wait | 240 MHz | Off | ~120 mA |
| BATTERY_ACTIVE | Battery + client connected | Always ON | 240 MHz | Off | ~120 mA |
| BATTERY_SLEEP | Battery, no client | 10s ON / 60s OFF | 80 MHz | Off | ~25 mA |
- AC loss β try to connect 10s β wait for client 30s β sleep if no client
- Client connects β instant wake from any state
- Client disconnects β wait 30s for reconnection β sleep
- AC restored β immediate return to full operation
- Battery < 15% β force maximum power saving
Uses the TP4056 pins: if charging or battery is full, it assumes AC power is present. Includes 3-second debounce to prevent rapid state changes from power flickers.
You can update the ESP32 firmware without a USB cable, directly from your browser:
- Connect to the ESP32's WiFi network
- Open
http://<esp32-ip>/update - Select the compiled
.binfile - Click Update and wait for the ESP32 to reboot
Or from the web interface, go to Config tab β Firmware Update section.
- Scheduled alarm system (turn on lamp at set times)
- Push notifications to mobile when battery is low
- Collaborative effects (multiple synchronized ESP32s)
- Home Assistant integration
- Native Android/iOS app
- User profiles (save complete configuration)
- Support for larger addressable LED strips (>100 LEDs)
- Real-time graphic equalizer on the web interface
- Alarm clock mode (simulate sunrise with LEDs)
| Alexminator |
|---|
|
The SML project is released under the GNU General Public License v3.0.
Need help? Contact me π¨ alexminator99@gmail.com
- VSCODE β Code editor.
- PlatformIO β C/C++ programming IDE for hardware.
- danilopinotti for the Battery18650Stats library
- me-no-dev for ESPAsyncWebServer and AsyncTCP
- FastLED for the incredible LED library
- ElegantOTA for hassle-free OTA updates
- PlatformIO for the excellent embedded development ecosystem
- The Cuban Arduino community.
- To everyone who helped me when I had doubts, especially my son.
- To my wife, for being the initial inspiration for this project β€οΈ






























