feat: HA light target live color preview — per-entity swatches via WebSocket
Lint & Test / test (push) Successful in 1m24s
Lint & Test / test (push) Successful in 1m24s
- Cache per-entity colors in HALightTargetProcessor._update_lights()
- Broadcast colors_update to WS clients at target's update_rate
- WS endpoint: /api/v1/output-targets/{target_id}/ha-light/ws
- Frontend: connect WS when target runs, update swatch colors live
- Card shows colored boxes per mapped entity with entity name labels
This commit is contained in:
@@ -18,42 +18,6 @@ class KeyColorRectangleSchema(BaseModel):
|
||||
height: float = Field(default=1.0, description="Height (0.0-1.0)", gt=0.0, le=1.0)
|
||||
|
||||
|
||||
class KeyColorsSettingsSchema(BaseModel):
|
||||
"""Settings for key colors extraction."""
|
||||
|
||||
fps: int = Field(default=10, description="Extraction rate (1-60)", ge=1, le=60)
|
||||
interpolation_mode: str = Field(
|
||||
default="average", description="Color mode (average, median, dominant)"
|
||||
)
|
||||
smoothing: float = Field(
|
||||
default=0.3, description="Temporal smoothing (0.0-1.0)", ge=0.0, le=1.0
|
||||
)
|
||||
pattern_template_id: str = Field(
|
||||
default="", description="Pattern template ID for rectangle layout"
|
||||
)
|
||||
brightness: float = Field(
|
||||
default=1.0, description="Output brightness (0.0-1.0)", ge=0.0, le=1.0
|
||||
)
|
||||
brightness_value_source_id: str = Field(default="", description="Brightness value source ID")
|
||||
|
||||
|
||||
class ExtractedColorResponse(BaseModel):
|
||||
"""A single extracted color."""
|
||||
|
||||
r: int = Field(description="Red (0-255)")
|
||||
g: int = Field(description="Green (0-255)")
|
||||
b: int = Field(description="Blue (0-255)")
|
||||
hex: str = Field(description="Hex color (#rrggbb)")
|
||||
|
||||
|
||||
class KeyColorsResponse(BaseModel):
|
||||
"""Extracted key colors for a target."""
|
||||
|
||||
target_id: str = Field(description="Target ID")
|
||||
colors: Dict[str, ExtractedColorResponse] = Field(description="Rectangle name -> color")
|
||||
timestamp: Optional[datetime] = Field(None, description="Extraction timestamp")
|
||||
|
||||
|
||||
class HALightMappingSchema(BaseModel):
|
||||
"""Maps an LED range to one HA light entity."""
|
||||
|
||||
@@ -69,7 +33,7 @@ class OutputTargetCreate(BaseModel):
|
||||
"""Request to create an output target."""
|
||||
|
||||
name: str = Field(description="Target name", min_length=1, max_length=100)
|
||||
target_type: str = Field(default="led", description="Target type (led, key_colors, ha_light)")
|
||||
target_type: str = Field(default="led", description="Target type (led, ha_light)")
|
||||
# LED target fields
|
||||
device_id: str = Field(default="", description="LED device ID")
|
||||
color_strip_source_id: str = Field(default="", description="Color strip source ID")
|
||||
@@ -101,13 +65,6 @@ class OutputTargetCreate(BaseModel):
|
||||
pattern="^(ddp|http)$",
|
||||
description="Send protocol: ddp (UDP) or http (JSON API)",
|
||||
)
|
||||
# KC target fields
|
||||
picture_source_id: str = Field(
|
||||
default="", description="Picture source ID (for key_colors targets)"
|
||||
)
|
||||
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(
|
||||
None, description="Key colors settings (for key_colors targets)"
|
||||
)
|
||||
# HA light target fields
|
||||
ha_source_id: str = Field(
|
||||
default="", description="Home Assistant source ID (for ha_light targets)"
|
||||
@@ -157,13 +114,6 @@ class OutputTargetUpdate(BaseModel):
|
||||
protocol: Optional[str] = Field(
|
||||
None, pattern="^(ddp|http)$", description="Send protocol: ddp (UDP) or http (JSON API)"
|
||||
)
|
||||
# KC target fields
|
||||
picture_source_id: Optional[str] = Field(
|
||||
None, description="Picture source ID (for key_colors targets)"
|
||||
)
|
||||
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(
|
||||
None, description="Key colors settings (for key_colors targets)"
|
||||
)
|
||||
# HA light target fields
|
||||
ha_source_id: Optional[str] = Field(
|
||||
None, description="Home Assistant source ID (for ha_light targets)"
|
||||
@@ -206,11 +156,6 @@ class OutputTargetResponse(BaseModel):
|
||||
default=False, description="Auto-reduce FPS when device is unresponsive"
|
||||
)
|
||||
protocol: str = Field(default="ddp", description="Send protocol (ddp or http)")
|
||||
# KC target fields
|
||||
picture_source_id: str = Field(default="", description="Picture source ID (key_colors)")
|
||||
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(
|
||||
None, description="Key colors settings"
|
||||
)
|
||||
# HA light target fields
|
||||
ha_source_id: str = Field(default="", description="Home Assistant source ID (ha_light)")
|
||||
ha_light_mappings: Optional[List[HALightMappingSchema]] = Field(
|
||||
@@ -263,12 +208,6 @@ class TargetProcessingState(BaseModel):
|
||||
timing_audio_render_ms: Optional[float] = Field(
|
||||
None, description="Audio visualization render time (ms)"
|
||||
)
|
||||
timing_calc_colors_ms: Optional[float] = Field(
|
||||
None, description="Color calculation time (ms, KC targets)"
|
||||
)
|
||||
timing_broadcast_ms: Optional[float] = Field(
|
||||
None, description="WebSocket broadcast time (ms, KC targets)"
|
||||
)
|
||||
display_index: Optional[int] = Field(None, description="Current display index")
|
||||
overlay_active: bool = Field(
|
||||
default=False, description="Whether visualization overlay is active"
|
||||
@@ -328,25 +267,3 @@ class BulkTargetResponse(BaseModel):
|
||||
errors: Dict[str, str] = Field(
|
||||
default_factory=dict, description="Map of target ID to error message for failures"
|
||||
)
|
||||
|
||||
|
||||
class KCTestRectangleResponse(BaseModel):
|
||||
"""A rectangle with its extracted color from a KC test."""
|
||||
|
||||
name: str = Field(description="Rectangle name")
|
||||
x: float = Field(description="Left edge (0.0-1.0)")
|
||||
y: float = Field(description="Top edge (0.0-1.0)")
|
||||
width: float = Field(description="Width (0.0-1.0)")
|
||||
height: float = Field(description="Height (0.0-1.0)")
|
||||
color: ExtractedColorResponse = Field(description="Extracted color for this rectangle")
|
||||
|
||||
|
||||
class KCTestResponse(BaseModel):
|
||||
"""Response from testing a KC target."""
|
||||
|
||||
image: str = Field(description="Base64 data URI of the captured frame")
|
||||
rectangles: List[KCTestRectangleResponse] = Field(
|
||||
description="Rectangles with extracted colors"
|
||||
)
|
||||
interpolation_mode: str = Field(description="Color extraction mode used")
|
||||
pattern_template_name: str = Field(description="Pattern template name")
|
||||
|
||||
Reference in New Issue
Block a user