87 lines
2.3 KiB
Python
87 lines
2.3 KiB
Python
"""
|
||
Combine global, group, device (and optional zone) brightness into one 0–255 wire value.
|
||
|
||
Formula: ``(f1/255) * (f2/255) * ... * (fn/255) * 255`` with integer rounding — one ``b`` sent to the driver.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from models.device import normalize_mac
|
||
|
||
|
||
def clamp255(value) -> int:
|
||
try:
|
||
v = int(value)
|
||
except (TypeError, ValueError):
|
||
return 255
|
||
return max(0, min(255, v))
|
||
|
||
|
||
def multiply_brightness_factors(factors: list) -> int:
|
||
"""Product ``(f1/255)*(f2/255)*...*255``; each factor clamped to 0..255."""
|
||
if not factors:
|
||
return 255
|
||
fs = [clamp255(f) for f in factors]
|
||
if len(fs) == 1:
|
||
return fs[0]
|
||
num = 1
|
||
for f in fs:
|
||
num *= f
|
||
den = 255 ** (len(fs) - 1)
|
||
return max(0, min(255, (num + den // 2) // den))
|
||
|
||
|
||
def _mac_in_device_list(raw_list, target_mac: str) -> bool:
|
||
tm = normalize_mac(target_mac)
|
||
if not tm:
|
||
return False
|
||
if not isinstance(raw_list, list):
|
||
return False
|
||
for raw in raw_list:
|
||
if normalize_mac(str(raw)) == tm:
|
||
return True
|
||
return False
|
||
|
||
|
||
def effective_brightness_for_mac(
|
||
settings_obj,
|
||
groups_model,
|
||
devices_model,
|
||
mac: str,
|
||
*,
|
||
zone_brightness=None,
|
||
) -> int:
|
||
"""
|
||
Factors (each 0..255): Pi **global_brightness**, each group's **output_brightness**
|
||
(neutral 255 if the device is in no group), device **output_brightness** (default 255),
|
||
optional **zone_brightness** from the zone slider when applying live.
|
||
"""
|
||
m = normalize_mac(mac)
|
||
if not m:
|
||
return 255
|
||
|
||
g_global = clamp255(settings_obj.get("global_brightness", 255))
|
||
|
||
dev_doc = devices_model.read(m)
|
||
if dev_doc is not None and dev_doc.get("output_brightness") is not None:
|
||
d_b = clamp255(dev_doc.get("output_brightness"))
|
||
else:
|
||
d_b = 255
|
||
|
||
group_factors = []
|
||
for _gid, gdoc in groups_model.items():
|
||
if not isinstance(gdoc, dict):
|
||
continue
|
||
if not _mac_in_device_list(gdoc.get("devices"), m):
|
||
continue
|
||
group_factors.append(clamp255(gdoc.get("output_brightness", 255)))
|
||
|
||
if not group_factors:
|
||
group_factors = [255]
|
||
|
||
factors = [g_global, *group_factors, d_b]
|
||
if zone_brightness is not None:
|
||
factors.append(clamp255(zone_brightness))
|
||
|
||
return multiply_brightness_factors(factors)
|