Files
ledgrab/plans/game-integration/phase-4-css-stream.md
T
alexei.dolgolyov 492bdb95e3 feat: game integration system
Receive real-time events from games (CS2, Dota 2, LoL, etc.) and drive
LED effects through the existing color strip and value source pipelines.

Core:
- GameEventBus (thread-safe pub/sub) with standardized 23-type event vocabulary
- GameAdapter ABC + AdapterRegistry + MappingAdapter (YAML-driven)
- Built-in adapters: CS2 GSI, Dota 2 GSI, LoL Live Client, Generic Webhook
- Community YAML adapters: Minecraft, Valorant, Rocket League
- GameEventColorStripStream with 5 effects (flash/pulse/sweep/color_shift/breathing)
- GameEventValueSource with EMA smoothing and timeout
- 4 built-in effect presets (FPS Combat, MOBA Health, Racing, Generic Alert)
- Auto-setup for Valve GSI games (Steam path detection, cfg file writing)
- Demo capture engine exposed to non-demo mode

Frontend:
- Game tab in Streams tree navigation with integration cards
- Game integration editor modal with adapter picker, config fields, event mappings
- game_event source type in CSS and ValueSource editors
- Setup instructions overlay (markdown rendered)
- Live event monitor and connection test

API:
- Full CRUD for game integrations
- Event ingestion endpoint (adapter-level auth)
- Adapter metadata, presets, auto-setup, status/diagnostics endpoints
2026-03-31 13:17:52 +03:00

79 lines
5.1 KiB
Markdown

# Phase 4: GameEventColorStripStream
**Status:** ✅ Complete
**Parent plan:** [PLAN.md](./PLAN.md)
**Domain:** backend
## Objective
Create a new ColorStripSource/Stream type that renders LED effects in response to game events. Follows the NotificationColorStripStream pattern — event-driven with a 30 FPS render loop and double-buffered output.
## Tasks
- [x] Task 1: Create `GameEventColorStripSource` dataclass in `storage/color_strip_source.py`
- Fields: game_integration_id (str), idle_color (BindableColor), event_mappings (list of EventMapping dicts — override/supplement config-level mappings)
- source_type = "game_event"
- Implement to_dict/from_dict/create_from_kwargs/apply_update
- sharable = False (each target gets its own stream)
- [x] Task 2: Register "game_event" in `_SOURCE_TYPE_MAP` in color_strip_source.py
- [x] Task 3: Create `GameEventColorStripStream` (`core/processing/game_event_stream.py`)
- Constructor: parse event_mappings into lookup dict, subscribe to EventBus
- `_on_game_event(event)` — callback from EventBus, enqueue effect (thread-safe via deque)
- Effect types: flash, pulse, sweep, color_shift, breathing
- Priority-based layering — higher priority effects override lower (same as notification)
- 30 FPS background render thread with frame_time sleep
- Double-buffered output under threading.Lock
- Idle: output idle_color when no active effects
- `get_latest_colors()` → returns current rendered frame (np.ndarray)
- `start()` / `stop()` for lifecycle
- Cleanup: unsubscribe from EventBus on stop
- [x] Task 4: Register in `_SIMPLE_STREAM_MAP` in `color_strip_stream_manager.py`
- [x] Task 5: Wire EventBus injection — stream needs access to the singleton EventBus
- Added `game_event_bus` parameter to ColorStripStreamManager constructor
- Injection via `set_event_bus()` using same hasattr pattern as asset_store
- [x] Task 6: Write tests for GameEventColorStripSource (serialization, factory, update)
- [x] Task 7: Write tests for GameEventColorStripStream (event → effect rendering, priority, idle state, lifecycle)
## Files to Modify/Create
- `server/src/wled_controller/storage/color_strip_source.py` — add GameEventColorStripSource + register
- `server/src/wled_controller/core/processing/game_event_stream.py` — new stream class
- `server/src/wled_controller/core/processing/color_strip_stream_manager.py` — register in _SIMPLE_STREAM_MAP, inject EventBus
- `server/src/wled_controller/core/processing/processor_manager.py` — pass EventBus to stream manager (if needed)
- `server/tests/core/test_game_event_css.py` — source + stream tests
## Acceptance Criteria
- "game_event" source type serializes/deserializes correctly
- Stream subscribes to EventBus and renders effects when events arrive
- Multiple simultaneous effects layer by priority
- Idle state outputs the configured idle_color
- Stream cleans up subscriptions on stop
- All tests pass
## Notes
- Reuse effect rendering logic from NotificationColorStripStream where possible (flash, pulse, sweep are identical)
- Consider extracting shared effect rendering into a utility if duplication is significant
- The stream needs the EventBus singleton — simplest injection is via the stream manager's dependencies
- ⚠️ Big Bang: color_strip_source.py and stream_manager.py are shared files — coordinate with Phase 5 if running in parallel
## Review Checklist
- [x] All tasks completed
- [x] Code follows project conventions
- [x] No unintended side effects
- [x] Tests pass (28/28)
## Handoff to Next Phase
### What was built
- `GameEventColorStripSource` dataclass in `storage/color_strip_source.py` with full serialization, factory, and update support
- `GameEventColorStripStream` in `core/processing/game_event_stream.py` — event-driven stream with 5 effects (flash, pulse, sweep, color_shift, breathing), 30 FPS render loop, double-buffered output, priority-based effect layering
- EventBus injection via `game_event_bus` parameter on `ColorStripStreamManager` constructor + `set_event_bus()` method on the stream
### Integration points for later phases
- **Phase 7 (frontend)**: The `source_type = "game_event"` needs a UI editor. Fields: `game_integration_id` (EntitySelect), `idle_color` (BindableColor picker), `event_mappings` (list of EventMapping dicts with effect/color/duration/intensity/priority), `led_count`
- **Phase 8 (wiring)**: `processor_manager.py` needs to pass the `GameEventBus` singleton to `ColorStripStreamManager` via the new `game_event_bus=` constructor parameter. The bus is created in Phase 1's `init_dependencies()`.
### Files modified
- `server/src/wled_controller/storage/color_strip_source.py` — added `GameEventColorStripSource` class + registered in `_SOURCE_TYPE_MAP`
- `server/src/wled_controller/core/processing/game_event_stream.py` — new file
- `server/src/wled_controller/core/processing/color_strip_stream_manager.py` — added import, `_SIMPLE_STREAM_MAP` entry, `game_event_bus` constructor param, injection hook
- `server/tests/core/test_game_event_css.py` — 28 tests covering source serialization, stream lifecycle, rendering, effects, auto-size, and hot-update