feat(npc): push scene changes to voice gateway #30
@@ -22,6 +22,7 @@ idf_component_register(
|
||||
REQUIRES
|
||||
media_manager
|
||||
hints_client
|
||||
esp_http_client
|
||||
esp_timer
|
||||
esp_system
|
||||
nvs_flash
|
||||
|
||||
@@ -184,6 +184,12 @@ const npc_state_t *npc_engine_state(void);
|
||||
// Thin wrapper kept here to give callers a single npc_engine_* surface.
|
||||
esp_err_t npc_engine_set_group_profile(const char *profile);
|
||||
|
||||
// Point the engine at the voice gateway (tools/zacus-gateway). On each scene
|
||||
// change the engine POSTs the active SCENE_* to {base_url}/game/step?scene=… so
|
||||
// the phone NPCs disguise that scene's hint. Best-effort; pass NULL/"" to
|
||||
// disable. `token` is sent as a Bearer header (gateway require_token).
|
||||
void npc_engine_set_gateway(const char *base_url, const char *token);
|
||||
|
||||
// Write the active puzzle id (e.g. "SCENE_LA_DETECTOR") into `out`,
|
||||
// truncated to `cap` bytes (NUL-terminated). Falls back to "SCENE_NPC"
|
||||
// when no scene is active or the engine is not initialised so callers
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "media_manager.h"
|
||||
@@ -27,6 +28,46 @@
|
||||
|
||||
static const char *TAG = "npc_engine";
|
||||
|
||||
// Voice gateway (tools/zacus-gateway) — we push the active SCENE_* to it at each
|
||||
// scene change so the phone NPCs disguise THIS scene's hint. Best-effort, set by
|
||||
// npc_engine_set_gateway(); empty = disabled (no-op, e.g. CI / dry runs).
|
||||
static char s_gw_url[128] = {0};
|
||||
static char s_gw_token[80] = {0};
|
||||
|
||||
void npc_engine_set_gateway(const char *base_url, const char *token) {
|
||||
if (base_url) snprintf(s_gw_url, sizeof(s_gw_url), "%s", base_url);
|
||||
if (token) snprintf(s_gw_token, sizeof(s_gw_token), "%s", token);
|
||||
}
|
||||
|
||||
// Fire a one-shot POST {gateway}/game/step?scene=<scene>. Short timeout,
|
||||
// best-effort: the puzzle progresses fine without it, it only keeps the phone
|
||||
// NPCs' hints in sync with the current scene. Never propagates failure.
|
||||
static void notify_gateway_scene(const char *scene) {
|
||||
if (!s_gw_url[0] || !scene || !scene[0]) return;
|
||||
char url[256];
|
||||
snprintf(url, sizeof(url), "%s/game/step?scene=%s", s_gw_url, scene);
|
||||
esp_http_client_config_t cfg = {
|
||||
.url = url,
|
||||
.method = HTTP_METHOD_POST,
|
||||
.timeout_ms = 2000,
|
||||
};
|
||||
esp_http_client_handle_t cli = esp_http_client_init(&cfg);
|
||||
if (!cli) return;
|
||||
if (s_gw_token[0]) {
|
||||
char auth[112];
|
||||
snprintf(auth, sizeof(auth), "Bearer %s", s_gw_token);
|
||||
esp_http_client_set_header(cli, "Authorization", auth);
|
||||
}
|
||||
esp_err_t err = esp_http_client_perform(cli);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "gateway /game/step notify failed: %s", esp_err_to_name(err));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "gateway scene -> %s (HTTP %d)", scene,
|
||||
esp_http_client_get_status_code(cli));
|
||||
}
|
||||
esp_http_client_cleanup(cli);
|
||||
}
|
||||
|
||||
// ─── Core: scene/trigger/mood lookup tables (verbatim Arduino) ──────────────
|
||||
|
||||
static const char *const kSceneIds[] = {
|
||||
@@ -372,6 +413,8 @@ esp_err_t npc_engine_set_step(uint8_t step_id, uint32_t expected_duration_ms) {
|
||||
(unsigned) prev_scene, (unsigned) step_id);
|
||||
}
|
||||
(void) hints_client_puzzle_start(puzzle_id);
|
||||
// Keep the voice gateway in sync so the phone NPCs hint on THIS scene.
|
||||
notify_gateway_scene(puzzle_id);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,12 @@
|
||||
// this to NVS so the field operator can repoint the firmware without a flash.
|
||||
#define ZACUS_HINTS_BASE_URL "http://192.168.0.150:8302"
|
||||
|
||||
// Voice gateway (tools/zacus-gateway) — the engine POSTs each scene change to
|
||||
// {URL}/game/step?scene=SCENE_* so the phone NPCs disguise that scene's hint.
|
||||
// Hardcoded for now like the URLs above — moves to NVS in the same follow-up.
|
||||
#define ZACUS_GATEWAY_BASE_URL "http://192.168.0.175:8401"
|
||||
#define ZACUS_GATEWAY_TOKEN "testtoken"
|
||||
|
||||
// Slice 7: voice-bridge WebSocket on the MacStudio (Tailscale address).
|
||||
// Hardcoded here for the same reason as ZACUS_HINTS_BASE_URL — moves to
|
||||
// NVS in a follow-up slice. The bridge endpoint is documented in
|
||||
@@ -530,6 +536,9 @@ void app_main(void) {
|
||||
ESP_LOGE(TAG, "npc_engine_init failed: %s",
|
||||
esp_err_to_name(npc_err));
|
||||
}
|
||||
// Push each scene change to the voice gateway so the phone NPCs
|
||||
// disguise the CURRENT scene's hint (best-effort, see main.c URL).
|
||||
npc_engine_set_gateway(ZACUS_GATEWAY_BASE_URL, ZACUS_GATEWAY_TOKEN);
|
||||
|
||||
// Slice 5: bring up the hints HTTP client (so npc_engine can
|
||||
// route hint requests through the real backend) and the voice
|
||||
|
||||
Reference in New Issue
Block a user