Add min brightness threshold to LED targets

New per-target property: when effective output brightness
(max pixel value × device/source brightness) falls below
the threshold, LEDs turn off completely. Useful for cutting
dim flicker in audio-reactive and ambient setups.

Threshold slider (0–254) in target editor, badge on card,
hot-swap to running processors, persisted in storage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 15:03:53 +03:00
parent c2deef214e
commit a164abe774
11 changed files with 75 additions and 1 deletions

View File

@@ -106,6 +106,7 @@ class PictureTargetStore:
fps: int = 30,
keepalive_interval: float = 1.0,
state_check_interval: int = DEFAULT_STATE_CHECK_INTERVAL,
min_brightness_threshold: int = 0,
key_colors_settings: Optional[KeyColorsSettings] = None,
description: Optional[str] = None,
picture_source_id: str = "",
@@ -138,6 +139,7 @@ class PictureTargetStore:
fps=fps,
keepalive_interval=keepalive_interval,
state_check_interval=state_check_interval,
min_brightness_threshold=min_brightness_threshold,
description=description,
auto_start=auto_start,
created_at=now,
@@ -174,6 +176,7 @@ class PictureTargetStore:
fps: Optional[int] = None,
keepalive_interval: Optional[float] = None,
state_check_interval: Optional[int] = None,
min_brightness_threshold: Optional[int] = None,
key_colors_settings: Optional[KeyColorsSettings] = None,
description: Optional[str] = None,
auto_start: Optional[bool] = None,
@@ -202,6 +205,7 @@ class PictureTargetStore:
fps=fps,
keepalive_interval=keepalive_interval,
state_check_interval=state_check_interval,
min_brightness_threshold=min_brightness_threshold,
key_colors_settings=key_colors_settings,
description=description,
auto_start=auto_start,

View File

@@ -19,6 +19,7 @@ class WledPictureTarget(PictureTarget):
fps: int = 30 # target send FPS (1-90)
keepalive_interval: float = 1.0 # seconds between keepalive sends when screen is static
state_check_interval: int = DEFAULT_STATE_CHECK_INTERVAL
min_brightness_threshold: int = 0 # brightness below this → 0 (disabled when 0)
def register_with_manager(self, manager) -> None:
"""Register this WLED target with the processor manager."""
@@ -31,6 +32,7 @@ class WledPictureTarget(PictureTarget):
keepalive_interval=self.keepalive_interval,
state_check_interval=self.state_check_interval,
brightness_value_source_id=self.brightness_value_source_id,
min_brightness_threshold=self.min_brightness_threshold,
)
def sync_with_manager(self, manager, *, settings_changed: bool,
@@ -43,6 +45,7 @@ class WledPictureTarget(PictureTarget):
"fps": self.fps,
"keepalive_interval": self.keepalive_interval,
"state_check_interval": self.state_check_interval,
"min_brightness_threshold": self.min_brightness_threshold,
})
if css_changed:
manager.update_target_css(self.id, self.color_strip_source_id)
@@ -54,6 +57,7 @@ class WledPictureTarget(PictureTarget):
def update_fields(self, *, name=None, device_id=None, color_strip_source_id=None,
brightness_value_source_id=None,
fps=None, keepalive_interval=None, state_check_interval=None,
min_brightness_threshold=None,
description=None, auto_start=None, **_kwargs) -> None:
"""Apply mutable field updates for WLED targets."""
super().update_fields(name=name, description=description, auto_start=auto_start)
@@ -69,6 +73,8 @@ class WledPictureTarget(PictureTarget):
self.keepalive_interval = keepalive_interval
if state_check_interval is not None:
self.state_check_interval = state_check_interval
if min_brightness_threshold is not None:
self.min_brightness_threshold = min_brightness_threshold
@property
def has_picture_source(self) -> bool:
@@ -83,6 +89,7 @@ class WledPictureTarget(PictureTarget):
d["fps"] = self.fps
d["keepalive_interval"] = self.keepalive_interval
d["state_check_interval"] = self.state_check_interval
d["min_brightness_threshold"] = self.min_brightness_threshold
return d
@classmethod
@@ -108,6 +115,7 @@ class WledPictureTarget(PictureTarget):
fps=data.get("fps", 30),
keepalive_interval=data.get("keepalive_interval", data.get("standby_interval", 1.0)),
state_check_interval=data.get("state_check_interval", DEFAULT_STATE_CHECK_INTERVAL),
min_brightness_threshold=data.get("min_brightness_threshold", 0),
description=data.get("description"),
auto_start=data.get("auto_start", False),
created_at=datetime.fromisoformat(data.get("created_at", datetime.utcnow().isoformat())),