Community project
Interactive Photo Booth Controller
This interactive photo booth controller combines an ESP32-based lighting system with a Raspberry Pi 5 compute engine to create a fully automated photo capture and display setup. The project integrates addressable RGB strips, dual-white CCT lighting, and dual camera modules to deliver professional-quality booth photography with real-time lighting control and image processing.
Builders will receive a complete wiring diagram, detailed parts list with sourcing information, step-by-step assembly instructions covering power distribution, level shifting, and LED integration, plus firmware configuration guides for both the WLED controller and custom ESP32 application. The guide walks through safety protocols, component mounting, and system calibration to get the photo booth operational.
Wiring diagram
Interactive · read-only
Pan and zoom to explore the wiring. Remix the project to edit it in your own workspace.
Parts list
Bill of materials| Component | Qty | Notes |
|---|---|---|
| WeAct ESP32-D0WD-V3 Core Board (ESP32-A, WLED) | 1 | WeAct ESP32-D0WD-V3 dual-core, external SPI flash W25QxxJVSSIQ, NO PSRAM. GPIO16/17/18 are free GPIOs confirmed by header silkscreen. 5V input via header 5V pin (diode-ORed D1/D2 SOD123 with USB VBUS — safe to feed from RM650e 5V while USB unplugged). Onboard AMS1117-3.3 regulator. Runs WLED for addressable strip + CCT PWM. |
| WeAct ESP32-D0WD-V3 Core Board (ESP32-B, Custom FW / Spare) | 1 | WeAct ESP32-D0WD-V3 dual-core, external SPI flash, NO PSRAM — identical chip to ESP32-A. Runs custom newline-delimited-JSON firmware (adapters/lighting/esp32.py ADR-0028). TCP transport default (no signal wires to Pi 5). Optional SerialEsp32Transport via UART if TCP replaced. Powered from RM650e 5V rail. |
| 74AHCT125 Quad Buffer / Level Shifter | 1 | Quad non-inverting buffer/line driver with 3-state outputs and active-low output-enable pins. In 5 V AHCT/HCT designs, 3.3 V MCU outputs are high enough for the TTL-level inputs, making it a common one-way 3.3 V to 5 V level shifter for WS2812/NeoPixel data and other fast digital lines. |
| Logic-Level N-MOSFET Module — Warm White (CCT Ch1) | 1 | Pre-built low-side N-MOSFET switch module (IRLZ44N or AOD4184-class) with onboard gate resistor and pulldown. Switches warm-white cathode of CCT ring strip. Gate driven directly from 3.3V ESP32 GPIO17 — logic-level FET switches fully at 3.3V. |
| Logic-Level N-MOSFET Module — Cool White (CCT Ch2) | 1 | Identical to warm module. Switches cool-white cathode of CCT ring strip. Gate driven from ESP32 GPIO18. |
| WS2815 RGB Side-glow/Rear Wall-wash Strip (12V, 60 LED/m) | 1 | 12V addressable RGB LED strip, WS2815 protocol (GRB), 60 LEDs/m. Built-in backup data line for redundancy. Segmented into side-fin and rear-wash runs via JST-SM 3-pin pigtails. 1000µF ≥16V electrolytic cap across V+/GND at strip start. DIN receives 5V logic from 74AHCT125 1Y output via 330–470Ω series resistor. Each segment daisy-chains V+/GND/DIN. |
| CCT Ring Light Strip — Dual-White COB 12V 2700K–6500K | 1 | Dual-white COB LED strip, 12V. Three wires: V+ common 12V anode, W warm-white cathode (low-side switched by MOSFET#1), C cool-white cathode (MOSFET#2). Not addressable — PWM brightness via MOSFET switches. |
| Series Resistor — WS2815 DIN signal390 Ω | 1 | 330–470Ω series resistor on the WS2815 DIN data line, between 74AHCT125 1Y output and strip DIN. Damps ringing on long cable runs. |
| Bulk Decoupling Cap — WS2815 strip head1000 µF 25V | 1 | 1000µF ≥16V electrolytic capacitor across V+/GND at the start of the WS2815 strip. Absorbs power-on inrush and protects first LEDs. |
| Raspberry Pi 5 (16GB) — Main Compute | 1 | Raspberry Pi 5, 16GB RAM. Powered via USB-C from RM650e 5V rail (plain DC — no USB-PD CC signalling, caps at 3A/15W; add ZY12PDN trigger board if throttling observed). Runs picamera2, booth software. Active Cooler + RTC battery (JST-PH) fitted. |
| Raspberry Pi Camera Module 3 (Standard FoV) | 1 | Official RPi Camera Module 3, standard field of view. 12MP Sony IMX708. Connects via 22-pin MIPI CSI-2 ribbon (300mm) to Pi 5 CSI0 port. Power and data carried entirely on the ribbon — no external wiring. |
| Raspberry Pi Camera Module 3 Wide | 1 | Official RPi Camera Module 3 Wide FoV. 12MP Sony IMX708. Connects via 22-pin MIPI CSI-2 ribbon (300mm) to Pi 5 CSI1 port. Power and data on ribbon. |
| Riverdi RVT121HVHNWC00-B 12.1" Touchscreen | 1 | 12.1-inch 1280×800 TFT with HDMI video input and USB capacitive touch controller. Video from Pi 5 HDMI0 via micro-HDMI to HDMI cable. Touch from Pi 5 USB via USB-C to USB-A cable. Powered by dedicated 12V DC PSU (not from RM650e backbone). |
| Raspberry Pi Zero 2 WH (Marquee Host) | 1 | Pi Zero 2 WH with pre-soldered 2×20 header. Runs rpi-rgb-led-matrix marquee agent. Powered directly from RM650e 5V rail — do NOT simultaneously power via micro-USB if bonnet also provides 5V through header (verify on bench). Connects to Adafruit RGB Matrix Bonnet via 40-pin header (board-to-board, no loose wires). |
| Adafruit RGB Matrix Bonnet (for Pi Zero 2 WH) | 1 | Adafruit product #3211. Plugs directly onto Pi Zero 2 WH 40-pin header. Onboard level shifters (3.3V→5V). Exposes HUB75 IDC connector(s) for up to 32×128 chained panels. Bonnet standard pinout: CLK=GPIO17, LAT=GPIO4, OE=GPIO18, R1=GPIO5, G1=GPIO13, B1=GPIO6, R2=GPIO12, G2=GPIO16, B2=GPIO17-conflict—handled by rpi-rgb-led-matrix driver, A=GPIO22, B=GPIO23, C=GPIO24, D=GPIO25. Provides 5V power feed to Pi Zero via GPIO header (verify revision; may back-power Zero). Note: bonnet I2C/SPI pins (GPIO2/3) are consumed by HUB75 matrix driver. |
| HUB75 64×32 P2.5 RGB Matrix Panel #1 | 1 | P2.5 64×32 HUB75 LED matrix panel. Left panel of 128×32 combined marquee canvas. HUB75 IN from bonnet HUB75 OUT. HUB75 OUT daisy-chains to Panel 2. 5V power injected separately via dedicated 18AWG pair to panel power terminals (not via HUB75 ribbon). Max ~3.85A at full white; brightness-limited in software. |
| HUB75 64×32 P2.5 RGB Matrix Panel #2 | 1 | P2.5 64×32 HUB75 LED matrix panel. Right panel of 128×32 marquee. HUB75 IN from Panel 1 HUB75 OUT. HUB75 OUT unused (end of chain). 5V power injected separately. |
| Illuminated Arcade Button #1 (24mm) | 1 | Momentary normally-open arcade button with 12V-rated built-in LED. Switch contacts are independent from LED circuit. LED has internal series resistor — wire directly to 12V, no external resistor needed. |
| Illuminated Arcade Button #2 (24mm) | 1 | Momentary normally-open arcade button with 12V-rated built-in LED. Switch contacts are independent from LED circuit. LED has internal series resistor — wire directly to 12V, no external resistor needed. |
| Illuminated Arcade Button #3 (24mm) | 1 | Momentary normally-open arcade button with 12V-rated built-in LED. Switch contacts are independent from LED circuit. LED has internal series resistor — wire directly to 12V, no external resistor needed. |
| TCS34725 Colour/Lux Sensor Breakout (Optional — Stage-future) | 1 | I2C colour and lux sensor breakout. Native 3.3V — no level shifting needed on Pi 5 I2C1. VIN 3.3V from Pi 5 pin 1. I2C address 0x29. For future ExposureService / KI-006. |
| Corsair RM650e ATX 3.0 PSU — DC Backbone | 1 | Corsair RM650e, 650W, 80+ Gold, ATX 3.0. Runs without motherboard via PS_ON jumper (24-pin pin 16 green → pin 15/17 black). Sole DC source for entire booth. 12V and 5V taken from modular SATA/Molex/PCIe cables. 3.3V unused. Verify actual rail amperage on PSU label before sizing branch fuses. |
| Switched Mains Power Strip (Booth Master Switch) | 1 | Standard switched power strip inside the booth enclosure. Single IEC/mains output feeds the Corsair RM650e ATX PSU — the ATX PSU is the sole DC source for all booth loads (Pi 5, screen, lighting, marquee, ESP32s). The strip's rocker switch is the booth master on/off. |
| USB-Serial Programmer port (ESP32-A) | 1 | USB micro-B or USB-C port on the WeAct ESP32-A board. Used for programming/flashing only. Not a permanent signal connection. |
| USB-Serial Programmer port (ESP32-B) | 1 | USB port on WeAct ESP32-B board. Programming only. Optional permanent UART wiring to Pi 5 if SerialEsp32Transport is used. |
| Building Mains Outlet (100–240V AC) | 1 | Single building mains outlet supplying the switched power strip. |
Assembly
14 stepsSafety first — all work with mains de-energised
Before wiring anything, confirm the switched power strip is OFF and unplugged from the wall. All three supplies (ATX PSU, Pi 5 USB-C PSU, screen 12V PSU) must be disconnected from mains. Work on a non-conductive surface. The Corsair RM650e contains lethal mains voltage internally even when the rocker switch is OFF — never open its enclosure.
- ⚠ Never work on wiring with any supply plugged into mains.
- ⚠ RM650e internal capacitors can hold charge — if you have handled it live, wait 30 s after disconnecting before touching modular cable sockets.
Force-on the Corsair RM650e (PS_ON jumper)
On the RM650e's 24-pin ATX main connector: locate pin 16 (green PS_ON wire) and pins 15 or 17 (black COM wires). Bridge them with a short solid-core wire or a commercial 24-pin ATX paperclip/breakout block. This permanently latches the PSU to turn on whenever mains is applied — the PSU's own IEC rocker switch then serves as the booth DC backbone on/off. Tape or heat-shrink any unused 24-pin pins to prevent accidental shorts. Do NOT connect the 24-pin connector to a motherboard.
- Tip: Commercial '24-pin ATX jumper' blocks (available for <$5) are tidier than a loose wire and have labelled positions.
- Tip: Leave the 3.3V (orange) and 5VSB (purple, pin 9) wires capped — not used by this design.
- ⚠ 5VSB on pin 9 is live whenever mains is connected, even before PS_ON pulls low. Never short it.
Build the 12V and 5V distribution buses
From the RM650e's SATA or Molex modular cables, tap 12V (yellow) and 5V (red) wires plus COM (black). Feed each rail into a WAGO 221 lever connector junction block as the distribution point. From each junction, run individual branches through inline blade/glass fuse holders to each load group. Suggested fuse sizing: • 12V → WS2815 strip + cap: 5A fuse • 12V → CCT strip (via MOSFETs): 3A fuse • 12V → button LEDs ×3: 1A fuse • 5V → ESP32-A + ESP32-B: 2A fuse • 5V → Pi Zero 2 WH (via bonnet): 3A fuse • 5V → HUB75 Panel 1 power: 5A fuse (18AWG wire) • 5V → HUB75 Panel 2 power: 5A fuse (18AWG wire) All COM (black) wires join at a single star-point WAGO connector — this is the system common ground.
- Tip: Use 18AWG red/black for 12V and 5V power runs, 22AWG for signal.
- Tip: Label each fused branch at the fuse holder with a permanent marker.
- Tip: Rate fuses at the load's expected current + 50%, rounded up to the next common value.
- ⚠ Verify the actual amperage printed on the RM650e label for 5V and 12V rails before finalising fuse values — use the label amps, not the total wattage.
- ⚠ Do not daisy-chain fuse holders in series — each branch gets its own fuse from the distribution junction.
Mount and power ESP32-A (WLED Controller)
Mount the WeAct ESP32-A board on M2.5 standoffs inside the enclosure. Connect: • ESP32 5V pin → 5V fused branch (ESP32 branch) • ESP32 GND pin → common ground star point Do not connect GPIO pins yet.
- Tip: Check the specific WeAct ESP32 silkscreen carefully — the 5V/VIN pin position varies between WeAct revisions. Confirm with a multimeter before powering.
Install 74AHCT125 level shifter
Mount the 74AHCT125 (DIP-14 or breakout) near ESP32-A. Wire: • Pin 14 (VCC) → 5V rail • Pin 7 (GND) → common ground • Pin 1 (1OE, output enable) → GND (tie permanently low = always enabled) • Pin 2 (1A, input) → ESP32-A GPIO16 (22AWG) • Channels 2/3/4: tie their OE pins (pins 4, 10, 13) HIGH (to VCC) to disable unused outputs • Pin 3 (1Y, output) → one leg of the 390Ω series resistor (instance: resistor_ws2815) • Other leg of 390Ω resistor → WS2815 strip DIN
- Tip: The AHCT125 inputs are TTL-compatible — 3.3V from ESP32 is above the 2V VIH threshold at 5V supply, so level shifting works correctly.
- Tip: Place the IC as close to the ESP32 as practical to keep the 3.3V input trace short.
Connect WS2815 RGB strip
At the start of the WS2815 strip: 1. Solder or connect a 1000µF ≥16V electrolytic capacitor (cap_ws2815) between V+ and GND on the strip's input pads — positive leg to V+, negative to GND. Keep leads short. 2. V+ → 12V fused branch (18AWG red, WAGO junction) 3. GND → common ground star (18AWG black) 4. DIN → 390Ω resistor output (from level shifter 1Y) Segmented runs: each segment's input JST-SM 3-pin pigtail receives V+/GND/DIN daisy-chained from the previous segment.
- Tip: Install the bulk cap before powering — without it, the first few LEDs can be damaged by inrush on power-on.
- Tip: Check strip polarity on V+. WS2815 strips are marked with an arrow indicating DIN direction.
- ⚠ Electrolytic capacitors are polarised — positive leg to 12V, negative to GND. Reversed polarity will destroy the cap.
Install CCT ring light MOSFETs and strip
Mount MOSFET module #1 (mosfet_warm) and module #2 (mosfet_cool) on standoffs or directly into the enclosure. Wire each module: • GATE ← ESP32-A GPIO17 (warm) / GPIO18 (cool) — 22AWG • SOURCE → common ground • DRAIN → CCT strip W wire (warm) / C wire (cool) CCT strip V+ (common anode) → 12V fused branch The MOSFETs pull each strip channel's return to ground in a PWM pattern.
- Tip: Logic-level MOSFETs (IRLZ44N, AOD4184) switch fully with 3.3V gate drive — no level shifting needed here.
- Tip: No external gate resistor needed if the module has one built in. Verify the module datasheet.
Flash and configure WLED on ESP32-A
With ESP32-A powered via USB (before connecting it to the RM650e 5V rail), use Schematik's Deploy button to flash the firmware.cpp fallback sketch, then switch to WLED binary from install.wled.me (select ESP32). After flashing, connect via WLED's own Wi-Fi AP to configure: • LED Output 1: Type WS2815/WS281x, Data pin 16, GRB, count = your LED count • LED Output 2: Type PWM White, Data pin 17 (warm) • LED Output 3: Type PWM White, Data pin 18 (cool) • Enable CCT mode for outputs 2+3 • Wi-Fi: join booth SSID • Note the assigned IP address — this is what ADR-0027 TcpWledTransport points to.
- Tip: The bench-test firmware (firmware.cpp) sweeps the CCT channels to verify MOSFET wiring before you flash WLED.
- Tip: Verify MOSFET channels respond to the bench sweep before committing to the WLED binary.
Mount and power ESP32-B (Custom FW / Spare)
Mount ESP32-B identically to ESP32-A. Connect 5V → 5V fused branch, GND → common ground star. Default transport is TCP/Wi-Fi — no signal wires to Pi 5 needed in normal configuration. Flash the project custom firmware (adapters/lighting/esp32.py companion sketch from the project repo) via Schematik Deploy. If opting for UART serial transport instead, also wire: • ESP32-B TX → Pi 5 GPIO15 (physical pin 10) — 22AWG • ESP32-B RX ← Pi 5 GPIO14 (physical pin 8) — 22AWG • Add a wire from Pi 5 GND (physical pin 6 or 9) to the RM650e common ground star point (required for shared logic reference).
- ⚠ Only bond Pi 5 GND to the RM650e star point if using the wired UART transport. If TCP-only, the Pi 5 operates on its separate PSU with no ground tie.
Assemble Pi Zero 2 WH + RGB Matrix Bonnet + HUB75 panels
1. Mount the Raspberry Pi Zero 2 WH on M2.5 standoffs. 2. Press the Adafruit RGB Matrix Bonnet onto the Pi Zero 2 WH 40-pin header — board-to-board, no loose wiring. 3. Connect the RM650e 5V branch to the bonnet's power input (screw terminal or barrel jack on the bonnet board — check the specific bonnet revision). 4. Verify whether the bonnet back-powers the Pi Zero via the GPIO 5V pin. If it does, no separate power cable to the Pi is needed. If it does NOT, attach a micro-USB pigtail from the 5V branch to the Pi's power micro-USB — but never connect both paths simultaneously. 5. Run HUB75 IDC ribbon from bonnet HUB75 OUT to Panel 1 HUB75 IN. 6. Run second HUB75 IDC ribbon from Panel 1 HUB75 OUT to Panel 2 HUB75 IN. 7. Inject 5V power to each panel's dedicated power input terminal (JST or screw terminals on the panel PCB, separate from the HUB75 IDC port) with its own 18AWG pair from the fused 5V branch. Do not rely on the HUB75 ribbon for panel power.
- Tip: Mount panels side-by-side to form the 128×32 combined canvas.
- Tip: The bonnet has onboard level shifters (3.3V→5V) for HUB75 — no extra level shifting needed.
- ⚠ Never power the Pi Zero from both the GPIO 5V pin (bonnet) and the micro-USB simultaneously. Pick one, verify on bench first.
- ⚠ HUB75 ribbon 5V pins are not rated for full panel current — always inject panel power directly.
Wire arcade buttons to Raspberry Pi 5
For each of the three illuminated arcade buttons: Switch circuit (active-low): • Button switch terminal A (SW1) → Pi 5 GPIO: Button1→GPIO5 (pin 29), Button2→GPIO6 (pin 31), Button3→GPIO13 (pin 33) — 22AWG • Button switch terminal B (SW2) → common GND (Pi 5 GND pin 30 or 34, tied to system GND) LED circuit (always-on, 12V): • LED+ spade terminal → 12V fused branch (use 4.8mm quick-connect spade) • LED- spade terminal → common GND Buttons use Pi 5's internal pull-up resistors in software (RPi.GPIO PUD_UP) — no external resistors needed on switch legs.
- Tip: Use 4.8mm quick-connect spade terminals for button tabs for tool-free replacement.
- Tip: Label each button's GPIO wire at both ends before routing inside the enclosure.
Connect cameras, touchscreen, and Pi 5 power
1. Cameras: insert 22-pin MIPI CSI-2 ribbons (300mm) into Pi 5's CSI0 (Camera Module 3 standard) and CSI1 (Camera Module 3 Wide) connectors. The ribbon carries power and data — no other wiring needed. 2. Touchscreen HDMI: micro-HDMI (Pi 5 HDMI0) → HDMI cable (1m) → Riverdi screen HDMI input. 3. Touchscreen USB touch: Pi 5 USB-A port → USB-A to USB-C cable → Riverdi screen USB-C touch port. 4. Touchscreen power: connect dedicated 12V PSU (screen_psu) barrel/terminal to Riverdi screen 12V IN. 5. Pi 5 power: official 27W USB-C PSU (pi5_psu) → Pi 5 USB-C power port. This PSU must NOT be substituted. 6. Plug all three mains supplies into the switched power strip.
- ⚠ The Pi 5 official USB-C PSU is mandatory — a generic 5V supply without USB-PD CC resistors caps the Pi at 3A (15W) and it will brown out under combined camera + screen + USB load.
- ⚠ CSI ribbon connectors are fragile — lift the latch gently, insert ribbon contacts-down, then close latch.
Optional — TCS34725 ambient colour/lux sensor
This sensor is Stage-future (KI-006) and can be omitted now. When adding: • VIN → Pi 5 3.3V (physical pin 1) • GND → Pi 5 GND (physical pin 6) • SDA → Pi 5 GPIO2 (physical pin 3, I2C1 SDA) • SCL → Pi 5 GPIO3 (physical pin 5, I2C1 SCL) No level shifting needed — Pi 5 I2C1 is native 3.3V and the TCS34725 breakout is 3.3V-native. I2C address: 0x29.
- Tip: After wiring, scan I2C with: sudo i2cdetect -y 1 — should show 0x29.
First power-on and validation sequence
Follow this order for first power-on: 1. Double-check all connections with the strip OFF — especially common ground star completeness, and that no 12V wires touch 5V branches. 2. Plug the switched power strip into mains. Turn ON the strip (booth master switch). 3. RM650e fan should spin; measure 12V and 5V at WAGO junction blocks with a multimeter before connecting any loads. 4. Connect ESP32-A only — verify WLED bench-sweep firmware dims the CCT strip smoothly and no LED on the WS2815 strip flickers without data. 5. Connect ESP32-B — verify it joins Wi-Fi and responds to TCP commands. 6. Connect Pi Zero 2 WH + bonnet + panels — verify marquee displays a test pattern (run matrix-test binary from rpi-rgb-led-matrix). 7. Connect Pi 5 — verify boot, CSI camera detection (libcamera-hello --list-cameras), touchscreen HDMI, and arcade button GPIO reads. 8. Final check: confirm 12V button LED branches are all lit.
- Tip: Measure current on each branch fuse before finalising — verify no branch is near its fuse rating at expected operating brightness.
- Tip: Keep a USB keyboard plugged into Pi 5 for the first boot in case of network/config issues.
- ⚠ Never connect any load to a rail you haven't verified with a multimeter first.
- ⚠ If any fuse blows on first power-on, find and fix the short before replacing the fuse.
Firmware
ESP32// Pixelbooth — wiring reference only.
// This project is designed in KiCad; no firmware is compiled here.
void setup() {}
void loop() {}“Deploy to device” opens this project in Schematik, where you can flash it to your board over USB.
Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.