feat(api-input): make SegmentPayload start/length optional
start defaults to 0, length defaults to led_count - start (the rest of the strip from start). A single segment with only mode + color now fills the entire strip — no more length: 9999 magic value clients have to pass. Buffer auto-grow only fires for segments with an explicit length past the current end; implicit "to the end" segments adapt to the current strip size.
This commit is contained in:
@@ -655,10 +655,22 @@ class ColorStripSourceListResponse(BaseModel):
|
||||
|
||||
|
||||
class SegmentPayload(BaseModel):
|
||||
"""A single segment for segment-based LED color updates."""
|
||||
"""A single segment for segment-based LED color updates.
|
||||
|
||||
start: int = Field(ge=0, description="Starting LED index")
|
||||
length: int = Field(ge=1, description="Number of LEDs in segment")
|
||||
``start`` and ``length`` are optional: when omitted, the segment defaults
|
||||
to ``start=0`` and ``length=led_count - start`` (i.e. the rest of the
|
||||
strip from ``start``). Sending a single segment with only ``mode`` and
|
||||
``color`` therefore fills the entire strip.
|
||||
"""
|
||||
|
||||
start: Optional[int] = Field(
|
||||
None, ge=0, description="Starting LED index (default 0 = beginning of strip)"
|
||||
)
|
||||
length: Optional[int] = Field(
|
||||
None,
|
||||
ge=1,
|
||||
description="Number of LEDs in segment (default = led_count - start)",
|
||||
)
|
||||
mode: Literal["solid", "per_pixel", "gradient"] = Field(description="Fill mode")
|
||||
color: Optional[List[int]] = Field(None, description="RGB for solid mode [R,G,B]")
|
||||
colors: Optional[List[List[int]]] = Field(
|
||||
|
||||
@@ -148,23 +148,37 @@ class ApiInputColorStripStream(ColorStripStream):
|
||||
"""Apply segment-based color updates to the buffer.
|
||||
|
||||
Each segment defines a range and fill mode. Segments are applied in
|
||||
order (last wins on overlap). The buffer is auto-grown if needed.
|
||||
order (last wins on overlap).
|
||||
|
||||
``start`` and ``length`` are optional: ``start`` defaults to 0,
|
||||
``length`` defaults to ``led_count - start`` (i.e. the remainder of
|
||||
the strip). The buffer is only auto-grown for segments that supply
|
||||
an explicit ``length`` extending past the current end — implicit
|
||||
"to the end" segments adapt to whatever the current strip size is.
|
||||
|
||||
Args:
|
||||
segments: list of dicts with keys:
|
||||
start (int) – starting LED index
|
||||
length (int) – number of LEDs in segment
|
||||
mode (str) – "solid" | "per_pixel" | "gradient"
|
||||
color (list) – [R,G,B] for solid mode
|
||||
colors (list) – [[R,G,B], ...] for per_pixel/gradient
|
||||
start (int, optional) – starting LED index (default 0)
|
||||
length (int, optional) – number of LEDs in segment
|
||||
(default = led_count - start)
|
||||
mode (str) – "solid" | "per_pixel" | "gradient"
|
||||
color (list) – [R,G,B] for solid mode
|
||||
colors (list) – [[R,G,B], ...] for per_pixel/gradient
|
||||
"""
|
||||
# Compute required buffer size from all segments
|
||||
max_index = max(seg["start"] + seg["length"] for seg in segments)
|
||||
# Compute required buffer size from segments that supply an explicit
|
||||
# length. Segments without a length take the strip as-is and so do
|
||||
# not trigger growth.
|
||||
explicit_max = 0
|
||||
for seg in segments:
|
||||
seg_start = seg.get("start") or 0
|
||||
seg_len = seg.get("length")
|
||||
if seg_len is not None:
|
||||
explicit_max = max(explicit_max, seg_start + seg_len)
|
||||
|
||||
with self._lock:
|
||||
# Auto-grow buffer if needed
|
||||
if max_index > self._led_count:
|
||||
self._ensure_capacity(max_index)
|
||||
# Auto-grow buffer if any explicit segment extends past current end
|
||||
if explicit_max > self._led_count:
|
||||
self._ensure_capacity(explicit_max)
|
||||
|
||||
# Start from current buffer (or fallback if timed out)
|
||||
if self._timed_out:
|
||||
@@ -173,8 +187,12 @@ class ApiInputColorStripStream(ColorStripStream):
|
||||
buf = self._colors.copy()
|
||||
|
||||
for seg in segments:
|
||||
start = seg["start"]
|
||||
length = seg["length"]
|
||||
seg_start = seg.get("start")
|
||||
start = 0 if seg_start is None else seg_start
|
||||
seg_len = seg.get("length")
|
||||
length = max(0, self._led_count - start) if seg_len is None else seg_len
|
||||
if length <= 0:
|
||||
continue
|
||||
mode = seg["mode"]
|
||||
end = start + length
|
||||
|
||||
|
||||
Reference in New Issue
Block a user