Split adaptive value source into explicit adaptive_time and adaptive_scene types

Replace single "adaptive" type with adaptive_mode sub-selector by two
distinct source types in the dropdown. Removes the adaptive_mode field
entirely — the source_type itself carries the mode. Clearer UX with
"Adaptive (Time of Day)" and "Adaptive (Scene)" as separate options.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 15:23:50 +03:00
parent d339dd3f90
commit 1e4a7a067f
10 changed files with 142 additions and 170 deletions

View File

@@ -1,11 +1,13 @@
"""Value source data model with inheritance-based source types.
A ValueSource produces a scalar float (0.01.0) that can drive target
parameters like brightness. Four types:
parameters like brightness. Five types:
StaticValueSource — constant float value
AnimatedValueSource — periodic waveform (sine, triangle, square, sawtooth)
AudioValueSource — audio-reactive scalar (RMS, peak, beat detection)
AdaptiveValueSource — adapts to external conditions (time of day, scene brightness)
AdaptiveValueSource — adapts to external conditions:
adaptive_time — interpolates brightness along a 24-hour schedule
adaptive_scene — derives brightness from a picture source's frame luminance
"""
from dataclasses import dataclass, field
@@ -19,7 +21,7 @@ class ValueSource:
id: str
name: str
source_type: str # "static" | "animated" | "audio"
source_type: str # "static" | "animated" | "audio" | "adaptive_time" | "adaptive_scene"
created_at: datetime
updated_at: datetime
description: Optional[str] = None
@@ -43,7 +45,6 @@ class ValueSource:
"mode": None,
"sensitivity": None,
"smoothing": None,
"adaptive_mode": None,
"schedule": None,
"picture_source_id": None,
"scene_behavior": None,
@@ -92,12 +93,19 @@ class ValueSource:
smoothing=float(data.get("smoothing") or 0.3),
)
if source_type == "adaptive":
if source_type == "adaptive_time":
return AdaptiveValueSource(
id=sid, name=name, source_type="adaptive",
id=sid, name=name, source_type="adaptive_time",
created_at=created_at, updated_at=updated_at, description=description,
adaptive_mode=data.get("adaptive_mode") or "time_of_day",
schedule=data.get("schedule") or [],
min_value=float(data.get("min_value") or 0.0),
max_value=float(data["max_value"]) if data.get("max_value") is not None else 1.0,
)
if source_type == "adaptive_scene":
return AdaptiveValueSource(
id=sid, name=name, source_type="adaptive_scene",
created_at=created_at, updated_at=updated_at, description=description,
picture_source_id=data.get("picture_source_id") or "",
scene_behavior=data.get("scene_behavior") or "complement",
sensitivity=float(data.get("sensitivity") or 1.0),
@@ -177,12 +185,11 @@ class AudioValueSource(ValueSource):
class AdaptiveValueSource(ValueSource):
"""Value source that adapts to external conditions.
Two sub-modes:
time_of_day — interpolates brightness along a 24-hour schedule
scene — derives brightness from a picture source's frame luminance
source_type determines the sub-mode:
adaptive_time — interpolates brightness along a 24-hour schedule
adaptive_scene — derives brightness from a picture source's frame luminance
"""
adaptive_mode: str = "time_of_day" # "time_of_day" | "scene"
schedule: List[dict] = field(default_factory=list) # [{time: "HH:MM", value: 0.0-1.0}]
picture_source_id: str = "" # for scene mode
scene_behavior: str = "complement" # "complement" | "match"
@@ -193,7 +200,6 @@ class AdaptiveValueSource(ValueSource):
def to_dict(self) -> dict:
d = super().to_dict()
d["adaptive_mode"] = self.adaptive_mode
d["schedule"] = self.schedule
d["picture_source_id"] = self.picture_source_id
d["scene_behavior"] = self.scene_behavior