OR OPEN RADIO · CORE2
SHEET 1/1 · PRE-RELEASE ← CUBE PAGE PL
Polish radio stations, anywhere on Earth/M5Stack Core2/ playing on my desk

Polish radio that
just plays.

My family and friends abroad like having Polish radio on in the background. Until now that meant paid apps or pricey dedicated receivers, so I built a cube that plays nine Polish radio stations over Wi-Fi and Bluetooth. There's also a white, pink and brown noise generator: it soothes, calms, and needs no internet. The system image is free — you can build your own.

ASSEMBLY DRAWING OR-C2 LAB
54 mm 54 mm 16 mm USB-C 5 V ESP32 2 × 240 MHz 16 MB FLASH · 8 MB PSRAM SPEAKER 1 W WI-FI 2.4 GHz + BT CLASSIC OR-C2 · SCREENS: 1:1 EMULATOR
last capture: output BTstarvation 0watchdog 0queue full
A1
9
radio stations
A2
~€50
all the hardware, no soldering
A3
3
noise colors for winding down
A4
0
accounts · cloud · telemetry
A5
2.75B
AI tokens in production
A6
100+
engineering documents
THE CUBE, LIVE REC
plays on loopclick for cube audio
/ a new platform, on purpose

We know yoRadio. We're deliberately building something else.

yoRadio is a great DIY workhorse: you pick the display and the DAC, solder, compile in the Arduino IDE and play over a wire. Respect. We're building a new platform from scratch with a different philosophy: Bluetooth instead of wires, mobility, convenience and lightness.

  • Audio over Bluetooth with Wi-Fi active — coexistence on a single 2.4 GHz radio. A problem wired ESP32 radios never even touch; here it's the heart of the system.
  • Recovery as a contract — last-known-good, endpoint rotation, watchdogs, safe mode. The radio picks itself up before you reach for the cable.
  • Byte-reproducible builds with telemetry gates before release: starvation Δ0, injected silence 0.0 s — the numbers deliver the verdict.
  • A pixel-parity emulator in the browser — every preview pixel is drawn by the same C++ RGB565 renderer that runs on the device.
  • A local noise mode — wellness with no internet; a category classic internet radios simply don't have.
  • Two-click flashing from the browser — instead of Arduino IDE 1.8.19, a myoptions.h generator and swapping fonts inside libraries.

And if tinkering is your love language: yoRadio has 65,000 station slots, MQTT and Home Assistant — and it's great at that. We're building the radio for your mom. Or maybe a new habit for any age: a small cube that gives your day a backdrop — music or noise — so living and working simply feel better.

01 / what it does

Two modes: radio and noise

Polish stations by day. A noise generator that calms the house by night. One cube.

MODE-01RADIO

Nine Polish stations

News, music and Polish affairs over Wi-Fi — on your Bluetooth speaker or the built-in one. You switch it on and it plays; the cube worries about the rest.

MODE-02WELLNESS

Noise: white · pink · brown

One tap turns the radio into a calming machine: baby sleep, naps, meditation, deep-work focus. The noise is generated inside the cube, so it works with no internet at all — in a hotel, a car, a plane.

USE CASES baby sleepnapsmeditationdeep worknoise maskingwinding down
02 / what it's really for

Poland in your pocket, always

Millions of Poles live abroad. This cube costs about as much as two pizzas and gives you something no platform sells: Polish mornings, Polish news and Polish music in Dublin, Chicago or Oslo.

Independence

No one can switch it off

No subscriptions, no account, no terms of service that change tomorrow. There is no OTA and no cloud, so there is no button anyone could press to remotely silence your radio.

Always with you

54 mm in a suitcase

Hotel Wi-Fi is enough for the radio, and the noise plays with no network at all. Up to two hours on the built-in battery, any power bank after that.

One price

~€50 and no bills

The station streams are public and the noise is born inside the cube. There is nothing to pay monthly.

The cube is not a service. There is no server that can die and no company that can change its mind. It's yours — like a radio on a shelf, except it plays from the internet.

03 / scope

What this cube is, and what it deliberately isn't

Open Radio started from one premise: buy ready-made all-in-one hardware and write the entire system for it. We froze the feature set on purpose.

Is

  • A system for off-the-shelf hardware. M5Stack builds the hardware, we build the rest: firmware, GUI, recovery, station catalog. No soldering iron, no 3D printer.
  • A trade-off between cost and performance. ESP32 versus streaming in 2026. All the engineering in this project flows from that mismatch.
  • Portable and dead simple to use. Three taps along the bottom of the screen: previous station, grid, next. A device you understand in ten seconds — and it plays up to 2 h unplugged on its built-in battery.
  • As hands-off as possible. Network, stream, speaker, configuration: anything that can fail retries itself, no reboot and no phone required.
  • Deliberately narrow in scope. Every kilobyte of DRAM is accounted for, and Wi-Fi and Bluetooth fight over one radio. More features simply don't fit in this silicon.

Isn't

  • High-end audio. 128 kbps MP3 over SBC to a Bluetooth speaker or the built-in 1 W driver. For the kitchen, the workshop, the balcony — not for a listening room.
  • A platform for everything. Nine stations and a closed feature set. No Spotify, no podcasts, no alarm clock, no phone control.
  • A configuration monster. Settings fit on three screens. No hidden files, no expert mode.
  • A cloud product. The only outbound traffic is station streams and optional NTP. The radio doesn't know what you're listening to, and has no one to tell.

Nine of Poland's biggest broadcasters — from Antyradio's rock to the club mixes on RMF MAXX Club. The cube plays their official, public MP3 streams straight from the broadcaster: no retransmission, no recording, no middlemen. As far as the station can tell, it's just one more tick on the listener counter, only in a nicer box. The links go to the official sites.

04 / hardware

One box, off the shelf

MCUESP32-D0WDQ6-V3 · 2 Xtensa LX6 cores @ 240 MHz
Memory520 KB SRAM + 8 MB PSRAM · 16 MB flash
DisplayIPS 2.0″ · 320 × 240 · capacitive touch
AudioI2S NS4168 amplifier + 1 W speaker
RadioWi-Fi 2.4 GHz b/g/n + Bluetooth Classic · A2DP source (SBC)
PowerUSB-C · built-in 380 mAh battery — up to 2 h unplugged
Enclosure54 × 54 × 16 mm · stock, factory-made
Why M5Stack Core2

Because it's the only path to €50 without soldering. Screen, touch, speaker, battery, enclosure and both radios are all included — you pull it out of the box and flash it.

You pay for it in one currency: Wi-Fi and Bluetooth share a single 2.4 GHz radio and have to time-share it. Most of the entries in the log below trace straight back to that one purchasing decision.

The Core2 is one piece of a bigger M5Stack ecosystem: display-equipped Core cubes, smaller Atom and StickC units, and dozens of stackable modules — all built on ESP32, all with public documentation. We didn't add anything to this project: one cube, straight out of the box.

SHA-256: a07569…77b671 · license (GPL-3.0, no warranty) ·

05 / audio path

From the CDN to the speaker cone

SIGNAL FLOW OR-C2/A 44.1 kHz
STATIONCDN · MP3 128 kbps WI-FI / TCPneeds 16 KB/s MP3 DECODER8192 frames / pass PCM QUEUE≈ 6 s of headroom · 44.1 kHz BT A2DP · SBCreconnect 8–20 s BT SPEAKERyours, remembered SPEAKER 1 Wbuilt-in fallback BT failure → sound keeps playing locally
MP3 128 kbps needs 16 KB/sWi-Fi under active BT delivers 12–14 KB/sthat gap = the project's main antagonist → LOG-01
06 / build log

Nerd stuff: what actually happened

Selected entries from the engineering log. Every number comes from telemetry dumped off the device during multi-minute test runs.

LOG-01PHYSICS

One radio, two jobs

Wi-Fi and Bluetooth share one 2.4 GHz radio on the ESP32 and time-slice the same antenna. When A2DP is transmitting, the TCP window (~5.7 KB — an Arduino LWIP compile-time constant) multiplied by an RTT stretched to 350–500 ms gives you 12–14 KB/s. A 128 kbps MP3 stream needs 16. The deficit isn't a bug, it's arithmetic.

LOG-02GOTCHA

WiFi.setSleep(false)

Classic forum advice for speeding up Wi-Fi on the ESP32. With Bluetooth active, the controller hits abort() and the cube boot-loops every 26 seconds. Modem-sleep stays; the coex layer requires it.

LOG-03PHYSICS

Burst-equilibrium

The CDN hands over the first few seconds of a stream in a fast burst, then settles into exactly 1× realtime. Any buffer threshold set above the equilibrium point will never be reached — the radio waits forever to "finish buffering." Every reserve threshold had to come down below it.

LOG-04DISCOVERY

Decoder budget ≠ bandwidth

Tripling the decoder's work per loop pass didn't add a single audio frame (the deficit lives in the network), but it stretched the pass to 1.6 s and killed touch response. Under a network deficit, the decoder budget only governs UI responsiveness. We set it back to 8192 frames per pass.

LOG-05BUG

The rotation that didn't rotate

The stream's death paths never cleared the active endpoint, so "candidate rotation" had been reopening the same dead URL over and over. Symptom: 81 restarts in 3 minutes. The fix came down to clearing the endpoint in three places.

LOG-06RAM

TLS versus Bluetooth

A TLS handshake needs ~40 KB of free DRAM. With Bluetooth playing, only 25–30 KB is left, so switching to a station that needs HTTPS discovery mid-playback is physically impossible. The fix: pinned plain-HTTP fallbacks per station, plus a cache of the last source that worked.

LOG-07BT

The pairing window

After a power cycle, the speaker doesn't politely wait for a scan — it calls the cube itself. And the cube was rejecting strangers. A standoff. Fix: tapping "scan" opens a window where any matching incoming speaker gets adopted and remembered.

LOG-08RF

Too close to the router

Two meters from the access point, the audio drops out in waves; one room over, it plays flawlessly. The router's Wi-Fi transmitter is drowning out the cube's Bluetooth receiver. Sometimes the best firmware fix is moving the device three meters.

07 / hands-off

What happens when something breaks

The design rule: plug in + power = it plays. The radio has to survive every failure on its own, no phone and no human required.

Wi-Fi dropsretries known networks with bounded backoff; never joins an unknown or open network
server drops the stream2 s without a frame = instant reopen and candidate rotation (one server killed the TCP connection 65× in 12 minutes — it kept playing anyway)
BT speaker diesaudio falls back to the built-in speaker, reconnect retries in the background every 8–20 s
dead URL in the cataloglast-known-good: each station's last working source is remembered in flash
main loop hangswatchdog 30 s: diagnostic reset and an automatic return to playing instead of a brick
corrupted configsafe mode with local repair; a broken state never overwrites the last one that worked
0 accounts0 cloud0 telemetry0 recording0 auto-OTAonly traffic: station streams + optional NTP
08 / production

Built in a triangle: two AIs and a human

The system is built entirely by a pair of AI agents working on the same machine, cross-auditing each other's work. The human is left with the decisions and the ears.

Lead engineer

GPT-5.6 Sol · Codex

2.5 billion
tokens

Architecture, firmware, a pixel-parity GUI simulator (the browser draws the exact same RGB565 pixels as the device), bilingual documentation.

Stabilization and audit

Claude Fable 5 · Claude Code

250M
tokens

Crisis takeovers: audio path physics, rotation and TLS hotfixes, QC gates, cross-auditing the other engine's reports.

Project owner

Tomasz Fiedoruk

1 pair of ears
+ decisions and veto

Sets the product boundaries, listens to the results live, and stops any flash that hasn't passed the test protocol. The only part of the system that can hear.

Telemetry hands down the PASS/FAIL verdict. Every firmware candidate runs a multi-minute logged test: starvation Δ0 · watchdog Δ0 · injected silence 0.0 s / 300 s · queues full. Only then does the human listen.

The repo holds over 100 numbered engineering documents, each in Polish and English. Yes, for a radio.

09 / FAQ

Questions people actually asked

Some of them, anyway.

FAQ-01

Why these exact nine stations?

My wife likes seven of them. The other two added themselves by having a stable stream. Engineering can be simple. ;)

FAQ-02

Why does it play better one room away from the router?

Because the router shouts Wi-Fi straight into the cube's Bluetooth ear. We measured it. Three meters of distance beat many a firmware fix, see LOG-08.

FAQ-03

But phone apps exist.

They do, some of them paid. Except a phone rings, notifies, and leaves the kitchen with you. The cube stays and plays.

FAQ-04

What did it really cost?

About €50 in hardware. Plus 2.75 billion AI tokens that we are not converting to euros, because this was supposed to be a hobby.

10 / status and distribution

Firmware image first, source second

We flipped the usual release order on purpose: instead of dropping raw source first, we're shipping a ready-to-flash image first — one esptool command and the cube plays. The code goes up on GitHub once it's cleaned up, has survived long-run testing, and the licensing gates are closed.

Plays on the desk for days on end — lab build, 9/9 stations with logos, touch, favorites
10-minute continuous test passed — 0.0 s of injected silence, with 1 real source restart along the way
Two physical BT speakers confirmed — pairing, auto-reconnect after a restart, adopting incoming connections
Long-run qualification in progress — 60 min → 2 h → 8 h continuous-play thresholds before release
Image 0.1 available for download — full flash (byte-reproducible build), with noise mode: white / pink / brown
GitHub repo: coming soon — source once it's polished; until then available on request (license, §2)
+ / known issues and next versions
Touch and speed — we run at the hardware's limits: one 2.4 GHz radio and every kilobyte of RAM accounted for. Some things, like starting and controlling the noise generator, have noticeable latency today. Responsiveness = the 0.2 priority
Not everything works as it should yet — this is build 0.1, the odd hiccup happens. When something stops playing: unplug and replug the power, the cube picks itself back up
Easter eggs — one or two easter eggs are hiding in the system: features waiting for their official release. Finders keepers ;)

Declared licenses: GPL-3.0-or-later (code) · CC BY-SA 4.0 (documentation) · CC0 (station catalog) · no retransmission or recording of broadcasts · station logos only with broadcaster consent