

LED Coaster
Battery-powered RGB LED drink coaster: ESP32-C3 firmware, Android BLE app, KiCad PCB and 3D-printed enclosure
- Copper layers
- 2
- Thickness
- 1.6 mm
- Parts
- 84
- Nets
- 66
- Pads
- 351
- Tracks, vias
- 752, 72
- Pours
- 3
- Routed
- Yes
- KiCad
- KiCad 10.0 (file 20260206)
- Created
- 3 May 2024
- Updated
- 7 Nov 2026
Overview
LED Coaster is an open-source printed circuit board by Olivermoberg98, from the Olivermoberg98/LED-Coaster repository on GitHub, published under the MIT licence. It is a 2-layer board with 84 parts on 66 nets, routed with 752 tracks and 72 vias.
It is built around the ESP32-C3-WROOM-02-H4, MCP73871-2CCI/ML and TLV75533PDBV, with the TZ-5050S2RGB-5V-I4-H1, CC0603KRX7R9BB104 and CL21A475KAQNNNE among its other parts. Its parts include 31 diodes, 21 capacitors, 17 resistors, 3 ICs and 3 connectors. It belongs with the radio and wireless and power boards and the ESP32 and RISC-V boards of this library.
Main components
12ESP32-C3-WROOM-02-H4
SMD,20x18mm-105dBm -40℃~+105℃ 2.4GHz 20.5dBm 345mA 3V~3.6V 82mA Bluetooth5.0 ESP32-C3 On-board PCB Antenna UART、SPI、I2C、I2S、USB SMD,20x18mm WiFi Modules ROHSEspressif SystemsWiFi ModulesMCP73871-2CCI/ML
QFN-20(4x4)-40℃~+85℃ 1 1.1A 28uA 4.1V~6V 4.2V Charging IC Support Support QFN-20(4x4) Battery Management ROHSMicrochip TechnologyBattery ManagementTLV75533PDBV
SOT-23-5-40℃~+125℃@(Tj) 1 238mV@(500mA) 25uA 3.3V 46dB@(100kHz) 5.5V 500mA 71.5uVrms Fixed Over Current Protection、Thermal Shutdown、Input undervoltage protection Positive SOT-23-5 Voltage Regulators - Linear, Low Drop Out (LDO) Regulators ROHSTexas InstrumentsVoltage Regulators - Linear, Low Drop Out (LDO) RegulatorsTZ-5050S2RGB-5V-I4-H1
SMD5050-4PRGB LEDs(Built-In IC)TUOZHANCC0603KRX7R9BB104
0603100nF 50V X7R ±10% 0603 Multilayer Ceramic Capacitors MLCC - SMD/SMT ROHSYAGEOMultilayer Ceramic Capacitors MLCC - SMD/SMTCL21A475KAQNNNE
080525V 4.7uF X5R ±10% 0805 Multilayer Ceramic Capacitors MLCC - SMD/SMT ROHSSamsung Electro-MechanicsMultilayer Ceramic Capacitors MLCC - SMD/SMT0805W8F1002
0805-55℃~+155℃ 10kΩ 125mW 150V Thick Film Resistor ±1% ±100ppm/℃ 0805 Chip Resistor - Surface Mount ROHSUNI-ROYALChip Resistor - Surface Mount0805W8F1001
0805-55℃~+155℃ 125mW 150V 1kΩ Thick Film Resistor ±1% ±100ppm/℃ 0805 Chip Resistor - Surface Mount ROHSUNI-ROYALChip Resistor - Surface MountCL21B104KCFNNNE
0805100V 100nF X7R ±10% 0805 Multilayer Ceramic Capacitors MLCC - SMD/SMT ROHSSamsung Electro-MechanicsMultilayer Ceramic Capacitors MLCC - SMD/SMT0805W8F1003
0805-55℃~+155℃ 100kΩ 125mW 150V Thick Film Resistor ±1% ±100ppm/℃ 0805 Chip Resistor - Surface Mount ROHSUNI-ROYALChip Resistor - Surface Mount0805W8F220J
0805-55℃~+155℃ 125mW 150V 22Ω Thick Film Resistor ±1% ±100ppm/℃ 0805 Chip Resistor - Surface Mount ROHSUNI-ROYALChip Resistor - Surface Mount0805W8F4703
0805-55℃~+155℃ 125mW 150V 470kΩ Thick Film Resistor ±1% ±100ppm/℃ 0805 Chip Resistor - Surface Mount ROHSUNI-ROYALChip Resistor - Surface Mount
README
Hardware/PCB/README.mdPCB
KiCad 10 project for the coaster board: a 90 mm round, two-layer board with an ESP32-C3 module, a Li-Po charger with power path, and two rings of WS2812-compatible LEDs, 10 on the front and 20 on the back.
| File | What it is |
|---|---|
LED_Coaster.kicad_pro / .kicad_sch / .kicad_pcb | The project, schematic and board |
LED_Coaster.kicad_sym, Library.pretty/ | Project symbol and footprint libraries |
production/ | JLCPCB outputs from the Fabrication Toolkit plugin: gerber zip, BOM, placement, IPC netlist |
fabrication-toolkit-options.json | The plugin's settings; EXCLUDE DNP must stay true |
tools/pcb_check.py | Connectivity and stray-copper checker, see below |
The board
| Outline | 90 mm circle, centre at (150, 80) mm in board coordinates |
| Layers | 2, with a GND pour on both |
| Front | ESP32-C3-WROOM-02 U1, USB-C J3, charger U3, LDO U4, LED-rail switch Q1 and SW1, inner ring D21–D30 with C16–C19, battery-sense divider, charge LED D34 |
| Back | Outer ring D1–D20 with decoupling C8–C15, battery connector J1 |
Power path. USB-C 5 V feeds the MCP73871 charger U3, which powers the
system rail +SYS from USB or the cell and charges the cell at 500 mA.
SW1 drives the gate of the P-FET Q1, which switches +SYS onto
+LED_PWR for the LEDs. The 3.3 V LDO U4 takes its enable from
+LED_PWR, so switching SW1 off powers down the ESP32 as well. Charging
still works with SW1 off, because U3 sits upstream of the switch.
ESP32-C3 pins
| GPIO | Net | Use |
|---|---|---|
| IO0 | /small_ring | Inner ring data, D21 → D30 |
| IO1 | /large_ring | Outer ring data, D1 → D20 |
| IO4 | /BAT_SENSE | Cell voltage through a 470k/470k divider and 100 nF |
| IO5, IO6, IO10 | /STAT1, /STAT2, /PG | Charger status, open-drain, read with internal pull-ups |
| IO7 | D34 | Charge LED, through 1k to GND |
| IO18, IO19 | USB D−, D+ | Native USB: flashing and serial log over the USB-C port |
| IO20, IO21 | UART0 | J4 header, not fitted |
How U3 is strapped. USB-port mode (SEL low), 500 mA input limit
(PROG2 high), 500 mA charge current (R2 2k), 50 mA termination (R15
20k), thermistor disabled (R14 10k to GND), and safety timer disabled
(TE high). The input limit (450 mA typical) is what governs, so the cell
charges at about 420 mA once the ESP32 has its share. With the timer off, both
status outputs low can only mean a temperature fault. The firmware decodes the states per datasheet Table 5-1;
the root CLAUDE.md has the table.
Rules for changing the design
+SYSand+BATTmust never touch. Shorting them defeats the power path: the board appears to work but charges wrongly.- Nothing may pull
STAT1,STAT2orPGup to+5V. They go straight to ESP32 pins rated 3.6 V. The board's original status LEDs did exactly that and were removed for this reason.PGis pseudo open-drain with a diode path toIN, so with USB unplugged the ESP32 pull-up back-feeds about 58 µA into+5V. That is harmless. - The charger must be the
-2CCvariant (MCP73871-2CCI/ML, LCSCC5121473), which regulates to 4.20 V and has LBO at 3.1 V.C637761is the-4CAvariant: it charges to 4.40 V and would overcharge a standard Li-Po. - Keep total system load near 1 A or below. The charger's BAT→SYS path is
about 200 mΩ. All 30 LEDs at full white draw about 1.08 A, enough to sag
+SYSbelow the LDO's dropout on a part-discharged cell, so the firmware caps LED current. - Keep the thermal vias under
U3, and keep the pour reaching them. At about 420 mA into a low cell the charger dissipates up to about 0.8 W and gets hot. - Leave the netless zone on
B.Cuat x 185–197, y 68–89. It is the ESP32 antenna keep-out. - The battery-sense divider sits next to the ESP32, so the long trace is the
low-impedance
+BATTrather than the 235 kΩ divider node. C20is 22 µF. A bigger bulk capacitor does not help: droop on an LED step is set by the cell's resistance plus about 400 mΩ in the path, not by capacitance.
Manufacturing
The first batch (September 2026) was 5 boards from JLCPCB with Economic PCBA on the front side only: 20 BOM lines, 47 parts, about US$98 including shipping. The back side is hand-soldered.
LED part. The LEDs are TUOZHAN TZ-5050S2RGB-5V-I4-H1 (C26167850), a
WS2812B-compatible part. The BOM still calls them WS2812B. Every real WS2812B is
MSL 5a and rated for 240 °C peak, and JLCPCB refuses them for Economic
assembly, which reflows at 255 °C. Its part pages may list them as Economic, but
only the cart decides. The TZ part is MSL 3 and rated for 250 °C. It has the same
1 = VDD, 2 = DOUT, 3 = GND, 4 = DIN pinout, so it fits the footprint at 0°.
Do not substitute an SK6812 without a 180° rotation offset. Its pinout is 1 = GND, 2 = DIN, 3 = VDD, 4 = DOUT. At 0° the supply is reversed and every LED on the board is destroyed at power-up.
DNP. The only thing that keeps a part out of the BOM is (dnp yes) on the
schematic symbol. A part without an MPN is not dropped; it appears as a line
with an empty LCSC number, which JLCPCB cannot source. The back-side parts,
J1, J4, Btn1–Btn4 and the mounting holes are DNP. Set DNP in the
schematic, because Update PCB from Schematic overwrites a board-only change.
Regenerating production/. Run the Fabrication Toolkit plugin from the
board editor. Then check bom.csv: it should have 20 lines and 47 parts, the
LED line should have a quantity of 10 (30 means the DNP flags were lost),
and U1 should appear once. In JLCPCB's placement preview, check one LED per
ring. All 30 share one orientation, so if one is right they all are. If one is
wrong, correct it with an FT Rotation Offset field on the symbols rather than
editing the placement file.
DRC constraints used for JLCPCB's standard process: track and clearance
0.15 mm, via 0.6 mm / 0.3 mm drill, annular ring 0.13 mm, hole-to-hole 0.5 mm,
copper to edge 0.30 mm, and minimum through hole 0.20 mm. KiCad's
default copper-to-edge of 0.0 mm never fires, and 0.30 mm minimum through hole
flags the 0.20 mm and 0.25 mm thermal vias inside the U3 and U1 footprints.
Current DRC and ERC status. DRC has 0 errors, 0 unconnected items and 0 schematic-parity issues. It reports 95 warnings, all cosmetic or library-related: 62 silkscreen over copper, 14 silkscreen overlaps, 2 silkscreen at the board edge, 16 footprints that differ from the KiCad 10 library copies, and 1 missing library. ERC has 0 errors and 39 warnings, 35 of them off-grid wire ends in the LED-ring wiring. The missing library is the ESP32-C3-WROOM-02's. Its symbol and footprint are embedded in the schematic and board, so the design is complete, but they are not in the project libraries yet.
Hand-soldering
| Stage | Parts | What it adds |
|---|---|---|
| 1 | J1 | Battery, so charging, BLE and the inner ring work |
| 2 | D1–D20, C8–C15 (100 nF 0603) | The outer ring |
J1is a JST-EH 2.5 mm connector: pin 1 GND, pin 2+BATT. There is no reverse-polarity protection, so check a new battery lead with a meter first, and use a protected cell.- TZ-5050S2RGB limits from its datasheet: iron at ≤ 315 °C, under 3 s per
joint, once only, and the tip must not touch the lens. To make that
possible, the outer-ring LED and capacitor pads connect to the
GNDpour through thermal relief. Everywhere else the pour connects solid, for reflow. - The outer ring is one data chain,
D1→D20, fed from IO1 intoD1pin 4. A dead or badly soldered LED leaves everything after it dark. If the ring lights up toDn, look atDn's DOUT andDn+1. - The footprint is a hand-solder variant with extended, slightly asymmetric pads. Machine-placed LEDs sit about 0.14 mm off-centre, which is expected.
Btn1–Btn4are not fitted. The firmware reads none of them, andBtn3(boot) andBtn4(enable) are not needed for flashing over native USB. A replacement must match the land pattern: two 1.80 × 1.10 mm pads plus two mechanical pads in an 8.6 × 9.3 mm envelope.
Checking the board
tools/pcb_check.py reads the .kicad_pcb directly. It needs only the Python
standard library, no KiCad install. It answers what DRC does not: whether each
net is really one connected island, which pad is stranded, and whether stray
copper is left over. CI runs all on every push and fails on any problem.
cd Hardware/PCB/tools
python pcb_check.py all # nets + zones + shorts + strays
python pcb_check.py net "+LED_PWR" # one net: groups and every copper item
python pcb_check.py rings # LED chain continuity and ring uniformity
python pcb_check.py --help # every subcommandRefill the zones (B) and save before trusting any result, because the checker reads the stored fill. The header of the script lists the parsing traps it handles. The main one is that back-side pads are not mirrored in X.
Parts
84| Qty | Value | Footprint | References |
|---|---|---|---|
| 30 | WS2812B | Library:LED_WS2812_5050_handsolder | D1, D2, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23 +14 |
| 12 | 100nF | Capacitor_SMD:C_0603_1608Metric_Pad1.08x0.95mm_HandSolder | C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19 |
| 6 | 4.7uF | Capacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolder | C1, C3, C4, C5, C6, C7 |
| 4 | 10k | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R1, R3, R4, R14 |
| 3 | 1k | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R8, R9, R12 |
| 3 | MountingHole | MountingHole:MountingHole_4.3mm_M4_Pad_Via | H1, H3, H4 |
| 2 | 0.1uF | Capacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolder | C2, C21 |
| 2 | 100k | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R13, R17 |
| 2 | 22 | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R10, R11 |
| 2 | 470k | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R18, R19 |
| 2 | 5.1K | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R6, R7 |
| 2 | button | Button_Switch_SMD:SW_SPST_SKQG_WithStem | Btn1, Btn2 |
| 1 | 20k | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R15 |
| 1 | 22uF | Capacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolder | C20 |
| 1 | 2k | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R2 |
| 1 | AO3401A | Package_TO_SOT_SMD:SOT-23 | Q1 |
| 1 | Boot | Button_Switch_SMD:SW_SPST_SKQG_WithStem | Btn3 |
| 1 | ESP32-C3-WROOM-02-H4 | ESP32-C3-WROOM-02-H4:MODULE_ESP32-C3-WROOM-02-H4 | U1 |
| 1 | Enable | Button_Switch_SMD:SW_SPST_SKQG_WithStem | Btn4 |
| 1 | LED | LED_SMD:LED_0805_2012Metric_Pad1.15x1.40mm_HandSolder | D34 |
| 1 | Li-po | Connector_JST:JST_EH_S2B-EH_1x02_P2.50mm_Horizontal | J1 |
| 1 | MCP73871-2CC | Package_DFN_QFN:QFN-20-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias | U3 |
| 1 | SW_SPDT | Button_Switch_SMD:SW_SPDT_CK_JS102011SAQN | SW1 |
| 1 | TLV75533PDBVR | Package_TO_SOT_SMD:SOT-23-5 | U4 |
| 1 | UART | Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical | J4 |
| 1 | USB_C_Receptacle_USB2.0_16P | Connector_USB:USB_C_Receptacle_HRO_TYPE-C-31-M-12 | J3 |
Similar boards
- 2 layers62 × 47 mm

