Add WLED health monitoring, calibration test mode, and UI improvements
Some checks failed
Validate / validate (push) Failing after 8s

- Add background health checks (GET /json/info) with configurable interval per device
- Auto-detect LED count from WLED device on add (remove led_count from create API)
- Add calibration test mode: toggle edges on/off with colored LEDs via PUT endpoint
- Show WLED firmware version badge and LED count badge on device cards
- Add modal dirty tracking with discard confirmation on close/backdrop click
- Fix layout jump when modals open by compensating for scrollbar width
- Add state_check_interval to settings API and UI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 23:44:29 +03:00
parent 579821a69b
commit d4261d76d8
10 changed files with 1047 additions and 315 deletions

View File

@@ -5,6 +5,8 @@ from typing import Dict, List, Literal, Optional
from pydantic import BaseModel, Field, HttpUrl
from wled_controller.core.processor_manager import DEFAULT_STATE_CHECK_INTERVAL
# Health and Version Schemas
@@ -53,7 +55,6 @@ class DeviceCreate(BaseModel):
name: str = Field(description="Device name", min_length=1, max_length=100)
url: str = Field(description="WLED device URL (e.g., http://192.168.1.100)")
led_count: int = Field(description="Total number of LEDs", gt=0, le=10000)
class DeviceUpdate(BaseModel):
@@ -61,7 +62,6 @@ class DeviceUpdate(BaseModel):
name: Optional[str] = Field(None, description="Device name", min_length=1, max_length=100)
url: Optional[str] = Field(None, description="WLED device URL")
led_count: Optional[int] = Field(None, description="Total number of LEDs", gt=0, le=10000)
enabled: Optional[bool] = Field(None, description="Whether device is enabled")
@@ -80,6 +80,10 @@ class ProcessingSettings(BaseModel):
fps: int = Field(default=30, description="Target frames per second", ge=1, le=60)
border_width: int = Field(default=10, description="Border width in pixels", ge=1, le=100)
brightness: float = Field(default=1.0, description="Global brightness (0.0-1.0)", ge=0.0, le=1.0)
state_check_interval: int = Field(
default=DEFAULT_STATE_CHECK_INTERVAL, ge=5, le=600,
description="Seconds between WLED health checks"
)
color_correction: Optional[ColorCorrection] = Field(
default_factory=ColorCorrection,
description="Color correction settings"
@@ -118,6 +122,25 @@ class Calibration(BaseModel):
)
class CalibrationTestModeRequest(BaseModel):
"""Request to set calibration test mode with multiple edges."""
edges: Dict[str, List[int]] = Field(
default_factory=dict,
description="Map of active edge names to RGB colors. "
"E.g. {'top': [255, 0, 0], 'left': [255, 255, 0]}. "
"Empty dict = exit test mode."
)
class CalibrationTestModeResponse(BaseModel):
"""Response for calibration test mode."""
test_mode: bool = Field(description="Whether test mode is active")
active_edges: List[str] = Field(default_factory=list, description="Currently lit edges")
device_id: str = Field(description="Device ID")
class DeviceResponse(BaseModel):
"""Device information response."""
@@ -154,6 +177,13 @@ class ProcessingState(BaseModel):
display_index: int = Field(description="Current display index")
last_update: Optional[datetime] = Field(None, description="Last successful update")
errors: List[str] = Field(default_factory=list, description="Recent errors")
wled_online: bool = Field(default=False, description="Whether WLED device is reachable")
wled_latency_ms: Optional[float] = Field(None, description="WLED health check latency in ms")
wled_name: Optional[str] = Field(None, description="WLED device name")
wled_version: Optional[str] = Field(None, description="WLED firmware version")
wled_led_count: Optional[int] = Field(None, description="LED count reported by WLED device")
wled_last_checked: Optional[datetime] = Field(None, description="Last health check time")
wled_error: Optional[str] = Field(None, description="Last health check error")
class MetricsResponse(BaseModel):