Add multi-segment LED targets, replace single color strip source + skip fields
Each target now has a segments list where each segment maps a color strip source to a pixel range (start/end) on the device with optional reverse. This enables composing multiple visualizations on a single LED strip. Old targets auto-migrate from the single source format on load. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,15 @@ class KeyColorsResponse(BaseModel):
|
||||
timestamp: Optional[datetime] = Field(None, description="Extraction timestamp")
|
||||
|
||||
|
||||
class TargetSegmentSchema(BaseModel):
|
||||
"""A segment mapping a color strip source to a pixel range on the device."""
|
||||
|
||||
color_strip_source_id: str = Field(default="", description="Color strip source ID")
|
||||
start: int = Field(default=0, ge=0, description="Start pixel (inclusive)")
|
||||
end: int = Field(default=0, ge=0, description="End pixel (exclusive, 0 = auto-fit)")
|
||||
reverse: bool = Field(default=False, description="Reverse pixel order within segment")
|
||||
|
||||
|
||||
class PictureTargetCreate(BaseModel):
|
||||
"""Request to create a picture target."""
|
||||
|
||||
@@ -52,12 +61,10 @@ class PictureTargetCreate(BaseModel):
|
||||
target_type: str = Field(default="led", description="Target type (led, key_colors)")
|
||||
# LED target fields
|
||||
device_id: str = Field(default="", description="LED device ID")
|
||||
color_strip_source_id: str = Field(default="", description="Color strip source ID")
|
||||
segments: List[TargetSegmentSchema] = Field(default_factory=list, description="LED segments")
|
||||
fps: int = Field(default=30, ge=1, le=90, description="Target send FPS (1-90)")
|
||||
keepalive_interval: float = Field(default=1.0, description="Keepalive send interval when screen is static (0.5-5.0s)", ge=0.5, le=5.0)
|
||||
state_check_interval: int = Field(default=DEFAULT_STATE_CHECK_INTERVAL, description="Device health check interval (5-600s)", ge=5, le=600)
|
||||
led_skip_start: int = Field(default=0, ge=0, description="Number of LEDs at the start to keep black")
|
||||
led_skip_end: int = Field(default=0, ge=0, description="Number of LEDs at the end to keep black")
|
||||
# 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)")
|
||||
@@ -70,12 +77,10 @@ class PictureTargetUpdate(BaseModel):
|
||||
name: Optional[str] = Field(None, description="Target name", min_length=1, max_length=100)
|
||||
# LED target fields
|
||||
device_id: Optional[str] = Field(None, description="LED device ID")
|
||||
color_strip_source_id: Optional[str] = Field(None, description="Color strip source ID")
|
||||
segments: Optional[List[TargetSegmentSchema]] = Field(None, description="LED segments")
|
||||
fps: Optional[int] = Field(None, ge=1, le=90, description="Target send FPS (1-90)")
|
||||
keepalive_interval: Optional[float] = Field(None, description="Keepalive interval (0.5-5.0s)", ge=0.5, le=5.0)
|
||||
state_check_interval: Optional[int] = Field(None, description="Health check interval (5-600s)", ge=5, le=600)
|
||||
led_skip_start: Optional[int] = Field(None, ge=0, description="Number of LEDs at the start to keep black")
|
||||
led_skip_end: Optional[int] = Field(None, ge=0, description="Number of LEDs at the end to keep black")
|
||||
# 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)")
|
||||
@@ -90,12 +95,10 @@ class PictureTargetResponse(BaseModel):
|
||||
target_type: str = Field(description="Target type")
|
||||
# LED target fields
|
||||
device_id: str = Field(default="", description="LED device ID")
|
||||
color_strip_source_id: str = Field(default="", description="Color strip source ID")
|
||||
segments: List[TargetSegmentSchema] = Field(default_factory=list, description="LED segments")
|
||||
fps: Optional[int] = Field(None, description="Target send FPS")
|
||||
keepalive_interval: float = Field(default=1.0, description="Keepalive interval (s)")
|
||||
state_check_interval: int = Field(default=DEFAULT_STATE_CHECK_INTERVAL, description="Health check interval (s)")
|
||||
led_skip_start: int = Field(default=0, description="LEDs skipped at start")
|
||||
led_skip_end: int = Field(default=0, description="LEDs skipped at end")
|
||||
# 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")
|
||||
@@ -116,7 +119,7 @@ class TargetProcessingState(BaseModel):
|
||||
|
||||
target_id: str = Field(description="Target ID")
|
||||
device_id: Optional[str] = Field(None, description="Device ID")
|
||||
color_strip_source_id: Optional[str] = Field(None, description="Color strip source ID")
|
||||
segments: List[TargetSegmentSchema] = Field(default_factory=list, description="LED segments")
|
||||
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)")
|
||||
|
||||
Reference in New Issue
Block a user