The Cupboard That Plays James Brown
An Arduino, a light sensor, and a speaker hidden in a kitchen cupboard. Open the door, get James Brown at full volume. A prank built with my son Vasco and his cousin Ary.
Vasco had the idea. Not me.
"What if when mum opened the kitchen cupboard, a song started playing?" Pause. "Like, James Brown."
It took me two seconds to realize it was an excellent idea, and two more to realize it was completely doable with what we already had at home.
The Concept
Inside the cupboard it's dark. When the door opens, light floods in. A photoresistor (LDR) detects the change and tells the Arduino to blast "I Feel Good" through a small speaker hidden behind the cereal boxes.
No buttons, no timers, no app. Just light and sound.
Every component came from the previous project: the Crazy Shoe that Vicente wore at his school's Science Week. Arduino Uno, DFPlayer Mini, 8Ω speaker, SD card. We didn't need to buy anything.
Vasco and his cousin Ary were my accomplices on this one. The three of us built it on a Saturday afternoon while mum was out.
What Went Wrong (Almost Everything, in Order)
The Threshold
The original sketch had THRESHOLD = 600. The photoresistor inside the closed cupboard reads ~90. Open, it reads ~300. The threshold would never be reached. Calibration needed: new value, 150.
The DFPlayer Wouldn't Initialize
The Serial Monitor kept printing DFPlayer failed. Blue LED off. No sound.
Here's where the real debugging started.
First suspect: the SD card. From the Crazy Shoe we'd learned the DFPlayer is picky. FAT32 only (exFAT doesn't work), files copied in order right after formatting, structure 01/001.mp3. We reformatted, recopied. Nothing.
Second suspect: the wiring. The DFPlayer has two GND pins, one on each side of the module. We'd only connected one. Wired the second. The blue LED lit up, the module was getting power. Still failed to initialize.
Third suspect: SoftwareSerial pins.
This was the subtle one. The constructor is SoftwareSerial(rxPin, txPin). rxPin is what receives data from the DFPlayer's TX, txPin is what sends to the DFPlayer's RX. We had mySerial(10, 11) but the DFPlayer's TX was on D11 and RX on D10. Inverted.
The fix: SoftwareSerial mySerial(11, 10).
The Serial Monitor responded DFPlayer OK.
Serial Sabotaging the Sound
DFPlayer initialized. Trigger firing (TRIGGER! in the monitor). But no sound.
The problem: Serial.println in the loop, running every 100ms for debug, was using interrupts. The same interrupts SoftwareSerial needs to communicate with the DFPlayer. They were fighting each other.
The fix: remove all Serial code before testing sound. With Serial gone, the DFPlayer started responding.
Boot Timing
After removing Serial, the DFPlayer initialized but the sound only played one out of three times. The pattern was clear: first activation after power-on worked, subsequent ones were inconsistent.
We added delay(1000) before player.begin() and another after. Not elegant, but the DFPlayer Mini (especially the clones) needs time to stabilize before accepting commands.
The Reset That Didn't Reset
The last piece: after playing once, covering and uncovering the sensor should prime the system to play again. Sometimes it did, sometimes it didn't.
What was happening: the trigger fired, played became true, lastPlay was recorded. Then the light oscillated, the reset of played to false happened almost immediately, but lastPlay had just been set and MIN_INTERVAL blocked the next activation for several seconds.
The fix: only allow reset after 3 seconds since the last play.
if (light < 120 && (now - lastPlay > 3000)) {
player.stop();
played = false;
}
The music starts without interference. When the cupboard closes, it stops. Open again, it plays again.
The Moment
After maybe two hours of debugging (the wiring, the inverted pins, the Serial conflict, the delays), the cupboard opened and James Brown sang "I Feel Good."
Vasco started laughing before the song finished. Ary was already planning where to hide the speaker for maximum impact.
What Two DFPlayer Projects Taught Us
After the Crazy Shoe and this, clear patterns have emerged:
SoftwareSerial pins are easy to invert. The constructor is (rx, tx) from the Arduino's perspective. rx receives from the DFPlayer's TX, tx sends to the DFPlayer's RX. Worth double-checking before spending an hour debugging.
Two GND pins, both connected. The module has GND on both sides. One isn't enough.
Serial and SoftwareSerial don't coexist in the loop. Use Serial Monitor for threshold calibration. Remove it completely for sound testing.
Delays in setup aren't optional. At least 1000ms before begin() and after. Clones are particularly demanding.
playFolder is more reliable than play. Discovered in the Crazy Shoe, confirmed here.
The prank is ready. Now we just need to install it in the cupboard without mum noticing.