Files
ledgrab/plans/game-integration/phase-5-value-source.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

4.3 KiB

Phase 5: GameEventValueSource

Status: Complete Parent plan: 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

  • 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
  • Task 2: Register "game_event" in _VALUE_SOURCE_MAP in value_source.py
  • 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
  • Task 4: Register in value source manager / factory
    • Add case for "game_event" source_type in the value stream creation logic
    • Inject EventBus reference
  • Task 5: Write tests for GameEventValueSource (serialization, from_dict, defaults)
  • 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

  • All tasks completed
  • Code follows project conventions
  • No unintended side effects
  • 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