Someday: 11 ESP32 drivers for role-playing game devices

- Role
- Lead software developer: architecture and 11 driver libraries
- Team
- Own all the software in a team of three specialists: electronics, enclosures, software
- Timeline
- The library ecosystem was developed from October 2025 and released for the 2026 game
- Status
- Proven in real conditions at the 2026 game, under further development
What I did
- The someday-lib coreFreeRTOS tasks, thread-safe state, serializable game effects and RFID on RC522 for Mifare Classic and Ultralight cards.
- Module driversButtons, LEDs, an addressable LED strip, the battery, a display with Cyrillic, Wi-Fi, GPS, RFID on PN532 and a Serial console with commands.
- Library architectureShared modules versioned with git tags instead of copied code in every firmware. Arduino and PlatformIO were my choice as well.
- Rules for the AI assistantClaude Code helps me make sense of C++ and writes separate pieces. For it I made the someday-guard plugin with hooks and rules: a driver template is created quickly, and I review and finish it myself.
Context
The project
Someday is an indie project by the KB Someday team: electronics for story-driven field role-playing games. The audience is niche: mostly LARPers who play in the S.T.A.L.K.E.R. universe and similar post-apocalyptic settings. The project's first venue is a S.T.A.L.K.E.R. field role-playing game in the Urals.
The team has three people: I am responsible for all the software, the second member for the electronics (circuits, soldering, assembly), and the third for the enclosures. Device firmware is built from the libraries, and the devices themselves are used by players on the field.
Next, the team plans to enter the international market with projects in similar settings and to monetize the work by offering ready-made devices and firmware to other games.
Situation
At first every device was written from scratch, and code repeated from firmware to firmware: buttons, LEDs, RFID, communication. I moved the shared code into the someday-* libraries, and a new device started coming together from ready-made modules faster.
Field conditions
- POWERBattery power
The drivers are designed for battery operation: charge monitoring, PWM backlight control and sleeping modules when idle.
- OFFLINENo network dependency
Devices do not depend on the internet or the field infrastructure. They work on their own or exchange data directly: over Wi-Fi in access point mode, BLE and RFID cards.
- FIELDField conditions
Built for outdoor use and active handling by players: button debouncing, resilience to careless handling and fast recovery after a failure.
- BUDGETLimited budget
The architecture targets affordable components — ESP32 and budget modules — without losing reliability.
Goal
Make the role-playing game more varied with our own devices and build every new device from ready-made modules instead of writing it from scratch.
Process, architecture and decisions
Architecture
The libraries split into a core and module drivers. They all follow the same rules, so modules from different libraries live together in one firmware without extra work.
- COREThe someday-lib core
FreeRTOS tasks on CRTP, a value with a lifetime behind a mutex, serializable game effects: radiation and psi healing, a timer, death, revival and reset. RFID on RC522 with strategies for Mifare Classic and Ultralight.
Task<Derived>SingletonGuardedState<T>EffectData
- CONVENTIONSShared rules
Every module has its own namespace. Modules are guarded by mutexes and never block: process() is called from the loop or from a task. Built through library.json for PlatformIO, versions on git tags.
someday::<module>process()library.json
- DRIVERSModule drivers
Several buttons in one firmware, an LED, a WS2812B addressable strip with the pin as a template parameter, a battery with a mock mode, a thread-safe 128×64 display with Cyrillic and PWM backlight, Wi-Fi in access point and client modes, GPS, RFID on PN532, a Serial console with commands, BLE artifact types.
someday-buttonsomeday-diodsomeday-address-ledsomeday-accumulatorsomeday-displaysomeday-wifisomeday-gpsSomeday_RFIDSomeday_SerialCommandersomeday-types
What the devices are built from
The firmware of six game devices runs on the libraries: a dosimeter, a scanner, a geo-tagger, a PKS, a BLE artifact with a detector and a master device for RFID cards. Below is what each firmware pulls in.
- SOMEDAY-LIBCore
device-uyutdevice-scannerdevice-candlerfid-tool
- MODULESGPS, Wi-Fi, buttons, light, Serial console
device-uyutdevice-scannerdevice-candle
- DISPLAY · POWERDisplay and battery
device-uyutdevice-candle
- RFIDSomeday_RFID
device-uyutrfid-tool
- SOMEDAY-TYPESBLE artifact types
device-artefactdevice-otklick
Hardware and buses
- MCUESP32-S3 and ESP32-C3
Including ESP32-S3 N16R8 with PSRAM.
- RFIDRC522 and PN532
RC522 over SPI, PN532 over UART.
- GPSAT6558 / GP-02
UART at 9600 baud, NMEA and CASIC commands.
- DISPLAYJLX12864G-086
128×64 on the ST7567 controller, software SPI, PWM backlight.
- LIGHTWS2812B and LEDs
The addressable strip through FastLED, buttons through OneButton.
- POWERTwo 18650 batteries
Voltage is read through a divider on the ADC: 1250–2100 mV map to 0–100 %.
Why Arduino and PlatformIO
The project was my way into embedded; before that I worked on the web. Arduino and PlatformIO give a fast start and plenty of ready-made libraries: for an embedded newcomer it is the fastest path.
Along the way I learned C++ for microcontrollers, ESP32, FreeRTOS, buses and datasheets. Claude Code helped me make sense of C++.
Integrations
- MFRC522
- PN532 + NDEF
- TinyGPSPlus
- ArduinoJson
- FastLED
- U8g2
- OneButton
connected by me
Third-party libraries talk to the hardware directly, and someday-* wrap them into modules with shared rules.
Quality and releases
For someday-lib I wrote Unity unit tests, about 1800 lines, which run right on the device. MockGps and the battery mock mode help to debug without hardware.
Everything else was tested by hand, in three stages.
- 01BenchWe assemble the device and run scenarios through the SerialCommander Serial console and mocks
- 02Field testA check on location before the game
- 03GameThe final check at the 2026 game
The libraries are versioned with git tags: someday-gps v2.1.0, Someday_RFID v1.1.0, the rest v1.0.x. Devices pin a version by tag or commit, so a new library version does not change firmware that is already built.
Every library has a README in Russian, and RFID and SerialCommander also have one in English. The someday-gps README runs to 670 lines.
Challenges
One RFID bus for several tasks
- Problem
- Several FreeRTOS tasks worked with the PN532 reader over one UART, and the ACK responses got mixed up.
- Solution
- I put one mutex on the whole Someday_RFID driver. Player data is written to the card as an NDEF record through the templated write<T> and read<T>.
- Result
- We found the problem on the bench while debugging, before the game. At the game RFID worked reliably.
Type-safe writes to the card
- Problem
- Game data is written to the players' RFID cards, and the firmware must not write anything to a card that cannot be read back.
- Solution
- In someday-lib, readData<T> and writeData<T> accept only serializable POD types through SFINAE and static_assert. After a write the data is verified by reading it back.
- Result
- An unsuitable type will not compile: the error shows up at build time, not on the field.
Metrics and results
- 11someday-* driver libraries
- 6game device firmwares built on them
- 18–20 hof device runtime on two 18650s
- ~30players went through the location's quests
At the 2026 game the team played as the Clear Sky faction: a game-tech location with a set of devices built on these libraries, 2–3 units of each. A chain of quests led players through working with different devices, and players spoke well of both the location and the devices.
I came to embedded from the web and wrote driver libraries that devices ran on at a real game. Today I would study the theory more closely at the start and maybe pick C or Rust instead of Arduino: Arduino has a number of serious limitations when working with controllers, and rewriting a finished ecosystem is now expensive.
Preparing a similar project with game electronics? I will take on the device software as a whole
I will design the architecture, write the module drivers and C++ and FreeRTOS firmware, test it and take it through field trials: RFID, GPS, displays, light, Wi-Fi and BLE.