Add demo mode: virtual hardware sandbox for testing without real devices
Demo mode provides a complete sandbox environment with: - Virtual capture engine (radial rainbow test pattern on 3 displays) - Virtual audio engine (synthetic music-like audio on 2 devices) - Virtual LED device provider (strip/60, matrix/256, ring/24 LEDs) - Isolated data directory (data/demo/) with auto-seeded sample entities - Dedicated config (config/demo_config.yaml) with pre-configured API key - Frontend indicator (DEMO badge + dismissible banner) - Engine filtering (only demo engines visible in demo mode) - Separate entry point: python -m wled_controller.demo (port 8081) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""Demo device provider — virtual LED devices for demo mode."""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import List
|
||||
|
||||
from wled_controller.config import is_demo_mode
|
||||
from wled_controller.core.devices.led_client import (
|
||||
DeviceHealth,
|
||||
DiscoveredDevice,
|
||||
LEDClient,
|
||||
LEDDeviceProvider,
|
||||
)
|
||||
from wled_controller.core.devices.mock_client import MockClient
|
||||
|
||||
# Pre-defined virtual devices: (name, led_count, ip, width, height)
|
||||
_DEMO_DEVICES = [
|
||||
("Demo LED Strip", 60, "demo-strip", None, None),
|
||||
("Demo LED Matrix", 256, "demo-matrix", 16, 16),
|
||||
("Demo LED Ring", 24, "demo-ring", None, None),
|
||||
]
|
||||
|
||||
|
||||
class DemoDeviceProvider(LEDDeviceProvider):
|
||||
"""Provider for virtual demo LED devices.
|
||||
|
||||
Exposes three discoverable virtual devices when demo mode is active.
|
||||
Uses MockClient for actual LED output (pixels are silently discarded).
|
||||
"""
|
||||
|
||||
@property
|
||||
def device_type(self) -> str:
|
||||
return "demo"
|
||||
|
||||
@property
|
||||
def capabilities(self) -> set:
|
||||
return {"manual_led_count", "power_control", "brightness_control", "static_color"}
|
||||
|
||||
def create_client(self, url: str, **kwargs) -> LEDClient:
|
||||
return MockClient(
|
||||
url,
|
||||
led_count=kwargs.get("led_count", 0),
|
||||
send_latency_ms=kwargs.get("send_latency_ms", 0),
|
||||
)
|
||||
|
||||
async def check_health(self, url: str, http_client, prev_health=None) -> DeviceHealth:
|
||||
# Simulate ~2ms latency for realistic appearance
|
||||
return DeviceHealth(
|
||||
online=True,
|
||||
latency_ms=2.0,
|
||||
last_checked=datetime.now(timezone.utc),
|
||||
device_name=url,
|
||||
device_version="demo",
|
||||
)
|
||||
|
||||
async def validate_device(self, url: str) -> dict:
|
||||
# Look up configured LED count from demo devices
|
||||
for name, led_count, ip, _w, _h in _DEMO_DEVICES:
|
||||
if url == f"demo://{ip}":
|
||||
return {"led_count": led_count}
|
||||
# Fallback for unknown demo URLs
|
||||
return {"led_count": 60}
|
||||
|
||||
async def discover(self, timeout: float = 3.0) -> List[DiscoveredDevice]:
|
||||
if not is_demo_mode():
|
||||
return []
|
||||
|
||||
return [
|
||||
DiscoveredDevice(
|
||||
name=name,
|
||||
url=f"demo://{ip}",
|
||||
device_type="demo",
|
||||
ip=ip,
|
||||
mac=f"DE:MO:00:00:00:{i:02X}",
|
||||
led_count=led_count,
|
||||
version="demo",
|
||||
)
|
||||
for i, (name, led_count, ip, _w, _h) in enumerate(_DEMO_DEVICES)
|
||||
]
|
||||
|
||||
async def get_power(self, url: str, **kwargs) -> bool:
|
||||
return True
|
||||
|
||||
async def set_power(self, url: str, on: bool, **kwargs) -> None:
|
||||
pass
|
||||
|
||||
async def get_brightness(self, url: str) -> int:
|
||||
return 255
|
||||
|
||||
async def set_brightness(self, url: str, brightness: int) -> None:
|
||||
pass
|
||||
|
||||
async def set_color(self, url: str, color, **kwargs) -> None:
|
||||
pass
|
||||
@@ -317,5 +317,8 @@ def _register_builtin_providers():
|
||||
from wled_controller.core.devices.gamesense_provider import GameSenseDeviceProvider
|
||||
register_provider(GameSenseDeviceProvider())
|
||||
|
||||
from wled_controller.core.devices.demo_provider import DemoDeviceProvider
|
||||
register_provider(DemoDeviceProvider())
|
||||
|
||||
|
||||
_register_builtin_providers()
|
||||
|
||||
Reference in New Issue
Block a user