mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-27 20:34:20 +02:00
* Retroactive review changes for #443 * Move up __init__ * Add test for test_change_switch_settings_service * Add docs * Add test for defaults * Remove unused function * Add skip var * move pylint marker * Refactor validate * Update README.md --------- Co-authored-by: Benjamin Auquite <halomastar@gmail.com>
This commit is contained in:
parent
c05e0cc244
commit
1ca3bf0f6a
5 changed files with 191 additions and 136 deletions
|
|
@ -41,9 +41,6 @@ async def async_setup(hass: HomeAssistant, config: dict[str, Any]):
|
|||
# This will reload any changes the user made to any YAML configurations.
|
||||
await async_setup_reload_service(hass, DOMAIN, PLATFORMS)
|
||||
|
||||
# quickly populate data for change_switch_settings before actually loading integration.
|
||||
# update_services_yaml()
|
||||
|
||||
if DOMAIN in config:
|
||||
for entry in config[DOMAIN]:
|
||||
hass.async_create_task(
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@
|
|||
"iot_class": "calculated",
|
||||
"issue_tracker": "https://github.com/basnijholt/adaptive-lighting/issues",
|
||||
"requirements": [],
|
||||
"version": "1.6.0"
|
||||
"version": "1.7.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,11 +189,6 @@ def _int_to_bytes(i: int, signed: bool = False) -> bytes:
|
|||
return i.to_bytes((bits + 7) // 8, "little", signed=signed)
|
||||
|
||||
|
||||
def int_between(min_int, max_int):
|
||||
"""Return an integer between 'min_int' and 'max_int'."""
|
||||
return vol.All(vol.Coerce(int), vol.Range(min=min_int, max=max_int))
|
||||
|
||||
|
||||
def _short_hash(string: str, length: int = 4) -> str:
|
||||
"""Create a hash of 'string' with length 'length'."""
|
||||
str_hash_bytes = _int_to_bytes(hash(string), signed=True)
|
||||
|
|
@ -365,12 +360,10 @@ async def handle_change_switch_settings(
|
|||
which = data.get(CONF_USE_DEFAULTS, "current")
|
||||
if which == "current": # use whatever we're already using.
|
||||
defaults = switch._current_settings # pylint: disable=protected-access
|
||||
# not needed since validate() does this part for us
|
||||
elif which == "factory": # use actual defaults listed in the documentation
|
||||
defaults = {key: default for key, default, _ in VALIDATION_TUPLES}
|
||||
elif (
|
||||
which == "configuration"
|
||||
): # use whatever's in the config flow or configuration.yaml
|
||||
elif which == "configuration":
|
||||
# use whatever's in the config flow or configuration.yaml
|
||||
defaults = switch._config_backup # pylint: disable=protected-access
|
||||
else:
|
||||
defaults = None
|
||||
|
|
@ -387,15 +380,13 @@ async def handle_change_switch_settings(
|
|||
|
||||
all_lights = switch._lights # pylint: disable=protected-access
|
||||
switch.turn_on_off_listener.reset(*all_lights, reset_manual_control=False)
|
||||
# pylint: disable=protected-access
|
||||
if switch.is_on:
|
||||
await switch._update_attrs_and_maybe_adapt_lights(
|
||||
await switch._update_attrs_and_maybe_adapt_lights( # pylint: disable=protected-access
|
||||
all_lights,
|
||||
transition=switch._initial_transition,
|
||||
force=True,
|
||||
context=switch.create_context("service", parent=service_call.context),
|
||||
)
|
||||
# pylint: enable=protected-access
|
||||
|
||||
|
||||
@callback
|
||||
|
|
@ -509,8 +500,8 @@ async def async_setup_entry(
|
|||
_fire_manual_control_event(this_switch, light, service_call.context)
|
||||
else:
|
||||
this_switch.turn_on_off_listener.reset(*all_lights)
|
||||
# pylint: disable=protected-access
|
||||
if this_switch.is_on:
|
||||
# pylint: disable=protected-access
|
||||
await this_switch._update_attrs_and_maybe_adapt_lights(
|
||||
all_lights,
|
||||
transition=this_switch._initial_transition,
|
||||
|
|
@ -556,9 +547,10 @@ async def async_setup_entry(
|
|||
)
|
||||
|
||||
args = {vol.Optional(CONF_USE_DEFAULTS, default="current"): cv.string}
|
||||
# Modifying these after init isn't possible
|
||||
skip = (CONF_INTERVAL, CONF_NAME, CONF_LIGHTS)
|
||||
for k, _, valid in VALIDATION_TUPLES:
|
||||
# Modifying these after initialization isn't possible (yet)
|
||||
if k != CONF_INTERVAL and k != CONF_NAME and k != CONF_LIGHTS:
|
||||
if k not in skip:
|
||||
args[vol.Optional(k)] = valid
|
||||
platform = entity_platform.current_platform.get()
|
||||
platform.async_register_entity_service(
|
||||
|
|
@ -568,24 +560,24 @@ async def async_setup_entry(
|
|||
)
|
||||
|
||||
|
||||
def validate(config_entry: ConfigEntry, **kwargs):
|
||||
def validate(
|
||||
config_entry: ConfigEntry,
|
||||
service_data: dict[str, Any] | None = None,
|
||||
defaults: dict[str, Any] | None = None,
|
||||
):
|
||||
"""Get the options and data from the config_entry and add defaults."""
|
||||
# defaults and data will exist only if this is called from change_switch_settings
|
||||
defaults = kwargs.get("defaults")
|
||||
service_data = kwargs.get("data")
|
||||
if defaults is None:
|
||||
defaults = {key: default for key, default, _ in VALIDATION_TUPLES}
|
||||
data = {key: default for key, default, _ in VALIDATION_TUPLES}
|
||||
else:
|
||||
data = defaults
|
||||
|
||||
if config_entry is not None:
|
||||
# Is this deepcopy necessary?
|
||||
# We're already creating a new array for the defaults variable...
|
||||
# afterwards defaults is never used again.
|
||||
data = deepcopy(defaults)
|
||||
assert service_data is None
|
||||
assert defaults is None
|
||||
data.update(config_entry.options) # come from options flow
|
||||
data.update(config_entry.data) # all yaml settings come from data
|
||||
else:
|
||||
# no idea how to clear original data from memory
|
||||
# hopefully it does it automatically, otherwise TODO.
|
||||
data = deepcopy(defaults)
|
||||
assert service_data is not None
|
||||
data.update(service_data)
|
||||
data = {key: replace_none_str(value) for key, value in data.items()}
|
||||
for key, (validate_value, _) in EXTRA_VALIDATION.items():
|
||||
|
|
@ -756,67 +748,6 @@ def _attributes_have_changed(
|
|||
class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
||||
"""Representation of a Adaptive Lighting switch."""
|
||||
|
||||
def _set_changeable_settings(
|
||||
self,
|
||||
data: dict,
|
||||
defaults: dict,
|
||||
):
|
||||
# Should only contain the settings we want the users to be able to change during runtime.
|
||||
data = validate(
|
||||
config_entry=None,
|
||||
data=data,
|
||||
defaults=defaults,
|
||||
)
|
||||
|
||||
# backup data for use in change_switch_settings "current" CONF_USE_DEFAULTS
|
||||
self._current_settings = data
|
||||
|
||||
self._detect_non_ha_changes = data[CONF_DETECT_NON_HA_CHANGES]
|
||||
self._include_config_in_attributes = data[CONF_INCLUDE_CONFIG_IN_ATTRIBUTES]
|
||||
self._initial_transition = data[CONF_INITIAL_TRANSITION]
|
||||
self._sleep_transition = data[CONF_SLEEP_TRANSITION]
|
||||
self._only_once = data[CONF_ONLY_ONCE]
|
||||
self._prefer_rgb_color = data[CONF_PREFER_RGB_COLOR]
|
||||
self._separate_turn_on_commands = data[CONF_SEPARATE_TURN_ON_COMMANDS]
|
||||
self._take_over_control = data[CONF_TAKE_OVER_CONTROL]
|
||||
self._transition = data[CONF_TRANSITION]
|
||||
self._adapt_delay = data[CONF_ADAPT_DELAY]
|
||||
self._send_split_delay = data[CONF_SEND_SPLIT_DELAY]
|
||||
_loc = get_astral_location(self.hass)
|
||||
if isinstance(_loc, tuple):
|
||||
# Astral v2.2
|
||||
location, _ = _loc
|
||||
else:
|
||||
# Astral v1
|
||||
location = _loc
|
||||
|
||||
self._sun_light_settings = SunLightSettings(
|
||||
name=self._name,
|
||||
astral_location=location,
|
||||
max_brightness=data[CONF_MAX_BRIGHTNESS],
|
||||
max_color_temp=data[CONF_MAX_COLOR_TEMP],
|
||||
min_brightness=data[CONF_MIN_BRIGHTNESS],
|
||||
min_color_temp=data[CONF_MIN_COLOR_TEMP],
|
||||
sleep_brightness=data[CONF_SLEEP_BRIGHTNESS],
|
||||
sleep_color_temp=data[CONF_SLEEP_COLOR_TEMP],
|
||||
sleep_rgb_color=data[CONF_SLEEP_RGB_COLOR],
|
||||
sleep_rgb_or_color_temp=data[CONF_SLEEP_RGB_OR_COLOR_TEMP],
|
||||
sunrise_offset=data[CONF_SUNRISE_OFFSET],
|
||||
sunrise_time=data[CONF_SUNRISE_TIME],
|
||||
max_sunrise_time=data[CONF_MAX_SUNRISE_TIME],
|
||||
sunset_offset=data[CONF_SUNSET_OFFSET],
|
||||
sunset_time=data[CONF_SUNSET_TIME],
|
||||
min_sunset_time=data[CONF_MIN_SUNSET_TIME],
|
||||
time_zone=self.hass.config.time_zone,
|
||||
transition=data[CONF_TRANSITION],
|
||||
)
|
||||
_LOGGER.debug(
|
||||
"%s: Set switch settings for lights '%s'. now using data: '%s'",
|
||||
self._name,
|
||||
self._lights,
|
||||
data,
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass,
|
||||
|
|
@ -827,8 +758,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
adapt_brightness_switch: SimpleSwitch,
|
||||
):
|
||||
"""Initialize the Adaptive Lighting switch."""
|
||||
# Set attributes we DON'T want users modifying
|
||||
# during runtime here.
|
||||
# Set attributes that can't be modified during runtime
|
||||
self.hass = hass
|
||||
self.turn_on_off_listener = turn_on_off_listener
|
||||
self.sleep_mode_switch = sleep_mode_switch
|
||||
|
|
@ -887,6 +817,67 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
data,
|
||||
)
|
||||
|
||||
def _set_changeable_settings(
|
||||
self,
|
||||
data: dict,
|
||||
defaults: dict,
|
||||
):
|
||||
# Only pass settings users can change during runtime
|
||||
data = validate(
|
||||
config_entry=None,
|
||||
service_data=data,
|
||||
defaults=defaults,
|
||||
)
|
||||
|
||||
# backup data for use in change_switch_settings "current" CONF_USE_DEFAULTS
|
||||
self._current_settings = data
|
||||
|
||||
self._detect_non_ha_changes = data[CONF_DETECT_NON_HA_CHANGES]
|
||||
self._include_config_in_attributes = data[CONF_INCLUDE_CONFIG_IN_ATTRIBUTES]
|
||||
self._initial_transition = data[CONF_INITIAL_TRANSITION]
|
||||
self._sleep_transition = data[CONF_SLEEP_TRANSITION]
|
||||
self._only_once = data[CONF_ONLY_ONCE]
|
||||
self._prefer_rgb_color = data[CONF_PREFER_RGB_COLOR]
|
||||
self._separate_turn_on_commands = data[CONF_SEPARATE_TURN_ON_COMMANDS]
|
||||
self._take_over_control = data[CONF_TAKE_OVER_CONTROL]
|
||||
self._transition = data[CONF_TRANSITION]
|
||||
self._adapt_delay = data[CONF_ADAPT_DELAY]
|
||||
self._send_split_delay = data[CONF_SEND_SPLIT_DELAY]
|
||||
_loc = get_astral_location(self.hass)
|
||||
if isinstance(_loc, tuple):
|
||||
# Astral v2.2
|
||||
location, _ = _loc
|
||||
else:
|
||||
# Astral v1
|
||||
location = _loc
|
||||
|
||||
self._sun_light_settings = SunLightSettings(
|
||||
name=self._name,
|
||||
astral_location=location,
|
||||
max_brightness=data[CONF_MAX_BRIGHTNESS],
|
||||
max_color_temp=data[CONF_MAX_COLOR_TEMP],
|
||||
min_brightness=data[CONF_MIN_BRIGHTNESS],
|
||||
min_color_temp=data[CONF_MIN_COLOR_TEMP],
|
||||
sleep_brightness=data[CONF_SLEEP_BRIGHTNESS],
|
||||
sleep_color_temp=data[CONF_SLEEP_COLOR_TEMP],
|
||||
sleep_rgb_color=data[CONF_SLEEP_RGB_COLOR],
|
||||
sleep_rgb_or_color_temp=data[CONF_SLEEP_RGB_OR_COLOR_TEMP],
|
||||
sunrise_offset=data[CONF_SUNRISE_OFFSET],
|
||||
sunrise_time=data[CONF_SUNRISE_TIME],
|
||||
max_sunrise_time=data[CONF_MAX_SUNRISE_TIME],
|
||||
sunset_offset=data[CONF_SUNSET_OFFSET],
|
||||
sunset_time=data[CONF_SUNSET_TIME],
|
||||
min_sunset_time=data[CONF_MIN_SUNSET_TIME],
|
||||
time_zone=self.hass.config.time_zone,
|
||||
transition=data[CONF_TRANSITION],
|
||||
)
|
||||
_LOGGER.debug(
|
||||
"%s: Set switch settings for lights '%s'. now using data: '%s'",
|
||||
self._name,
|
||||
self._lights,
|
||||
data,
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device if any."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue