← Back to blog
Story

Starting from a blank page

Leaving the Raspberry Pi for an ESP32, rewriting the whole codebase in C++, redesigning the case to make it simpler. The prototype changes its foundations.

In the previous article, I introduced the Raspberry Pi version of the project: a complete, working, open source system. And I ended by saying it was time to turn the page. So here's the beginning of what comes next.

Why leave the Raspberry Pi

In everyday use, the Raspberry Pi has its limits. It's expensive, it draws a lot of power, it boots slowly, and it runs a full operating system for what is, at heart, an audio player controlled by NFC. That's too much, for what it actually does.

After some research and valuable advice, I finally convinced myself to put the Raspberry Pi version on pause and focus on building the ESP32 version. Simpler, much cheaper, very low power, and above all, full control over what runs. No OS, no updates that break drivers, no useless layers of abstraction. Just the application, directly on the microcontroller.

It wasn't an easy choice. I'd been working on the Python version for a while and I was busy fixing bugs, except this part was starting to drag on, while in parallel I was realizing the ESP32 was more interesting for what's ahead. I was looking for the middle ground between finishing what I'd started and abandoning a project in progress.

The choice made itself.

Rewriting the entire codebase

The problem is that you don't port Python to an ESP32. I had to start over in C++. And I didn't know the language.

Python
print("Hello, World!")
C++
#include <iostream>

int main() {
  std::cout << "Hello, World!\n";
  return 0;
}
Comparing Python and C++ to print a Hello World

It was a huge challenge. C++ has nothing in common with what I was doing before: manual memory management, compilation, resource constraints, no garbage collector. A different way of thinking.

As with the initial proof of concept, generative AI helped me a lot. To get started, to understand the patterns, to spot what I was doing wrong. But this time, the conceptual leap was bigger: I had to actually learn the language, not just transpose my iOS developer reflexes.

But after a few months of grinding, I have something functional. The system works, reads the cards, plays music, manages playlists. The skeleton stands, and it stands on a microcontroller worth a few euros.

Finding the right board

I started with an Arduino Nano ESP32-S3. A small, clean board, perfect to get started. But everything else was missing: NFC reader, audio output, SD reader, power management. One external module per component, wires everywhere. Practical to begin with, but not usable as-is for my kids.

ESP32 breadboard with NFC reader, audio DAC, SD reader and power management wired as separate modules
ESP32 breadboard with NFC reader, audio DAC, SD reader and power management wired as separate modules

After looking around, I came across a board that brings together the basic components I needed to start the project: HermitX's NFC Reader, in its N8R8 version. ESP32-S3, integrated NFC reader, audio output, SD reader, but no battery management. A board designed for this kind of use, which saves me from rewiring everything at every iteration.

HermitX's NFC Reader board sitting next to the battery, speaker, potentiometers and buttons of the prototype
HermitX's NFC Reader board sitting next to the battery, speaker, potentiometers and buttons of the prototype

That's the board the current prototype runs on.

The case, simpler

While I was rewriting the firmware, I also went back to the case design. The v3 had a cubic structure, conceived as the frame of a 3D-printed cube with laser-cut MDF panels for the faces. Beautiful in the render, but heavy to print, and every failed print cost hours.

So I simplified everything. No more complex structure, no more panels to align to a tenth of a millimeter. A simple box, more compact, easier to print, that holds the board, the speaker, the battery, and that's it.

Fewer parts, less calibration, fewer chances to mess up.

The prototype in 3D, drag to rotate and explore it.

What's still on the to-do list

The big unsolved problem is still battery management. I'm still on the same LiPo Rider as on the v3, and it has the same flaw: when you unplug USB, the switch to battery causes a brief power dip that restarts the board.

The good news is that the ESP32 boots in ten seconds. Versus one to two minutes on the Raspberry Pi. It's not perfect, but it's not even close. In daily use, it changes everything: you unplug, it reboots, and it's almost transparent.

What I take away from this

Starting from a blank page is scary in the moment. You leave behind code that worked, a case that ran every day at home, months of tinkering. But it was the right call.

The project is more aligned with what it should be: a simple, frugal object that does one thing and does it well. And the strong constraints of the microcontroller, paradoxically, force me to write cleaner code than I was on the Raspberry Pi. And the best part: you can finally take it with you, because it's much lighter and it lasts more than five hours on battery.

A child places a card on the box, the music starts on its own

What's next is stabilizing the firmware, sorting out the power question, and seriously thinking about what will turn this prototype into something other people can build. More on that in the next article.

Newsletter

Stay informed

Leave your email to follow the project's progress and not miss the launch.