The problem
No microphone, no voice assistant, no battery, no display. That sounds like less work, but it moves the whole problem onto four things: speech quality from a tiny driver, reliable streaming on a cheap radio module, a device that can be provisioned and updated safely at factory scale, and a bill of materials that stays under target at volume. The client fixed USB-C 5 V input, a pre certified module with onboard antenna, a mono Class-D amplifier, an LED ring, a single button, and signed OTA with per device identity.
What I did
Milestone one produced the architecture, six decision records the client signed off, a priced BOM, power and flash budgets, and a proof of concept that had to stream over HTTPS with real TLS for 30 minutes with heap logged every 30 seconds. It passed with zero underruns. Milestone two produced a round two layer board with single sided assembly: USB-C with fuse, TVS and CC pull downs, a synchronous buck, the ESP32-S3 module with strapping handled and the antenna zone clear, the I2S Class-D amplifier with its thermal pad in the pour, a level shifted addressable LED ring, one button and microSD on SPI. The first board came up cleanly.
The firmware splits into an audio pipeline with a 1 MB PSRAM ring buffer and an 8 second lead, a network task with reconnect and backoff, a player task with a command queue, and a UX layer mapping state to ring patterns. The audio chain has a fourth order 150 Hz high pass to protect the driver and a soft knee limiter above 70 percent so maximum volume compresses instead of clipping. The stream broke the first time it left the LAN. lwIP fails DNS instantly on a lease with no server list, so the station now falls back to the gateway and a public resolver. And the default 5.7 KB TCP window over a 290 ms round trip capped throughput at 17 KB/s when a 22 kHz WAV needs 44 KB/s.
A 64 KB window and deeper buffers took it to about 200 KB/s.
Decisions that shaped it
- Fixed milestones with acceptance tests the client runs without me.
- Decision records before code for the choices that needed sign off.
- A soak instrument inside the firmware, logging heap, largest free block, PSRAM and underruns every 30 seconds.
- Dual OTA partitions from the first build, so production updates need no repartition.
Result
Milestones 1 and 2 delivered. The custom board is built, brought up and streaming from a public host. Milestone 3 covers the decoder, scheduler, signed OTA and the enclosure.



