From bc5d8fdc9bd2f82cc2b67818864c6b34ccf30340 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sun, 8 Mar 2026 21:21:00 +0300 Subject: [PATCH] Remove led_count from static, gradient, color_cycle, and effect CSS sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These types always auto-size from the connected device — the explicit led_count override was unused clutter. Streams now use getattr fallback. Co-Authored-By: Claude Opus 4.6 --- .../core/processing/color_strip_stream.py | 15 +++++++++------ .../core/processing/effect_stream.py | 5 +++-- .../static/js/features/color-strips.js | 10 +++------- server/src/wled_controller/static/sw.js | 2 +- .../storage/color_strip_source.py | 18 +++--------------- .../storage/color_strip_store.py | 12 ------------ 6 files changed, 19 insertions(+), 43 deletions(-) diff --git a/server/src/wled_controller/core/processing/color_strip_stream.py b/server/src/wled_controller/core/processing/color_strip_stream.py index 467577f..49387fe 100644 --- a/server/src/wled_controller/core/processing/color_strip_stream.py +++ b/server/src/wled_controller/core/processing/color_strip_stream.py @@ -573,8 +573,9 @@ class StaticColorStripStream(ColorStripStream): def _update_from_source(self, source) -> None: color = source.color if isinstance(source.color, list) and len(source.color) == 3 else [255, 255, 255] self._source_color = color # stored separately so configure() can rebuild - self._auto_size = not source.led_count # True when led_count == 0 - led_count = source.led_count if source.led_count and source.led_count > 0 else 1 + _lc = getattr(source, "led_count", 0) + self._auto_size = not _lc + led_count = _lc if _lc and _lc > 0 else 1 self._led_count = led_count self._animation = source.animation # dict or None; read atomically by _animate_loop self._rebuild_colors() @@ -798,8 +799,9 @@ class ColorCycleColorStripStream(ColorStripStream): self._color_list = [ c for c in raw if isinstance(c, list) and len(c) == 3 ] or default - self._auto_size = not source.led_count - self._led_count = source.led_count if source.led_count > 0 else 1 + _lc = getattr(source, "led_count", 0) + self._auto_size = not _lc + self._led_count = _lc if _lc > 0 else 1 self._rebuild_colors() def _rebuild_colors(self) -> None: @@ -950,8 +952,9 @@ class GradientColorStripStream(ColorStripStream): def _update_from_source(self, source) -> None: self._stops = list(source.stops) if source.stops else [] - self._auto_size = not source.led_count - led_count = source.led_count if source.led_count and source.led_count > 0 else 1 + _lc = getattr(source, "led_count", 0) + self._auto_size = not _lc + led_count = _lc if _lc and _lc > 0 else 1 self._led_count = led_count self._animation = source.animation # dict or None; read atomically by _animate_loop self._rebuild_colors() diff --git a/server/src/wled_controller/core/processing/effect_stream.py b/server/src/wled_controller/core/processing/effect_stream.py index 87b06e1..9421a10 100644 --- a/server/src/wled_controller/core/processing/effect_stream.py +++ b/server/src/wled_controller/core/processing/effect_stream.py @@ -203,8 +203,9 @@ class EffectColorStripStream(ColorStripStream): def _update_from_source(self, source) -> None: self._effect_type = getattr(source, "effect_type", "fire") - self._auto_size = not source.led_count - self._led_count = source.led_count if source.led_count and source.led_count > 0 else 1 + _lc = getattr(source, "led_count", 0) + self._auto_size = not _lc + self._led_count = _lc if _lc and _lc > 0 else 1 self._palette_name = getattr(source, "palette", None) or _EFFECT_DEFAULT_PALETTE.get(self._effect_type, "fire") self._palette_lut = _build_palette_lut(self._palette_name) color = getattr(source, "color", None) diff --git a/server/src/wled_controller/static/js/features/color-strips.js b/server/src/wled_controller/static/js/features/color-strips.js index 4c81d7c..46dbe47 100644 --- a/server/src/wled_controller/static/js/features/color-strips.js +++ b/server/src/wled_controller/static/js/features/color-strips.js @@ -116,9 +116,10 @@ export function onCSSTypeChange() { } _syncAnimationSpeedState(); - // LED count — not needed for composite/mapped/audio/api_input (uses device count) + // LED count — only shown for picture, api_input, notification + const hasLedCount = ['picture', 'api_input', 'notification']; document.getElementById('css-editor-led-count-group').style.display = - (type === 'composite' || type === 'mapped' || type === 'audio' || type === 'api_input') ? 'none' : ''; + hasLedCount.includes(type) ? '' : 'none'; // Sync clock — shown for animated types (static, gradient, color_cycle, effect) const clockTypes = ['static', 'gradient', 'color_cycle', 'effect']; @@ -716,7 +717,6 @@ export function createColorStripCard(source, pictureSourceMap, audioSourceMap) { ${hexColor.toUpperCase()} - ${source.led_count ? `${ICON_LED} ${source.led_count}` : ''} ${animBadge} ${clockBadge} `; @@ -727,7 +727,6 @@ export function createColorStripCard(source, pictureSourceMap, audioSourceMap) { ).join(''); propsHtml = ` ${swatches} - ${source.led_count ? `${ICON_LED} ${source.led_count}` : ''} ${clockBadge} `; } else if (isGradient) { @@ -749,7 +748,6 @@ export function createColorStripCard(source, pictureSourceMap, audioSourceMap) { propsHtml = ` ${cssGradient ? `` : ''} ${ICON_PALETTE} ${stops.length} ${t('color_strip.gradient.stops_count')} - ${source.led_count ? `${ICON_LED} ${source.led_count}` : ''} ${animBadge} ${clockBadge} `; @@ -759,7 +757,6 @@ export function createColorStripCard(source, pictureSourceMap, audioSourceMap) { propsHtml = ` ${ICON_FPS} ${escapeHtml(effectLabel)} ${paletteLabel ? `${ICON_PALETTE} ${escapeHtml(paletteLabel)}` : ''} - ${source.led_count ? `${ICON_LED} ${source.led_count}` : ''} ${clockBadge} `; } else if (isComposite) { @@ -1103,7 +1100,6 @@ export async function saveCSSEditor() { intensity: parseFloat(document.getElementById('css-editor-effect-intensity').value), scale: parseFloat(document.getElementById('css-editor-effect-scale').value), mirror: document.getElementById('css-editor-effect-mirror').checked, - led_count: parseInt(document.getElementById('css-editor-led-count').value) || 0, }; // Meteor uses a color picker if (payload.effect_type === 'meteor') { diff --git a/server/src/wled_controller/static/sw.js b/server/src/wled_controller/static/sw.js index 1bb42d7..9f698a5 100644 --- a/server/src/wled_controller/static/sw.js +++ b/server/src/wled_controller/static/sw.js @@ -7,7 +7,7 @@ * - Navigation: network-first with offline fallback */ -const CACHE_NAME = 'ledgrab-v11'; +const CACHE_NAME = 'ledgrab-v12'; // Only pre-cache static assets (no auth required). // Do NOT pre-cache '/' — it requires API key auth and would cache an error page. diff --git a/server/src/wled_controller/storage/color_strip_source.py b/server/src/wled_controller/storage/color_strip_source.py index 9d875bd..3b1d94a 100644 --- a/server/src/wled_controller/storage/color_strip_source.py +++ b/server/src/wled_controller/storage/color_strip_source.py @@ -134,7 +134,6 @@ class ColorStripSource: id=sid, name=name, source_type="static", created_at=created_at, updated_at=updated_at, description=description, clock_id=clock_id, color=color, - led_count=data.get("led_count") or 0, animation=data.get("animation"), ) @@ -145,7 +144,6 @@ class ColorStripSource: id=sid, name=name, source_type="gradient", created_at=created_at, updated_at=updated_at, description=description, clock_id=clock_id, stops=stops, - led_count=data.get("led_count") or 0, animation=data.get("animation"), ) @@ -156,7 +154,6 @@ class ColorStripSource: id=sid, name=name, source_type="color_cycle", created_at=created_at, updated_at=updated_at, description=description, clock_id=clock_id, colors=colors, - led_count=data.get("led_count") or 0, ) if source_type == "composite": @@ -204,7 +201,6 @@ class ColorStripSource: id=sid, name=name, source_type="effect", created_at=created_at, updated_at=updated_at, description=description, clock_id=clock_id, effect_type=data.get("effect_type") or "fire", - led_count=data.get("led_count") or 0, palette=data.get("palette") or "fire", color=color, intensity=float(data.get("intensity") or 1.0), @@ -313,13 +309,11 @@ class StaticColorStripSource(ColorStripSource): """ color: list = field(default_factory=lambda: [255, 255, 255]) # [R, G, B] - led_count: int = 0 # 0 = use device LED count animation: Optional[dict] = None # {"enabled": bool, "type": str, "speed": float} or None def to_dict(self) -> dict: d = super().to_dict() d["color"] = list(self.color) - d["led_count"] = self.led_count d["animation"] = self.animation return d @@ -332,7 +326,7 @@ class GradientColorStripSource(ColorStripSource): Each stop has a primary color; optionally a second "right" color to create a hard discontinuity (bidirectional stop) at that position. - LED count auto-sizes from the connected device when led_count == 0. + LED count auto-sizes from the connected device. """ # Each stop: {"position": float, "color": [R,G,B], "color_right": [R,G,B] | null} @@ -340,13 +334,11 @@ class GradientColorStripSource(ColorStripSource): {"position": 0.0, "color": [255, 0, 0]}, {"position": 1.0, "color": [0, 0, 255]}, ]) - led_count: int = 0 # 0 = use device LED count animation: Optional[dict] = None # {"enabled": bool, "type": str, "speed": float} or None def to_dict(self) -> dict: d = super().to_dict() d["stops"] = [dict(s) for s in self.stops] - d["led_count"] = self.led_count d["animation"] = self.animation return d @@ -357,19 +349,17 @@ class ColorCycleColorStripSource(ColorStripSource): All LEDs receive the same solid color at any point in time, smoothly interpolating between the configured color stops in a continuous loop. - LED count auto-sizes from the connected device when led_count == 0. + LED count auto-sizes from the connected device. """ colors: list = field(default_factory=lambda: [ [255, 0, 0], [255, 255, 0], [0, 255, 0], [0, 255, 255], [0, 0, 255], [255, 0, 255], ]) - led_count: int = 0 # 0 = use device LED count def to_dict(self) -> dict: d = super().to_dict() d["colors"] = [list(c) for c in self.colors] - d["led_count"] = self.led_count return d @@ -379,11 +369,10 @@ class EffectColorStripSource(ColorStripSource): The effect_type field selects which algorithm to use: fire, meteor, plasma, noise, aurora. - LED count auto-sizes from the connected device when led_count == 0. + LED count auto-sizes from the connected device. """ effect_type: str = "fire" # fire | meteor | plasma | noise | aurora - led_count: int = 0 # 0 = use device LED count palette: str = "fire" # named color palette color: list = field(default_factory=lambda: [255, 80, 0]) # [R,G,B] for meteor head intensity: float = 1.0 # effect-specific intensity (0.1–2.0) @@ -393,7 +382,6 @@ class EffectColorStripSource(ColorStripSource): def to_dict(self) -> dict: d = super().to_dict() d["effect_type"] = self.effect_type - d["led_count"] = self.led_count d["palette"] = self.palette d["color"] = list(self.color) d["intensity"] = self.intensity diff --git a/server/src/wled_controller/storage/color_strip_store.py b/server/src/wled_controller/storage/color_strip_store.py index ba34e84..0c1dc53 100644 --- a/server/src/wled_controller/storage/color_strip_store.py +++ b/server/src/wled_controller/storage/color_strip_store.py @@ -155,7 +155,6 @@ class ColorStripStore: description=description, clock_id=clock_id, color=rgb, - led_count=led_count, animation=animation, ) elif source_type == "gradient": @@ -171,7 +170,6 @@ class ColorStripStore: {"position": 0.0, "color": [255, 0, 0]}, {"position": 1.0, "color": [0, 0, 255]}, ], - led_count=led_count, animation=animation, ) elif source_type == "color_cycle": @@ -188,7 +186,6 @@ class ColorStripStore: description=description, clock_id=clock_id, colors=colors if isinstance(colors, list) and len(colors) >= 2 else default_colors, - led_count=led_count, ) elif source_type == "effect": rgb = color if isinstance(color, list) and len(color) == 3 else [255, 80, 0] @@ -201,7 +198,6 @@ class ColorStripStore: description=description, clock_id=clock_id, effect_type=effect_type or "fire", - led_count=led_count, palette=palette or "fire", color=rgb, intensity=float(intensity) if intensity else 1.0, @@ -402,27 +398,19 @@ class ColorStripStore: 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 if animation is not None: source.animation = animation elif isinstance(source, GradientColorStripSource): if stops is not None and isinstance(stops, list): source.stops = stops - if led_count is not None: - source.led_count = led_count if animation is not None: source.animation = animation elif isinstance(source, ColorCycleColorStripSource): if colors is not None and isinstance(colors, list) and len(colors) >= 2: source.colors = colors - if led_count is not None: - source.led_count = led_count elif isinstance(source, EffectColorStripSource): if effect_type is not None: source.effect_type = effect_type - if led_count is not None: - source.led_count = led_count if palette is not None: source.palette = palette if color is not None and isinstance(color, list) and len(color) == 3: