CSS: add StaticColorStripSource type with auto-sized LED count
Introduces a new 'static' source type that fills all device LEDs with a single constant RGB color — no screen capture or processing required. - StaticColorStripSource storage model (color + led_count=0 auto-size) - StaticColorStripStream: no background thread, configure() sizes to device LED count at processor start; hot-updates preserve runtime size - ColorStripStreamManager dispatches static sources (no LiveStream needed) - WledTargetProcessor calls stream.configure(device_led_count) on start - API schemas/routes: source_type Literal["picture","static"]; color field; overlay/calibration-test endpoints return 400 for static - Frontend: type selector modal, color picker, type-aware card rendering (🎨 icon + color swatch), LED count field hidden for static type - Locale keys: color_strip.type, color_strip.static_color (en + ru) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,9 +6,9 @@ calibration, color correction, smoothing, and FPS.
|
||||
|
||||
Current types:
|
||||
PictureColorStripSource — derives LED colors from a PictureSource (screen capture)
|
||||
StaticColorStripSource — constant solid color fills all LEDs
|
||||
|
||||
Future types (not yet implemented):
|
||||
StaticColorStripSource — constant solid colors
|
||||
GradientColorStripSource — animated gradient
|
||||
"""
|
||||
|
||||
@@ -53,6 +53,7 @@ class ColorStripSource:
|
||||
"interpolation_mode": None,
|
||||
"calibration": None,
|
||||
"led_count": None,
|
||||
"color": None,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@@ -85,7 +86,20 @@ class ColorStripSource:
|
||||
else CalibrationConfig(layout="clockwise", start_position="bottom_left")
|
||||
)
|
||||
|
||||
# Only "picture" type for now; extend with elif branches for future types
|
||||
if source_type == "static":
|
||||
raw_color = data.get("color")
|
||||
color = (
|
||||
raw_color if isinstance(raw_color, list) and len(raw_color) == 3
|
||||
else [255, 255, 255]
|
||||
)
|
||||
return StaticColorStripSource(
|
||||
id=sid, name=name, source_type="static",
|
||||
created_at=created_at, updated_at=updated_at, description=description,
|
||||
color=color,
|
||||
led_count=data.get("led_count") or 0,
|
||||
)
|
||||
|
||||
# Default: "picture" type
|
||||
return PictureColorStripSource(
|
||||
id=sid, name=name, source_type=source_type,
|
||||
created_at=created_at, updated_at=updated_at, description=description,
|
||||
@@ -133,3 +147,22 @@ class PictureColorStripSource(ColorStripSource):
|
||||
d["calibration"] = calibration_to_dict(self.calibration)
|
||||
d["led_count"] = self.led_count
|
||||
return d
|
||||
|
||||
|
||||
@dataclass
|
||||
class StaticColorStripSource(ColorStripSource):
|
||||
"""Color strip source that fills all LEDs with a single static color.
|
||||
|
||||
No capture or processing — the entire LED strip is set to one constant
|
||||
RGB color. Useful for solid-color accents or as a placeholder while
|
||||
a PictureColorStripSource is being configured.
|
||||
"""
|
||||
|
||||
color: list = field(default_factory=lambda: [255, 255, 255]) # [R, G, B]
|
||||
led_count: int = 0 # 0 = use device LED count
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
d = super().to_dict()
|
||||
d["color"] = list(self.color)
|
||||
d["led_count"] = self.led_count
|
||||
return d
|
||||
|
||||
@@ -10,6 +10,7 @@ from wled_controller.core.capture.calibration import CalibrationConfig, calibrat
|
||||
from wled_controller.storage.color_strip_source import (
|
||||
ColorStripSource,
|
||||
PictureColorStripSource,
|
||||
StaticColorStripSource,
|
||||
)
|
||||
from wled_controller.utils import get_logger
|
||||
|
||||
@@ -99,6 +100,7 @@ class ColorStripStore:
|
||||
interpolation_mode: str = "average",
|
||||
calibration=None,
|
||||
led_count: int = 0,
|
||||
color: Optional[list] = None,
|
||||
description: Optional[str] = None,
|
||||
) -> ColorStripSource:
|
||||
"""Create a new color strip source.
|
||||
@@ -113,29 +115,41 @@ class ColorStripStore:
|
||||
if source.name == name:
|
||||
raise ValueError(f"Color strip source with name '{name}' already exists")
|
||||
|
||||
if calibration is None:
|
||||
calibration = CalibrationConfig(layout="clockwise", start_position="bottom_left")
|
||||
|
||||
source_id = f"css_{uuid.uuid4().hex[:8]}"
|
||||
now = datetime.utcnow()
|
||||
|
||||
source = PictureColorStripSource(
|
||||
id=source_id,
|
||||
name=name,
|
||||
source_type=source_type,
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
description=description,
|
||||
picture_source_id=picture_source_id,
|
||||
fps=fps,
|
||||
brightness=brightness,
|
||||
saturation=saturation,
|
||||
gamma=gamma,
|
||||
smoothing=smoothing,
|
||||
interpolation_mode=interpolation_mode,
|
||||
calibration=calibration,
|
||||
led_count=led_count,
|
||||
)
|
||||
if source_type == "static":
|
||||
rgb = color if isinstance(color, list) and len(color) == 3 else [255, 255, 255]
|
||||
source = StaticColorStripSource(
|
||||
id=source_id,
|
||||
name=name,
|
||||
source_type="static",
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
description=description,
|
||||
color=rgb,
|
||||
led_count=led_count,
|
||||
)
|
||||
else:
|
||||
if calibration is None:
|
||||
calibration = CalibrationConfig(layout="clockwise", start_position="bottom_left")
|
||||
source = PictureColorStripSource(
|
||||
id=source_id,
|
||||
name=name,
|
||||
source_type=source_type,
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
description=description,
|
||||
picture_source_id=picture_source_id,
|
||||
fps=fps,
|
||||
brightness=brightness,
|
||||
saturation=saturation,
|
||||
gamma=gamma,
|
||||
smoothing=smoothing,
|
||||
interpolation_mode=interpolation_mode,
|
||||
calibration=calibration,
|
||||
led_count=led_count,
|
||||
)
|
||||
|
||||
self._sources[source_id] = source
|
||||
self._save()
|
||||
@@ -156,6 +170,7 @@ class ColorStripStore:
|
||||
interpolation_mode: Optional[str] = None,
|
||||
calibration=None,
|
||||
led_count: Optional[int] = None,
|
||||
color: Optional[list] = None,
|
||||
description: Optional[str] = None,
|
||||
) -> ColorStripSource:
|
||||
"""Update an existing color strip source.
|
||||
@@ -196,6 +211,12 @@ class ColorStripStore:
|
||||
source.calibration = calibration
|
||||
if led_count is not None:
|
||||
source.led_count = led_count
|
||||
elif isinstance(source, StaticColorStripSource):
|
||||
if color is not None:
|
||||
if isinstance(color, list) and len(color) == 3:
|
||||
source.color = color
|
||||
if led_count is not None:
|
||||
source.led_count = led_count
|
||||
|
||||
source.updated_at = datetime.utcnow()
|
||||
self._save()
|
||||
|
||||
Reference in New Issue
Block a user