Files
clement 5519ed2f72
CI / platformio (pull_request) Failing after 9m57s
CI / platformio (push) Failing after 14m8s
feat(box3): touch gamebook (tap to choose)
Context:
The Freenove gamebook is screen+buttons, the PLIP is audio+dial. The
ESP32-S3-BOX-3 has a 320x240 touchscreen, so its natural format is a
tap-to-choose "livre dont tu es le heros": read the passage on screen,
tap a choice button to navigate.

Approach:
A new gamebook module reuses the same SD pack as the master (the JSON
passages already carry screen/text/choices[label,goto]) and builds the
UI on the already-running LVGL stack: a scrollable column with the
title, the wrapped passage text, and one tappable button per choice.

Changes:
- New gamebook.c/.h: mounts the SD (bsp_sdcard_mount), reads
  /sdcard/gamebook/{library.json, <id>.json}, shows a story list, then
  per passage renders title + text + choice buttons; tapping a choice
  goes to its target, an ending offers "back to menu". cJSON runs on
  PSRAM hooks (the expanded books are ~80 KB JSON); LVGL calls are
  wrapped in bsp_display_lock at init (button callbacks already run in
  the LVGL task).
- main.c: call gamebook_init() after the scenario server is up; it
  takes over the screen when a pack is on the SD, else no-op (the phone
  UI stays).
- CMakeLists: build gamebook.c.

Impact:
With a JSON pack on its SD, the BOX-3 is a touch gamebook: tap a story,
tap your choices. Text-only (no audio needed). Hardware-validated:
boots into a 6-story touch library.
2026-06-20 00:37:13 +02:00
..
2026-04-02 09:20:43 +02:00

Zacus BOX-3 Voice Pipeline

ESP-IDF firmware for ESP32-S3-BOX-3 — voice interface for Le Mystere du Professeur Zacus escape room.

Prerequisites

  • ESP-IDF v5.2+ (with ESP32-S3 support)
  • Python 3.8+ (for idf.py)

Build

# Set target
idf.py set-target esp32s3

# Configure (optional — defaults in sdkconfig.defaults)
idf.py menuconfig

# Build
idf.py build

# Flash (USB-C on BOX-3)
idf.py -p /dev/tty.usbmodem* flash monitor

Configuration

Use idf.py menuconfig > Zacus BOX-3 Voice Configuration:

Option Default Description
WiFi SSID zacus-net Network for voice bridge
WiFi Password (empty) WPA2 password
Voice Bridge URL ws://192.168.4.1:8080/ws/voice mascarade WebSocket
Wake Word hi esp WakeNet9 trigger phrase
Speaker Volume 70 0-100
Mic Gain 80 0-100

Hardware

  • Board: ESP32-S3-BOX-3 (16MB flash, 8MB PSRAM)
  • Codec: ES8311 (I2C addr 0x18)
  • Display: ILI9341 320x240
  • Mic: onboard MEMS
  • Speaker: onboard 1W with PA

Architecture

[Mic] -> I2S -> WakeNet -> Voice Capture -> WebSocket -> mascarade bridge
                                                              |
[Speaker] <- I2S <- TTS audio <------------- WebSocket -------+
                                                              |
                                              hints engine <--+

Générateur de stimulus (QR + mélodie)

En plus du pipeline vocal, la BOX-3 sert de source de stimulus pour le master Freenove. Elle affiche un QR code (lu par la caméra du master) et joue une mélodie (entendue par le micro du master). Cela permet de tester les énigmes locales P1 (son) et P3 (QR) du master de bout en bout, sans QR imprimé ni instrument de musique.

Les routes sont enregistrées sur le serveur HTTP existant (scenario_server) au démarrage, juste après l'init de l'écran et de l'UI (stimulus_init() puis stimulus_register_routes() dans app_main).

POST /stim/qr

{"text": "zacus-qr-1"}

Affiche le texte en QR plein écran : un widget lv_qrcode de 160 px sur une page LVGL dédiée, chargée au premier plan. Le rétroéclairage est atténué à 35 % pour réduire le halo de l'écran émissif et préserver le contraste pour la caméra du master.

curl -X POST http://192.168.1.50/stim/qr \
  -H 'Content-Type: application/json' \
  -d '{"text":"zacus-qr-1"}'
# {"status":"ok","text":"zacus-qr-1"}

POST /stim/melody

{"notes": [60, 62, 64, 65], "ms": 400}

Joue la séquence de notes MIDI au haut-parleur. notes est un tableau d'entiers 0-127 (60 = do central), ms est la durée par note en millisecondes, bornée à 1-4000 (défaut 400). La séquence est jouée sur une tâche worker dédiée, donc la réponse HTTP revient immédiatement. Maximum 32 notes ; les notes hors plage sont ignorées.

curl -X POST http://192.168.1.50/stim/melody \
  -H 'Content-Type: application/json' \
  -d '{"notes":[60,62,64,65,67],"ms":300}'
# {"status":"ok","notes":5}

Note de terrain

Le décodage par la caméra du master du QR affiché sur l'écran LCD n'est pas fiable : le contraste émissif est insuffisant pour quirc, qui ne retrouve pas les motifs de repérage (finder patterns) quelle que soit la résolution, même écran atténué. La mélodie est le chemin de stimulus le plus robuste. Pour P3, le QR imprimé reste recommandé ; le /stim/qr sert surtout au cadrage et au débogage de la caméra.

Configuration Wi-Fi

Le générateur est joignable sur l'IP de la BOX-3 en mode station. Configurez le réseau via idf.py menuconfig > Zacus BOX-3 Voice Configuration, ou directement par CONFIG_ZACUS_WIFI_SSID / CONFIG_ZACUS_WIFI_PASSWORD.