Remove target segments, use single color strip source per target
Segments are redundant now that the "mapped" CSS type handles spatial multiplexing internally. Each target now references one color_strip_source_id instead of an array of segments with start/end/reverse ranges. Backward compat: existing targets with old segments format are migrated on load by extracting the first segment's CSS source ID. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -32,7 +32,6 @@ from wled_controller.api.schemas.picture_targets import (
|
||||
PictureTargetUpdate,
|
||||
TargetMetricsResponse,
|
||||
TargetProcessingState,
|
||||
TargetSegmentSchema,
|
||||
)
|
||||
from wled_controller.config import get_config
|
||||
from wled_controller.core.capture_engines import EngineRegistry
|
||||
@@ -94,15 +93,7 @@ def _target_to_response(target) -> PictureTargetResponse:
|
||||
name=target.name,
|
||||
target_type=target.target_type,
|
||||
device_id=target.device_id,
|
||||
segments=[
|
||||
TargetSegmentSchema(
|
||||
color_strip_source_id=s.color_strip_source_id,
|
||||
start=s.start,
|
||||
end=s.end,
|
||||
reverse=s.reverse,
|
||||
)
|
||||
for s in target.segments
|
||||
],
|
||||
color_strip_source_id=target.color_strip_source_id,
|
||||
fps=target.fps,
|
||||
keepalive_interval=target.keepalive_interval,
|
||||
state_check_interval=target.state_check_interval,
|
||||
@@ -157,7 +148,7 @@ async def create_target(
|
||||
name=data.name,
|
||||
target_type=data.target_type,
|
||||
device_id=data.device_id,
|
||||
segments=[s.model_dump() for s in data.segments] if data.segments else None,
|
||||
color_strip_source_id=data.color_strip_source_id,
|
||||
fps=data.fps,
|
||||
keepalive_interval=data.keepalive_interval,
|
||||
state_check_interval=data.state_check_interval,
|
||||
@@ -267,12 +258,11 @@ async def update_target(
|
||||
kc_settings = _kc_schema_to_settings(data.key_colors_settings)
|
||||
|
||||
# Update in store
|
||||
segments_dicts = [s.model_dump() for s in data.segments] if data.segments is not None else None
|
||||
target = target_store.update_target(
|
||||
target_id=target_id,
|
||||
name=data.name,
|
||||
device_id=data.device_id,
|
||||
segments=segments_dicts,
|
||||
color_strip_source_id=data.color_strip_source_id,
|
||||
fps=data.fps,
|
||||
keepalive_interval=data.keepalive_interval,
|
||||
state_check_interval=data.state_check_interval,
|
||||
@@ -288,7 +278,7 @@ async def update_target(
|
||||
data.keepalive_interval is not None or
|
||||
data.state_check_interval is not None or
|
||||
data.key_colors_settings is not None),
|
||||
segments_changed=data.segments is not None,
|
||||
css_changed=data.color_strip_source_id is not None,
|
||||
device_changed=data.device_id is not None,
|
||||
)
|
||||
except ValueError:
|
||||
@@ -756,9 +746,8 @@ async def start_target_overlay(
|
||||
# can start even when processing is not currently running.
|
||||
calibration = None
|
||||
display_info = None
|
||||
if isinstance(target, WledPictureTarget) and target.segments:
|
||||
# Use the first segment's CSS for calibration/overlay
|
||||
first_css_id = target.segments[0].color_strip_source_id
|
||||
if isinstance(target, WledPictureTarget) and target.color_strip_source_id:
|
||||
first_css_id = target.color_strip_source_id
|
||||
if first_css_id:
|
||||
try:
|
||||
css = color_strip_store.get_source(first_css_id)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Picture target schemas (CRUD, processing state, metrics)."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Dict, Optional, List
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
@@ -45,15 +45,6 @@ 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."""
|
||||
|
||||
@@ -61,7 +52,7 @@ 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")
|
||||
segments: List[TargetSegmentSchema] = Field(default_factory=list, description="LED segments")
|
||||
color_strip_source_id: str = Field(default="", description="Color strip source ID")
|
||||
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)
|
||||
@@ -77,7 +68,7 @@ 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")
|
||||
segments: Optional[List[TargetSegmentSchema]] = Field(None, description="LED segments")
|
||||
color_strip_source_id: Optional[str] = Field(None, description="Color strip source ID")
|
||||
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)
|
||||
@@ -95,7 +86,7 @@ class PictureTargetResponse(BaseModel):
|
||||
target_type: str = Field(description="Target type")
|
||||
# LED target fields
|
||||
device_id: str = Field(default="", description="LED device ID")
|
||||
segments: List[TargetSegmentSchema] = Field(default_factory=list, description="LED segments")
|
||||
color_strip_source_id: str = Field(default="", description="Color strip source ID")
|
||||
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)")
|
||||
@@ -119,7 +110,7 @@ class TargetProcessingState(BaseModel):
|
||||
|
||||
target_id: str = Field(description="Target ID")
|
||||
device_id: Optional[str] = Field(None, description="Device ID")
|
||||
segments: List[TargetSegmentSchema] = Field(default_factory=list, description="LED segments")
|
||||
color_strip_source_id: str = Field(default="", description="Color strip source 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)")
|
||||
|
||||
Reference in New Issue
Block a user