freenove: scope QR media flow to espnow and fix boot action asset

This commit is contained in:
Clément SAILLANT
2026-02-25 14:52:55 +01:00
parent 8cccd8c3a9
commit d4ccd49b3f
7 changed files with 76 additions and 10 deletions
+3 -1
View File
@@ -61,6 +61,7 @@ prompt_input:
- "SCENE_GOTO SCENE_LOCKED"
- "SCENE_GOTO SCENE_CAMERA_SCAN"
- "QR_SIM A_COMPLETER"
- "SC_EVENT espnow QR_OK"
- "BOOT_MODE_STATUS"
- "RESET"
@@ -148,13 +149,14 @@ current_firmware_snapshot:
- "ACTION_REFRESH_SD"
transitions:
- "serial:QR_OK->STEP_MEDIA_MANAGER"
- "espnow:QR_OK->STEP_MEDIA_MANAGER"
- step_id: "STEP_MEDIA_MANAGER"
screen_scene_id: "SCENE_MEDIA_MANAGER"
audio_pack_id: ""
actions:
- "ACTION_TRACE_STEP"
- "ACTION_SET_BOOT_MEDIA_MANAGER"
- "ACTION_SET_BOOT_MEDIA"
- "ACTION_HW_LED_READY"
mp3_gate_open: true
transitions: []
@@ -1,5 +1,5 @@
{
"id": "ACTION_SET_BOOT_MEDIA_MANAGER",
"id": "ACTION_SET_BOOT_MEDIA",
"type": "set_boot_mode",
"config": {
"mode": "media_manager",
@@ -33,7 +33,7 @@
"ACTION_QUEUE_SONAR",
"ACTION_REC_START",
"ACTION_REC_STOP",
"ACTION_SET_BOOT_MEDIA_MANAGER"
"ACTION_SET_BOOT_MEDIA"
],
"steps": [
{
@@ -83,13 +83,22 @@
],
"transitions": [
{
"id": "TR_STEP_DONE_MEDIA",
"id": "TR_STEP_DONE_MEDIA_SERIAL",
"trigger": "on_event",
"event_type": "serial",
"event_name": "QR_OK",
"target_step_id": "STEP_MEDIA_MANAGER",
"after_ms": 0,
"priority": 140
},
{
"id": "TR_STEP_DONE_MEDIA_ESPNOW",
"trigger": "on_event",
"event_type": "espnow",
"event_name": "QR_OK",
"target_step_id": "STEP_MEDIA_MANAGER",
"after_ms": 0,
"priority": 130
}
]
},
@@ -98,7 +107,7 @@
"screen_scene_id": "SCENE_MEDIA_MANAGER",
"action_ids": [
"ACTION_TRACE_STEP",
"ACTION_SET_BOOT_MEDIA_MANAGER",
"ACTION_SET_BOOT_MEDIA",
"ACTION_HW_LED_READY"
],
"mp3_gate_open": true
+19
View File
@@ -1,3 +1,22 @@
## [2026-02-25] Scope ESP-NOW + fix action boot media (LittleFS)
- Objectif:
- inclure ESP-NOW dans le passage vers `STEP_MEDIA_MANAGER`,
- corriger l'action de boot media qui provoquait un warning buildfs.
- Actions:
- action renommee `ACTION_SET_BOOT_MEDIA` (`data/story/actions/ACTION_SET_BOOT_MEDIA.json`) pour rester compatible LittleFS.
- references scenario mises a jour:
- `docs/protocols/story_specs/scenarios/default_unlock_win_etape2.yaml`
- `data/story/scenarios/DEFAULT.json`
- transition ESP-NOW ajoutee:
- `on_event espnow QR_OK -> STEP_MEDIA_MANAGER`.
- compat runtime conservee dans `main.cpp`:
- accepte `ACTION_SET_BOOT_MEDIA` + alias legacy `ACTION_SET_BOOT_MEDIA_MANAGER`.
- Gates:
- `pio run -e freenove_esp32s3`
- `pio run -e freenove_esp32s3_full_with_ui -t buildfs`
- warning `unable to open '/story/actions/ACTION_SET_BOOT_MEDIA_MANAGER.json.` disparu.
## [2026-02-25] Passes completes ChatGPT examples -> firmware (QR + media + gates)
- Skills utilises:
@@ -170,13 +170,19 @@ steps:
target_step_id: STEP_MEDIA_MANAGER
after_ms: 0
priority: 140
- trigger: on_event
event_type: espnow
event_name: QR_OK
target_step_id: STEP_MEDIA_MANAGER
after_ms: 0
priority: 130
- step_id: STEP_MEDIA_MANAGER
screen_scene_id: SCENE_MEDIA_MANAGER
audio_pack_id: ""
actions:
- ACTION_TRACE_STEP
- ACTION_SET_BOOT_MEDIA_MANAGER
- ACTION_SET_BOOT_MEDIA
- ACTION_HW_LED_READY
apps:
- APP_SCREEN
@@ -7,6 +7,7 @@ Verifier le flux QR final, la persistance NVS du boot mode `MEDIA_MANAGER`, et l
- `BOOT_MODE_STATUS` doit exposer un etat coherent (`mode`, `media_validated`).
- Le script force `SCENE_GOTO SCENE_CAMERA_SCAN` avant `QR_SIM <payload>` pour un test deterministe.
- `QR_SIM` doit produire une evidence `UI_EVENT` (`SERIAL:QR_OK` ou `QR_OK`) et/ou un routage `SCENE_MEDIA_MANAGER`.
- Scope ESP-NOW actif: `SC_EVENT espnow QR_OK` doit aussi permettre le passage `STEP_DONE -> STEP_MEDIA_MANAGER`.
- La persistence doit rester active apres `RESET` (retour `SCENE_MEDIA_MANAGER`).
- La verification post-reset repose sur `HW_STATUS scene=...` (pas de dependance `story.status`).
- Les scenes hub doivent etre atteignables: `SCENE_PHOTO_MANAGER`, `SCENE_MP3_PLAYER`, story (`SC_LOAD DEFAULT` + `SCENE_READY`).
@@ -555,6 +555,11 @@ bool parseEventType(const char* text, StoryEventType* out_type) {
*out_type = StoryEventType::kSerial;
return true;
}
if (std::strcmp(normalized, "espnow") == 0 || std::strcmp(normalized, "esp_now") == 0) {
// ESP-NOW events are bridged to story SERIAL:* tokens.
*out_type = StoryEventType::kSerial;
return true;
}
if (std::strcmp(normalized, "action") == 0) {
*out_type = StoryEventType::kAction;
return true;
@@ -673,6 +678,13 @@ bool normalizeEventTokenFromText(const char* raw_text, char* out_event, size_t o
snprintf(out_event, out_capacity, "SERIAL:%s", name[0] != '\0' ? name : "BTN_NEXT");
return true;
}
if (startsWithIgnoreCase(event, "ESPNOW ")) {
char* name = event + 7;
trimAsciiInPlace(name);
toUpperAsciiInPlace(name);
snprintf(out_event, out_capacity, "SERIAL:%s", name[0] != '\0' ? name : "BTN_NEXT");
return true;
}
if (startsWithIgnoreCase(event, "TIMER ")) {
char* name = event + 6;
trimAsciiInPlace(name);
@@ -2631,7 +2643,8 @@ bool executeStoryAction(const char* action_id, const ScenarioSnapshot& snapshot,
return g_media.stopRecording();
}
if (std::strcmp(action_id, "ACTION_SET_BOOT_MEDIA_MANAGER") == 0) {
if (std::strcmp(action_id, "ACTION_SET_BOOT_MEDIA") == 0 ||
std::strcmp(action_id, "ACTION_SET_BOOT_MEDIA_MANAGER") == 0) {
const bool mode_ok = g_boot_mode_store.saveMode(BootModeStore::StartupMode::kMediaManager);
const bool flag_ok = g_boot_mode_store.setMediaValidated(true);
applyStartupMode(BootModeStore::StartupMode::kMediaManager);
@@ -3852,8 +3865,24 @@ bool dispatchScenarioEventByType(StoryEventType type, const char* event_name, ui
return true;
case StoryEventType::kTimer:
return g_scenario.notifyTimerEvent(event_name, now_ms);
case StoryEventType::kSerial:
return g_scenario.notifySerialEvent(event_name, now_ms);
case StoryEventType::kSerial: {
const bool dispatched = g_scenario.notifySerialEvent(event_name, now_ms);
if (dispatched) {
return true;
}
if (event_name != nullptr && std::strcmp(event_name, "QR_OK") == 0) {
const ScenarioSnapshot snapshot = g_scenario.snapshot();
const bool boot_mode_ok = executeStoryAction("ACTION_SET_BOOT_MEDIA", snapshot, now_ms);
const bool goto_ok = g_scenario.gotoScene("SCENE_MEDIA_MANAGER", now_ms, "event_qr_ok_fallback");
if (boot_mode_ok || goto_ok) {
Serial.printf("[SC_EVENT] qr fallback mode_ok=%u goto_ok=%u\n",
boot_mode_ok ? 1U : 0U,
goto_ok ? 1U : 0U);
}
return boot_mode_ok || goto_ok;
}
return false;
}
case StoryEventType::kAction:
return g_scenario.notifyActionEvent(event_name, now_ms);
default:
@@ -5292,7 +5321,7 @@ void runRuntimeIteration(uint32_t now_ms) {
}
if (!dispatched && std::strcmp(runtime_event, "QR_OK") == 0) {
const ScenarioSnapshot snapshot = g_scenario.snapshot();
const bool boot_mode_ok = executeStoryAction("ACTION_SET_BOOT_MEDIA_MANAGER", snapshot, now_ms);
const bool boot_mode_ok = executeStoryAction("ACTION_SET_BOOT_MEDIA", snapshot, now_ms);
const bool goto_ok = g_scenario.gotoScene("SCENE_MEDIA_MANAGER", now_ms, "ui_qr_fallback");
dispatched = goto_ok;
if (boot_mode_ok || goto_ok) {