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:
@@ -57,7 +57,7 @@ from wled_controller.api.schemas.system import (
|
||||
VersionResponse,
|
||||
)
|
||||
from wled_controller.core.backup.auto_backup import AutoBackupEngine
|
||||
from wled_controller.config import get_config
|
||||
from wled_controller.config import get_config, is_demo_mode
|
||||
from wled_controller.core.capture.screen_capture import get_available_displays
|
||||
from wled_controller.utils import atomic_write_json, get_logger
|
||||
|
||||
@@ -119,6 +119,7 @@ async def health_check():
|
||||
status="healthy",
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
version=__version__,
|
||||
demo_mode=get_config().demo,
|
||||
)
|
||||
|
||||
|
||||
@@ -134,6 +135,7 @@ async def get_version():
|
||||
version=__version__,
|
||||
python_version=f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
|
||||
api_version="v1",
|
||||
demo_mode=get_config().demo,
|
||||
)
|
||||
|
||||
|
||||
@@ -176,11 +178,20 @@ async def get_displays(
|
||||
logger.info(f"Listing available displays (engine_type={engine_type})")
|
||||
|
||||
try:
|
||||
if engine_type:
|
||||
from wled_controller.core.capture_engines import EngineRegistry
|
||||
from wled_controller.core.capture_engines import EngineRegistry
|
||||
|
||||
if engine_type:
|
||||
engine_cls = EngineRegistry.get_engine(engine_type)
|
||||
display_dataclasses = await asyncio.to_thread(engine_cls.get_available_displays)
|
||||
elif is_demo_mode():
|
||||
# In demo mode, use the best available engine (demo engine at priority 1000)
|
||||
# instead of the mss-based real display detection
|
||||
best = EngineRegistry.get_best_available_engine()
|
||||
if best:
|
||||
engine_cls = EngineRegistry.get_engine(best)
|
||||
display_dataclasses = await asyncio.to_thread(engine_cls.get_available_displays)
|
||||
else:
|
||||
display_dataclasses = await asyncio.to_thread(get_available_displays)
|
||||
else:
|
||||
display_dataclasses = await asyncio.to_thread(get_available_displays)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user