Add Daylight Cycle value source type

New value source that outputs brightness (0-1) based on the daylight
color LUT, computing BT.601 luminance from the simulated sky color.
Supports real-time wall-clock mode or configurable simulation speed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 11:27:36 +03:00
parent 73562cd525
commit ee40d99067
13 changed files with 271 additions and 12 deletions

View File

@@ -1,13 +1,14 @@
"""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. Five types:
parameters like brightness. Six 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:
adaptive_time — interpolates brightness along a 24-hour schedule
adaptive_scene — derives brightness from a picture source's frame luminance
DaylightValueSource — brightness based on simulated or real-time daylight cycle
"""
from dataclasses import dataclass, field
@@ -21,7 +22,7 @@ class ValueSource:
id: str
name: str
source_type: str # "static" | "animated" | "audio" | "adaptive_time" | "adaptive_scene"
source_type: str # "static" | "animated" | "audio" | "adaptive_time" | "adaptive_scene" | "daylight"
created_at: datetime
updated_at: datetime
description: Optional[str] = None
@@ -51,6 +52,8 @@ class ValueSource:
"schedule": None,
"picture_source_id": None,
"scene_behavior": None,
"use_real_time": None,
"latitude": None,
}
@staticmethod
@@ -121,6 +124,17 @@ class ValueSource:
max_value=float(data["max_value"]) if data.get("max_value") is not None else 1.0,
)
if source_type == "daylight":
return DaylightValueSource(
id=sid, name=name, source_type="daylight",
created_at=created_at, updated_at=updated_at, description=description, tags=tags,
speed=float(data.get("speed") or 1.0),
use_real_time=bool(data.get("use_real_time", False)),
latitude=float(data.get("latitude") or 50.0),
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,
)
# Default: "static" type
return StaticValueSource(
id=sid, name=name, source_type="static",
@@ -221,3 +235,27 @@ class AdaptiveValueSource(ValueSource):
d["min_value"] = self.min_value
d["max_value"] = self.max_value
return d
@dataclass
class DaylightValueSource(ValueSource):
"""Value source that outputs brightness based on a daylight cycle.
Uses the same daylight LUT as the CSS daylight stream to derive a
scalar brightness from the simulated (or real-time) sky color luminance.
"""
speed: float = 1.0 # simulation speed (ignored when use_real_time)
use_real_time: bool = False # use wall clock instead of simulation
latitude: float = 50.0 # affects sunrise/sunset in real-time mode
min_value: float = 0.0 # output range min
max_value: float = 1.0 # output range max
def to_dict(self) -> dict:
d = super().to_dict()
d["speed"] = self.speed
d["use_real_time"] = self.use_real_time
d["latitude"] = self.latitude
d["min_value"] = self.min_value
d["max_value"] = self.max_value
return d