mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-28 21:04:19 +02:00
Merge main before final turn-on policy review
This commit is contained in:
commit
b34db1261c
14 changed files with 2181 additions and 25 deletions
131
custom_components/adaptive_lighting/diagnostics.py
Normal file
131
custom_components/adaptive_lighting/diagnostics.py
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
"""Diagnostics support for Adaptive Lighting."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP_KELVIN,
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_TRANSITION,
|
||||
)
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .adaptation_utils import LightControlAttributes
|
||||
from .const import (
|
||||
ADAPT_BRIGHTNESS_SWITCH,
|
||||
ADAPT_COLOR_SWITCH,
|
||||
ATTR_ADAPTIVE_LIGHTING_MANAGER,
|
||||
DOMAIN,
|
||||
SLEEP_MODE_SWITCH,
|
||||
)
|
||||
from .switch import AdaptiveLightingManager, AdaptiveSwitch
|
||||
|
||||
_REPORTABLE_LIGHT_STATES = {
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
}
|
||||
_TARGET_ATTRIBUTES = (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP_KELVIN,
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_TRANSITION,
|
||||
)
|
||||
|
||||
|
||||
def _last_adaptation_values(
|
||||
manager: AdaptiveLightingManager,
|
||||
light: str,
|
||||
) -> dict[str, Any] | None:
|
||||
"""Return latest retained value for each allowlisted adaptation attribute.
|
||||
|
||||
Values may come from different commands because the manager merges partial
|
||||
service data per attribute.
|
||||
"""
|
||||
service_data = manager.last_service_data.get(light)
|
||||
if service_data is None:
|
||||
return None
|
||||
target = {
|
||||
attribute: (
|
||||
list(service_data[attribute])
|
||||
if attribute == ATTR_RGB_COLOR
|
||||
else service_data[attribute]
|
||||
)
|
||||
for attribute in _TARGET_ATTRIBUTES
|
||||
if attribute in service_data
|
||||
}
|
||||
return target or None
|
||||
|
||||
|
||||
def _autoreset_seconds(
|
||||
manager: AdaptiveLightingManager,
|
||||
light: str,
|
||||
) -> float | None:
|
||||
"""Return remaining time for a running global manual-control reset."""
|
||||
timer = manager.auto_reset_manual_control_timers.get(light)
|
||||
if timer is None or not timer.is_running():
|
||||
return None
|
||||
remaining = timer.remaining_time()
|
||||
return round(remaining, 3) if remaining > 0 else None
|
||||
|
||||
|
||||
async def async_get_config_entry_diagnostics(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
) -> dict[str, Any]:
|
||||
"""Return an allowlisted, on-demand snapshot for one config entry."""
|
||||
domain_data = hass.data.get(DOMAIN)
|
||||
if not isinstance(domain_data, dict):
|
||||
return {"loaded": False}
|
||||
entry_data = domain_data.get(config_entry.entry_id)
|
||||
manager = domain_data.get(ATTR_ADAPTIVE_LIGHTING_MANAGER)
|
||||
if not isinstance(entry_data, dict) or not isinstance(
|
||||
manager,
|
||||
AdaptiveLightingManager,
|
||||
):
|
||||
return {"loaded": False}
|
||||
switch = entry_data.get(SWITCH_DOMAIN)
|
||||
if not isinstance(switch, AdaptiveSwitch):
|
||||
return {"loaded": False}
|
||||
|
||||
lights: dict[str, Any] = {}
|
||||
for index, light in enumerate(sorted(switch.lights), start=1):
|
||||
state = hass.states.get(light)
|
||||
state_value = "missing"
|
||||
if state is not None:
|
||||
state_value = (
|
||||
state.state
|
||||
if state.state in _REPORTABLE_LIGHT_STATES
|
||||
else STATE_UNKNOWN
|
||||
)
|
||||
manual_control = manager.get_manual_control_attributes(light)
|
||||
lights[f"light_{index}"] = {
|
||||
"state": state_value,
|
||||
"global_manager_manual_control": {
|
||||
"brightness": bool(
|
||||
manual_control & LightControlAttributes.BRIGHTNESS,
|
||||
),
|
||||
"color": bool(manual_control & LightControlAttributes.COLOR),
|
||||
},
|
||||
"global_manager_autoreset_seconds": _autoreset_seconds(manager, light),
|
||||
"global_manager_last_adaptation_values": _last_adaptation_values(
|
||||
manager,
|
||||
light,
|
||||
),
|
||||
}
|
||||
|
||||
return {
|
||||
"loaded": True,
|
||||
"profile_switches": {
|
||||
"profile": switch.is_on,
|
||||
"adapt_brightness": entry_data[ADAPT_BRIGHTNESS_SWITCH].is_on,
|
||||
"adapt_color": entry_data[ADAPT_COLOR_SWITCH].is_on,
|
||||
"sleep_mode": entry_data[SLEEP_MODE_SWITCH].is_on,
|
||||
},
|
||||
"manager_fact_scope": "global_shared_across_profiles",
|
||||
"lights": lights,
|
||||
}
|
||||
|
|
@ -2623,22 +2623,20 @@ class AdaptiveLightingManager:
|
|||
# Fix for https://github.com/basnijholt/adaptive-lighting/issues/1378
|
||||
state = self.hass.states.get(eid)
|
||||
if state is not None and state.state == STATE_ON:
|
||||
try:
|
||||
switch = _switch_with_lights(
|
||||
self.hass,
|
||||
[eid],
|
||||
expand_light_groups=False,
|
||||
)
|
||||
await self.update_manually_controlled_from_event(
|
||||
switch,
|
||||
eid,
|
||||
force=False,
|
||||
)
|
||||
except NoSwitchFoundError:
|
||||
_LOGGER.debug(
|
||||
"No switch found for entity_id='%s' in 'on' event listener",
|
||||
eid,
|
||||
)
|
||||
switches = _switches_with_lights(
|
||||
self.hass,
|
||||
[eid],
|
||||
expand_light_groups=False,
|
||||
)
|
||||
for switch in switches:
|
||||
# Preserve tracking for a lone profile, including when off.
|
||||
# Shared lights notify each enabled owner using its takeover policy.
|
||||
if switch.is_on or len(switches) == 1:
|
||||
await self.update_manually_controlled_from_event(
|
||||
switch,
|
||||
eid,
|
||||
force=False,
|
||||
)
|
||||
|
||||
timer = self.auto_reset_manual_control_timers.get(eid)
|
||||
if (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue