It started in January with a simple, romantic idea: build two identical lamps, keep one, and give the other to my wife. When one of us touches our lamp to change its color, the other lamp, miles away, instantly changes to match it. A digital embodiment of quantum entanglement.
On paper, the architecture seemed straightforward. An ESP32 microcontroller, a ring of NeoPixel LEDs, a homemade capacitive touch sensor, and a web server to sync the states. Read a sensor, light an LED, send a web request. How hard could it be?
As it turns out, bridging physical craftsmanship with the cloud is a masterclass in hidden complexity. The "Quantum Light" project became a labor of love that spanned woodworking, embedded systems, low-level peripheral timing, and full-stack network architecture.
I wanted the lamps to look as magical as they acted. I started by building custom wooden stands to house the electronics. For the covers, I cut sheets of clear acrylic glass and carefully glued them together into rectangular boxes.
To give the light a soft, ambient glow rather than a harsh glare, I applied a frosted effect to the acrylic. The final aesthetic touch was a set of custom stencils—a peaceful silhouette of palm trees and subtle hearts. Waiting for these specific stencils to arrive took several agonizing weeks, pushing my timeline right past the mid-February deadline. Ultimately, I gave the lamp to my wife the day after Valentine's Day. Thankfully, she knew I had been working on something special for a long time, so the slight delay only added to the anticipation.
To trigger the color changes, I didn't want a clunky mechanical button. Instead, I lined the inside with copper tape, wiring it directly to the ESP32 to act as an invisible capacitive touch sensor. Running a finger along the lamp would magically command the colors to flow.
While I had tinkered with simpler microcontrollers in the past, this project was my first time working deeply with the ESP32 and Espressif’s native IoT Development Framework (ESP-IDF). It’s a massive leap in capability from the Arduino environment, but it comes with its own steep learning curve.
Instead of a single, simple loop, I had to architect a real-time system utilizing the dual-core nature of the ESP32 and FreeRTOS. I separated the workload: one core handles the sensitive, high-priority hardware interrupts of the capacitive touch sensor, while the other core manages the heavy lifting of network cryptography and cloud synchronization. To allow these background tasks to communicate safely without crashing the system, I utilized RTOS event queues. When you release your finger from the copper tape, the touch task simply drops a color packet into a queue, and the background network task picks it up and fires it to the cloud.
I didn't want to hardcode our home Wi-Fi passwords into the firmware—what happens when the router is replaced, or if she takes the lamp to her office?
Leaning heavily into the ESP SDK, I implemented their official Wi-Fi Provisioning manager. When the lamp boots up without a known network, it starts broadcasting a Bluetooth (BLE) signal and goes into a breathing blue setup mode. Using the official ESP BLE Provisioning smartphone app, we can securely pair the lamp to a new Wi-Fi network just like a commercial smart home product. It added a layer of professional polish that made the gift feel incredibly premium.
Once the physical build was coming together, the electronics threw a curveball. The lights turned on, but they flickered wildly, randomly throwing rainbow colors across the frosted glass.
NeoPixels don't use standard communication protocols; they require a highly precise, timing-dependent pulse train where a fraction of a microsecond determines a 1 or a 0. Initially, the ESP32's CPU generated these signals. But the Quantum Light is an IoT device. Every time the CPU paused to handle a Wi-Fi interrupt, it starved the LED data buffer. The NeoPixels interpreted this microscopic pause as a "Reset" command, latching whatever scrambled data they had and vomiting rainbows.
The solution was Direct Memory Access (DMA). I had to dive deep into the SDK to pivot the firmware, hijacking the ESP32's SPI bus. By configuring the SPI peripheral to use DMA, the hardware controller could push perfect, unbroken color commands directly from memory to the LEDs, completely bypassing the CPU. The CPU was left free to manage the Wi-Fi, and the flickering vanished, leaving a rock-solid, glowing landscape.
With the lights stable, I implemented a smooth "Hue Flow" animation when you held your finger on the copper tape. But the colors didn't flow smoothly; the green channel would rise beautifully and then violently crash to zero, creating a jagged, ugly transition.
The bug was hidden in the hsv_to_rgb math. A temporary variable used to calculate the color wheel sectors was defined as an 8-bit integer (uint8_t). As the math crossed a certain threshold, the value hit 258, overflowed the 255 maximum, and wrapped around to 2. Changing a single variable to a 16-bit integer restored the buttery smooth rainbow fade across the frosted acrylic.
The final piece of the puzzle was the "entanglement." Initially, the lamps used standard HTTP requests, polling a Python server every few seconds to ask, "Did the color change?"
This was terribly inefficient. It wasted bandwidth, ate up CPU cycles, and created a frustrating lag. If you tapped the light, you had to wait up to 3 seconds for the network to catch up.
The architecture was entirely rewritten to use WebSockets and a Node.js server. This changed the paradigm from polling to event-driven. The lamps now maintain a persistent, silent, secure connection to the server. When you lift your finger from the copper tape, the ESP32 instantly fires a JSON payload into the RTOS queue, flushes any old data, and pushes it through the WebSocket. The Node.js server receives it and instantly broadcasts it to the other lamp.
The result? Zero polling. Zero CPU overhead when idle. The moment you touch one lamp, the other lamp changes color in milliseconds.
What looks like a glowing, frosted box of palm trees on a wooden stand is actually a symphony of isolated systems working perfectly together. It required hand-crafting acrylic, utilizing dual-core RTOS queues, managing sub-microsecond signal timing via SPI, navigating integer overflows, and maintaining persistent cryptographic web sockets.
The "Quantum Light" was a day late for Valentine's Day, but it works beautifully. It stands as a daily, glowing reminder of love, and a testament to the profound, hidden complexity inside the things we build.