- 2 layers23 × 30.5 mm

- 2 layers20 × 160 mm

Zibs Saber v2
PedroBMedeiros/PolySaber
Firmware for Cal Poly Senior Project - PolySaber a Custom PCB Soundboard
75 parts - 2 layers65.4 × 133.6 mm

BSidesTLV2025GloveBadge
bsidestlv/bsidestlv-2025-badge
To solve the challenge you will need to discover a series of flags, hidden inside the badge. Each one will help you unlock the next step in the challenge, to finally reveal the ultimate secret the badge holds.
35 parts13MIT - 4 layers52 × 52 mm

Moto gps rev a1
mx3353672833-debug/moto-gps-waveshare
MOTO GPS · Waveshare ESP32-S3 1.75C 圆屏导航 + iPhone App | Author: Maler X | Noncommercial, attribution required | Experimental
112 parts529 - 2 layers95 × 54 mm

EinkPDA screen
TalismanDesign/PocketMage_PDA
An E-Ink PDA device using the ESP32 S3.
28 parts2kApache-2.0 - 2 layers60 × 50 mm

Hackeriot board 2024
bmeisels/hackeriot_board
Hackeriot Board is a research target for learning about Hardware Reverse Engineering. The board was used as part of the Hardware Reverse Engineering workshop at the 2024 conference.
39 parts1 - 4 layers52 × 94.2 mm

Tangara mainboard
dpaola2/Harmony
Current logistics, September 26: core modules are received, and the revision B shells, LCD supports and carrier gauge passed loose fit checks. Screws and foam are ordered. The SD trial playlist is prepared.
124 parts
Questions
What parts does the LED Coaster use?
84 parts, built around the ESP32-C3-WROOM-02-H4, MCP73871-2CCI/ML, TLV75533PDBV and TZ-5050S2RGB-5V-I4-H1. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.
Where can I download the LED Coaster KiCad files?
From the Olivermoberg98/LED-Coaster repository on GitHub, at the commit this page was made from: the board is Hardware/PCB/LED_Coaster.kicad_pcb and its schematic Hardware/PCB/LED_Coaster.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Can I use the LED Coaster design in my own project?
Its repository publishes it under the MIT licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).