# Phase 5: GameEventValueSource **Status:** ✅ Complete **Parent plan:** [PLAN.md](./PLAN.md) **Domain:** backend ## Objective Create a new ValueSource type that exposes game metrics (health, ammo, mana, etc.) as 0.0-1.0 scalar values. These can be bound to any existing effect parameter (brightness, speed, color position) via the BindableFloat/BindableColor system. ## Tasks - [x] Task 1: Create `GameEventValueSource` dataclass in `storage/value_source.py` - Fields: game_integration_id (str), event_type (str — from standard vocabulary), min_game_value (float, default 0.0), max_game_value (float, default 100.0), smoothing (float, 0.0-1.0, EMA alpha), default_value (float, 0.5), timeout (float, seconds before reverting to default) - source_type = "game_event" - Implement to_dict/from_dict - [x] Task 2: Register "game_event" in `_VALUE_SOURCE_MAP` in value_source.py - [x] Task 3: Create `GameEventValueStream` runtime resolver (`core/value_sources/game_event_value_source.py`) - Subscribe to EventBus for the configured event_type - Normalize incoming value using min/max mapping → 0.0-1.0 - Apply EMA smoothing if configured - Track last_event_time for timeout detection - `get_value()` → returns current normalized value (or default if timed out) - `get_color()` → returns None (game event value source only provides scalars) - Thread-safe (EventBus callback + get_value from render thread) - Cleanup: unsubscribe from EventBus on release - [x] Task 4: Register in value source manager / factory - Add case for "game_event" source_type in the value stream creation logic - Inject EventBus reference - [x] Task 5: Write tests for GameEventValueSource (serialization, from_dict, defaults) - [x] Task 6: Write tests for GameEventValueStream (normalization, smoothing, timeout, thread safety) ## Files to Modify/Create - `server/src/wled_controller/storage/value_source.py` — add GameEventValueSource + register - `server/src/wled_controller/core/value_sources/game_event_value_source.py` — runtime resolver - `server/src/wled_controller/core/processing/value_stream.py` — register factory case + event_bus param - `server/tests/core/test_game_event_value_source.py` — tests ## Acceptance Criteria - "game_event" value source type serializes/deserializes correctly - Runtime resolver normalizes game values to 0.0-1.0 using min/max - EMA smoothing works correctly (smooth transitions, not jumpy) - Timeout reverts to default_value when no events received - Can be bound to BindableFloat properties on any ColorStripSource - All tests pass ## Notes - EMA formula: `smoothed = alpha * new_value + (1 - alpha) * smoothed` where alpha = 1 - smoothing - Timeout uses monotonic clock — compare current time vs last_event_time - Best suited for continuous event types (health, mana, ammo) — triggers (kill, death) are less useful here - ⚠️ Big Bang: value_source.py is a shared file — coordinate with Phase 4 if running in parallel ## Review Checklist - [x] All tasks completed - [x] Code follows project conventions - [x] No unintended side effects - [x] Tests pass (24/24) ## Handoff to Next Phase ### What was implemented - **GameEventValueSource** dataclass in `storage/value_source.py` with all required fields (game_integration_id, event_type, min/max mapping, smoothing, default_value, timeout) - **GameEventValueStream** in new module `core/value_sources/game_event_value_source.py` — subscribes to GameEventBus, normalizes values, applies EMA smoothing, handles timeout with monotonic clock, thread-safe via threading.Lock - **ValueStreamManager** updated with `event_bus` parameter and factory case for `GameEventValueSource` in `core/processing/value_stream.py` - **24 tests** covering serialization, normalization (7 cases), smoothing (3 cases), timeout (4 cases), lifecycle (4 cases), thread safety, and hot-update ### Integration notes for downstream phases - `ValueStreamManager.__init__` now accepts an optional `event_bus: GameEventBus` parameter — Phase 8 (wiring) needs to pass the EventBus instance when constructing ValueStreamManager in `dependencies.py` - New module `core/value_sources/` created — contains `__init__.py` and `game_event_value_source.py` - No changes to API schemas or routes — Phase 7 (frontend) will need to add "game_event" to the value source editor UI