No description
  • C++ 98.1%
  • Python 1%
  • CMake 0.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
seluba 2aba24095d
All checks were successful
CI / Host tests, coverage, static analysis (push) Successful in 1m23s
CI / Firmware build (push) Successful in 2m46s
Add link to blog and website.
2026-09-19 23:56:06 +02:00
.forgejo/workflows Initial commit 2026-08-27 17:13:30 +02:00
components Set version to 1.0.0 2026-08-30 14:00:53 +02:00
documentation Untrack AI agent configuration and unused sprite sources 2026-09-18 21:57:30 +02:00
licenses Initial commit 2026-08-27 17:13:30 +02:00
main change value screens to markers, renumber game modes 2026-08-30 10:20:22 +02:00
test Set version to 1.0.0 2026-08-30 14:00:53 +02:00
tools Initial commit 2026-08-27 17:13:30 +02:00
.clang-tidy Initial commit 2026-08-27 17:13:30 +02:00
.gitattributes Initial commit 2026-08-27 17:13:30 +02:00
.gitignore Untrack AI agent configuration and unused sprite sources 2026-09-18 21:57:30 +02:00
CMakeLists.txt Initial commit 2026-08-27 17:13:30 +02:00
dependencies.lock Initial commit 2026-08-27 17:13:30 +02:00
LICENSE Initial commit 2026-08-27 17:13:30 +02:00
partitions.csv Initial commit 2026-08-27 17:13:30 +02:00
README.md Add link to blog and website. 2026-09-19 23:56:06 +02:00
sdkconfig.defaults change config text appearance, only number bold 2026-08-30 10:20:27 +02:00
sdkconfig.defaults.debug Initial commit 2026-08-27 17:13:30 +02:00
THIRD-PARTY-NOTICES.md Initial commit 2026-08-27 17:13:30 +02:00
VERSION Set version to 1.0.0 2026-08-30 14:00:53 +02:00

Lumi

Lumi is a device for sport activities, workouts, and games. You can read more about it on on my blog.

It is free and open source under the MIT license. See LICENSE and THIRD-PARTY-NOTICES.md. The sourc code was mostly generated using Claude Code.

Status

Working firmware, tested on real hardware with three pods.

Software

  • Language: C++
  • Framework: ESP-IDF
  • OS: FreeRTOS
  • GUI: LVGL
  • Mesh technology: ESP-NOW

Hardware

The three buttons are capacitive. A capacitive button senses the touch of a finger and has no moving part.

Part GPIO Description Info
Wemos Lolin32 Lite None The microcontroller that runs the firmware. Link
Button center T3 (GPIO 15) The large button in the center.
Button left T8 (GPIO 33) The button on the left.
Button right T9 (GPIO 32) The button on the right.
Neopixel LED ring 13 A ring of 24 WS2812B RGB LEDs. The firmware sets the color of each LED.
OLED SSD1306 SDA 12, SCL 14 A display, 128 pixels wide and 32 pixels high. The I2C address is 0x3C. Link
TOF sensor VL53L0X SDA 12, SCL 14 A time-of-flight sensor. It measures the distance to your hand with light. The I2C address is 0x29. Link
Piezo buzzer 19 It makes the sounds.

Game modes

Mode What you do Pods
Reaction Time One pod lights up at a time. Touch it. You get your average time, your best time, and your worst time. 1+
Memory The pods show a pattern. The pattern gets longer in each round. Do the pattern again. 1+
Mine Sweeper If a pod is green, touch it quickly. If a pod is red, do not touch it, because it is a mine. Each wave is faster than the wave before. 1+
Interval The buzzer sends you to one pod after another. Move your hand above the pod, or touch it, before the time runs out. The time gets shorter. 1+
Reaction Multiplayer Each player has a color. Touch the pods that show your color and collect points. The first player with all points wins. 2+

Diagrams of each mode

How a game works

flowchart LR
    A[Pick a game<br/>on any pod] --> B[This pod becomes<br/>the coordinator]
    B --> C[It tells the other pods<br/>when to light up]
    C --> D[The players react]
    D --> E[All pods show<br/>the same result]

Repository layout

Path Contents
components/lumi_core Games, mesh protocol, settings, menu logic. No hardware calls, so the unit tests run on a PC.
components/lumi_hal Drivers: touch, LEDs, buzzer, display, distance sensor, storage, radio.
components/lumi_ui Screens and the app state machine.
main Firmware entry point.
test Unit tests that run on a PC.
documentation Requirements, game-mode diagrams, coding guidelines, CI setup.
tools Version-header generator and the coverage report.

Build and flash

You need ESP-IDF v6.0 and an ESP32 board.

idf.py set-target esp32
idf.py build
idf.py -p <PORT> flash

The release build writes no log output. To get log output on the serial port, build with the debug option:

idf.py fullclean
idf.py -DLUMI_DEBUG=ON build
idf.py -p <PORT> flash monitor

You must run idf.py fullclean first. ESP-IDF reads the sdkconfig.defaults files only when no sdkconfig file exists.

Run the tests

The game, mesh, and menu logic lives in components/lumi_core and has no hardware dependency, so it builds and runs on a normal PC.

cmake -S test -B test/build -G Ninja -DCMAKE_BUILD_TYPE=Debug
cmake --build test/build
./test/build/lumi_core_tests

Line coverage, with a GCC build:

CC=gcc CXX=g++ cmake -S test -B test/build-coverage -G Ninja \
  -DCMAKE_CXX_FLAGS="--coverage -O0" -DCMAKE_EXE_LINKER_FLAGS="--coverage"
cmake --build test/build-coverage
./test/build-coverage/lumi_core_tests
python3 tools/coverage_report.py test/build-coverage --min 80

Static analysis reads a compile_commands.json file. The build on the PC makes this file for lumi_core:

cmake -S test -B test/build -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
clang-tidy -p test/build components/lumi_core/src/*.cpp

For lumi_hal and lumi_ui, point clang-tidy at the ESP-IDF build directory instead.

Documentation