Add LED device abstraction layer for multi-controller support
Introduce abstract LEDClient base class with factory pattern so new LED controller types can plug in alongside WLED. ProcessorManager is now fully type-agnostic — all device-specific logic (health checks, state snapshot/restore, fast send) lives behind the LEDClient interface. - New led_client.py: LEDClient ABC, DeviceHealth, factory functions - WLEDClient inherits LEDClient, encapsulates WLED health checks and state management - device_type field on Device storage model (defaults to "wled") - Rename target_type "wled" → "led" with backward-compat migration - Frontend: "WLED" tab → "LED", device type badge, type selector in add-device modal, device type shown in target device dropdown - All wled_* API fields renamed to device_* for generic naming Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,10 +7,11 @@ from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class DeviceCreate(BaseModel):
|
||||
"""Request to create/attach a WLED device."""
|
||||
"""Request to create/attach an LED device."""
|
||||
|
||||
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)")
|
||||
url: str = Field(description="Device URL (e.g., http://192.168.1.100)")
|
||||
device_type: str = Field(default="wled", description="LED device type (e.g., wled)")
|
||||
|
||||
|
||||
class DeviceUpdate(BaseModel):
|
||||
@@ -53,6 +54,7 @@ class Calibration(BaseModel):
|
||||
# Skip LEDs at start/end of strip
|
||||
skip_leds_start: int = Field(default=0, ge=0, description="LEDs to skip (black out) at the start of the strip")
|
||||
skip_leds_end: int = Field(default=0, ge=0, description="LEDs to skip (black out) at the end of the strip")
|
||||
border_width: int = Field(default=10, ge=1, le=100, description="Border width in pixels for edge sampling")
|
||||
|
||||
|
||||
class CalibrationTestModeRequest(BaseModel):
|
||||
@@ -79,7 +81,8 @@ class DeviceResponse(BaseModel):
|
||||
|
||||
id: str = Field(description="Device ID")
|
||||
name: str = Field(description="Device name")
|
||||
url: str = Field(description="WLED device URL")
|
||||
url: str = Field(description="Device URL")
|
||||
device_type: str = Field(default="wled", description="LED device type")
|
||||
led_count: int = Field(description="Total number of LEDs")
|
||||
enabled: bool = Field(description="Whether device is enabled")
|
||||
calibration: Optional[Calibration] = Field(None, description="Calibration configuration")
|
||||
@@ -98,14 +101,15 @@ class DeviceStateResponse(BaseModel):
|
||||
"""Device health/connection state response."""
|
||||
|
||||
device_id: str = Field(description="Device ID")
|
||||
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_rgbw: Optional[bool] = Field(None, description="Whether WLED device uses RGBW LEDs")
|
||||
wled_led_type: Optional[str] = Field(None, description="LED chip type (e.g. WS2812B, SK6812 RGBW)")
|
||||
wled_last_checked: Optional[datetime] = Field(None, description="Last health check time")
|
||||
wled_error: Optional[str] = Field(None, description="Last health check error")
|
||||
device_type: str = Field(default="wled", description="LED device type")
|
||||
device_online: bool = Field(default=False, description="Whether device is reachable")
|
||||
device_latency_ms: Optional[float] = Field(None, description="Health check latency in ms")
|
||||
device_name: Optional[str] = Field(None, description="Device name reported by firmware")
|
||||
device_version: Optional[str] = Field(None, description="Firmware version")
|
||||
device_led_count: Optional[int] = Field(None, description="LED count reported by device")
|
||||
device_rgbw: Optional[bool] = Field(None, description="Whether device uses RGBW LEDs")
|
||||
device_led_type: Optional[str] = Field(None, description="LED chip type (e.g. WS2812B, SK6812 RGBW)")
|
||||
device_last_checked: Optional[datetime] = Field(None, description="Last health check time")
|
||||
device_error: Optional[str] = Field(None, description="Last health check error")
|
||||
test_mode: bool = Field(default=False, description="Whether calibration test mode is active")
|
||||
test_mode_edges: List[str] = Field(default_factory=list, description="Currently lit edges in test mode")
|
||||
|
||||
@@ -21,7 +21,6 @@ class ProcessingSettings(BaseModel):
|
||||
|
||||
display_index: int = Field(default=0, description="Display to capture", ge=0)
|
||||
fps: int = Field(default=30, description="Target frames per second", ge=10, le=90)
|
||||
border_width: int = Field(default=10, description="Border width in pixels", ge=1, le=100)
|
||||
interpolation_mode: str = Field(default="average", description="LED color interpolation mode (average, median, dominant)")
|
||||
brightness: float = Field(default=1.0, description="Global brightness (0.0-1.0)", ge=0.0, le=1.0)
|
||||
smoothing: float = Field(default=0.3, description="Temporal smoothing factor (0.0=none, 1.0=full)", ge=0.0, le=1.0)
|
||||
@@ -76,8 +75,8 @@ class PictureTargetCreate(BaseModel):
|
||||
"""Request to create a picture target."""
|
||||
|
||||
name: str = Field(description="Target name", min_length=1, max_length=100)
|
||||
target_type: str = Field(default="wled", description="Target type (wled, key_colors)")
|
||||
device_id: str = Field(default="", description="WLED device ID")
|
||||
target_type: str = Field(default="led", description="Target type (led, key_colors)")
|
||||
device_id: str = Field(default="", description="LED device ID")
|
||||
picture_source_id: str = Field(default="", description="Picture source ID")
|
||||
settings: Optional[ProcessingSettings] = Field(None, description="Processing settings (for wled targets)")
|
||||
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(None, description="Key colors settings (for key_colors targets)")
|
||||
@@ -132,15 +131,15 @@ class TargetProcessingState(BaseModel):
|
||||
display_index: int = Field(default=0, 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_rgbw: Optional[bool] = Field(None, description="Whether WLED device uses RGBW LEDs")
|
||||
wled_led_type: Optional[str] = Field(None, description="LED chip type (e.g. WS2812B, SK6812 RGBW)")
|
||||
wled_last_checked: Optional[datetime] = Field(None, description="Last health check time")
|
||||
wled_error: Optional[str] = Field(None, description="Last health check error")
|
||||
device_online: bool = Field(default=False, description="Whether device is reachable")
|
||||
device_latency_ms: Optional[float] = Field(None, description="Health check latency in ms")
|
||||
device_name: Optional[str] = Field(None, description="Device name reported by firmware")
|
||||
device_version: Optional[str] = Field(None, description="Firmware version")
|
||||
device_led_count: Optional[int] = Field(None, description="LED count reported by device")
|
||||
device_rgbw: Optional[bool] = Field(None, description="Whether device uses RGBW LEDs")
|
||||
device_led_type: Optional[str] = Field(None, description="LED chip type (e.g. WS2812B, SK6812 RGBW)")
|
||||
device_last_checked: Optional[datetime] = Field(None, description="Last health check time")
|
||||
device_error: Optional[str] = Field(None, description="Last health check error")
|
||||
|
||||
|
||||
class TargetMetricsResponse(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user