Reorganize the flat core/ directory (17 files) into three sub-packages: - core/devices/ — LED device communication (led_client, wled/adalight clients, providers, DDP) - core/processing/ — target processing pipeline (processor_manager, target processors, live streams, settings) - core/capture/ — screen capture & calibration (screen_capture, calibration, pixel_processor, overlay) Also split the monolithic filters/builtin.py (460 lines, 8 filters) into individual files: brightness, saturation, gamma, downscaler, pixelate, auto_crop, flip, color_correction. Includes the ProcessorManager refactor from target-centric architecture: ProcessorManager slimmed from ~1600 to ~490 lines with unified _processors dict replacing duplicate _targets/_kc_targets dicts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
187 lines
10 KiB
Python
187 lines
10 KiB
Python
"""Picture target schemas (CRUD, processing state, settings, metrics)."""
|
|
|
|
from datetime import datetime
|
|
from typing import Dict, List, Literal, Optional
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from wled_controller.core.processing.processing_settings import DEFAULT_STATE_CHECK_INTERVAL
|
|
|
|
|
|
class ColorCorrection(BaseModel):
|
|
"""Color correction settings."""
|
|
|
|
gamma: float = Field(default=2.2, description="Gamma correction", ge=0.1, le=5.0)
|
|
saturation: float = Field(default=1.0, description="Saturation multiplier", ge=0.0, le=2.0)
|
|
brightness: float = Field(default=1.0, description="Brightness multiplier", ge=0.0, le=1.0)
|
|
|
|
|
|
class ProcessingSettings(BaseModel):
|
|
"""Processing settings for a picture target."""
|
|
|
|
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)
|
|
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)
|
|
standby_interval: float = Field(default=1.0, description="Seconds between keepalive sends when screen is static (0.5-5.0)", ge=0.5, le=5.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"
|
|
)
|
|
|
|
|
|
class KeyColorRectangleSchema(BaseModel):
|
|
"""A named rectangle for key color extraction (relative coords 0.0-1.0)."""
|
|
|
|
name: str = Field(description="Rectangle name", min_length=1, max_length=50)
|
|
x: float = Field(default=0.0, description="Left edge (0.0-1.0)", ge=0.0, le=1.0)
|
|
y: float = Field(default=0.0, description="Top edge (0.0-1.0)", ge=0.0, le=1.0)
|
|
width: float = Field(default=1.0, description="Width (0.0-1.0)", gt=0.0, le=1.0)
|
|
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")
|
|
|
|
|
|
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 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="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)")
|
|
description: Optional[str] = Field(None, description="Optional description", max_length=500)
|
|
|
|
|
|
class PictureTargetUpdate(BaseModel):
|
|
"""Request to update a picture target."""
|
|
|
|
name: Optional[str] = Field(None, description="Target name", min_length=1, max_length=100)
|
|
device_id: Optional[str] = Field(None, description="WLED device ID")
|
|
picture_source_id: Optional[str] = Field(None, 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)")
|
|
description: Optional[str] = Field(None, description="Optional description", max_length=500)
|
|
|
|
|
|
class PictureTargetResponse(BaseModel):
|
|
"""Picture target response."""
|
|
|
|
id: str = Field(description="Target ID")
|
|
name: str = Field(description="Target name")
|
|
target_type: str = Field(description="Target type")
|
|
device_id: str = Field(default="", description="WLED device ID")
|
|
picture_source_id: str = Field(default="", description="Picture source ID")
|
|
settings: Optional[ProcessingSettings] = Field(None, description="Processing settings (wled)")
|
|
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(None, description="Key colors settings (key_colors)")
|
|
description: Optional[str] = Field(None, description="Description")
|
|
created_at: datetime = Field(description="Creation timestamp")
|
|
updated_at: datetime = Field(description="Last update timestamp")
|
|
|
|
|
|
class PictureTargetListResponse(BaseModel):
|
|
"""List of picture targets response."""
|
|
|
|
targets: List[PictureTargetResponse] = Field(description="List of picture targets")
|
|
count: int = Field(description="Number of targets")
|
|
|
|
|
|
class TargetProcessingState(BaseModel):
|
|
"""Processing state for a picture target."""
|
|
|
|
target_id: str = Field(description="Target ID")
|
|
device_id: Optional[str] = Field(None, description="Device ID")
|
|
processing: bool = Field(description="Whether processing is active")
|
|
fps_actual: Optional[float] = Field(None, description="Actual FPS achieved")
|
|
fps_potential: Optional[float] = Field(None, description="Potential FPS (processing speed without throttle)")
|
|
fps_target: int = Field(default=0, description="Target FPS")
|
|
frames_skipped: Optional[int] = Field(None, description="Frames skipped (no screen change)")
|
|
frames_keepalive: Optional[int] = Field(None, description="Keepalive frames sent during standby")
|
|
fps_current: Optional[int] = Field(None, description="Frames sent in the last second")
|
|
timing_extract_ms: Optional[float] = Field(None, description="Border extraction time (ms)")
|
|
timing_map_leds_ms: Optional[float] = Field(None, description="LED mapping time (ms)")
|
|
timing_smooth_ms: Optional[float] = Field(None, description="Smoothing time (ms)")
|
|
timing_send_ms: Optional[float] = Field(None, description="DDP send time (ms)")
|
|
timing_total_ms: Optional[float] = Field(None, description="Total processing 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: int = Field(default=0, description="Current display index")
|
|
overlay_active: bool = Field(default=False, description="Whether visualization overlay is active")
|
|
last_update: Optional[datetime] = Field(None, description="Last successful update")
|
|
errors: List[str] = Field(default_factory=list, description="Recent errors")
|
|
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_fps: Optional[int] = Field(None, description="Device-reported FPS (WLED internal refresh rate)")
|
|
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):
|
|
"""Target metrics response."""
|
|
|
|
target_id: str = Field(description="Target ID")
|
|
device_id: Optional[str] = Field(None, description="Device ID")
|
|
processing: bool = Field(description="Whether processing is active")
|
|
fps_actual: Optional[float] = Field(None, description="Actual FPS")
|
|
fps_target: int = Field(description="Target FPS")
|
|
uptime_seconds: float = Field(description="Processing uptime in seconds")
|
|
frames_processed: int = Field(description="Total frames processed")
|
|
errors_count: int = Field(description="Total error count")
|
|
last_error: Optional[str] = Field(None, description="Last error message")
|
|
last_update: Optional[datetime] = Field(None, description="Last update timestamp")
|
|
|
|
|
|
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")
|