diff --git a/custom_components/home_connect_alt/manifest.json b/custom_components/home_connect_alt/manifest.json index b2cd48c..8f12099 100644 --- a/custom_components/home_connect_alt/manifest.json +++ b/custom_components/home_connect_alt/manifest.json @@ -16,6 +16,6 @@ "requirements": ["home-connect-async==0.8.0"], "loggers": ["home_connect_alt", "home_connect_async"], "ssdp": [], - "version": "1.1.1", + "version": "1.1.2", "zeroconf": [] } \ No newline at end of file diff --git a/custom_components/home_connect_alt/select.py b/custom_components/home_connect_alt/select.py index f8e48ed..a9c87b7 100644 --- a/custom_components/home_connect_alt/select.py +++ b/custom_components/home_connect_alt/select.py @@ -1,6 +1,7 @@ """ Implement the Select entities of this implementation """ from __future__ import annotations import logging +from custom_components.home_connect_alt.time import DelayedOperationTime from home_connect_async import Appliance, HomeConnect, HomeConnectError, Events, ConditionalLogger as CL from homeassistant.components.select import SelectEntity from homeassistant.core import HomeAssistant @@ -32,13 +33,14 @@ def add_appliance(appliance:Appliance) -> None: for program in appliance.available_programs.values(): if program.options: for option in program.options.values(): - if conf.get_entity_setting(option.key, "type") == "DelayedOperation" and entry_conf[CONF_DELAYED_OPS] == CONF_DELAYED_OPS_DEFAULT: + if conf.get_entity_setting(option.key, "type") == "DelayedOperation" and ( + entry_conf[CONF_DELAYED_OPS] == CONF_DELAYED_OPS_DEFAULT or not DelayedOperationTime.has_program_run_time(appliance)): device = DelayedOperationSelect(appliance, option.key, conf, option) # remove the TIME delayed operation entity if it exists reg = async_get(hass) - select_entity = reg.async_get_entity_id("time", DOMAIN, device.unique_id) - if select_entity: - reg.async_remove(select_entity) + time_entity = reg.async_get_entity_id("time", DOMAIN, device.unique_id) + if time_entity: + reg.async_remove(time_entity) entity_manager.add(device) elif option.allowedvalues and len(option.allowedvalues)>1: diff --git a/custom_components/home_connect_alt/time.py b/custom_components/home_connect_alt/time.py index 2e6d9c1..6bc7379 100644 --- a/custom_components/home_connect_alt/time.py +++ b/custom_components/home_connect_alt/time.py @@ -28,7 +28,9 @@ def add_appliance(appliance:Appliance) -> None: for program in appliance.available_programs.values(): if program.options: for option in program.options.values(): - if conf.get_entity_setting(option.key, "type") == "DelayedOperation" and entry_conf[CONF_DELAYED_OPS]==CONF_DELAYED_OPS_ABSOLUTE_TIME: + if conf.get_entity_setting(option.key, "type") == "DelayedOperation" \ + and entry_conf[CONF_DELAYED_OPS]==CONF_DELAYED_OPS_ABSOLUTE_TIME \ + and DelayedOperationTime.has_program_run_time(appliance): device = DelayedOperationTime(appliance, option.key, conf, option) # remove the SELECT delayed operation entity if it exists reg = async_get(hass) @@ -54,8 +56,7 @@ class DelayedOperationTime(InteractiveEntityBase, TimeEntity): def __init__(self, appliance: Appliance, key: str = None, conf: dict = None, hc_obj = None) -> None: super().__init__(appliance, key, conf, hc_obj) - self._current:time = self.init_time() - + self._current:time = None @property def name_ext(self) -> str|None: return self._hc_obj.name if self._hc_obj.name else "Delayed operation" @@ -69,7 +70,7 @@ def icon(self) -> str: def available(self) -> bool: # We must have the program run time for this entity to work - available = super().program_option_available and self.get_program_run_time() is not None + available = super().program_option_available and self.get_program_run_time(self._appliance) is not None if not available: self._appliance.clear_startonly_option(self._key) @@ -84,13 +85,17 @@ async def async_set_value(self, value: time) -> None: @property def native_value(self) -> time: """Return the entity value to represent the entity state.""" + if self._current is None: + self._current = self.init_time() + if self._appliance.startonly_options and self._key in self._appliance.startonly_options: self._current = self.adjust_time(self._current, True) else: self._current = self.adjust_time(self._current, False) return self._current - def adjust_time(self, t:time, set_option:bool) -> time: + + def adjust_time(self, t:time, set_option:bool) -> time|None: now = datetime.datetime.now() endtime = datetime.datetime(year=now.year, month=now.month, day=now.day, hour=t.hour, minute=t.minute) @@ -99,7 +104,10 @@ def adjust_time(self, t:time, set_option:bool) -> time: # if the specified time is smaller than now then it means tomorrow endtime += datetime.timedelta(days=1) - program_run_time = self.get_program_run_time() + program_run_time = self.get_program_run_time(self._appliance) + + if not program_run_time: + return None if endtime < now + timedelta(seconds=program_run_time): # the set end time is closer then the program run time so change it to the expected end of the program @@ -129,23 +137,26 @@ def init_time(self) -> time: t = time(hour=inittime.hour, minute=inittime.minute) return self.adjust_time(t, False) - def get_program_run_time(self) -> int|None: - - # There seems to be a bug in HC which returns the remaining time for the previous program when there isn't an dactive one - prog_time_option = self._appliance.get_applied_program_option("BSH.Common.Option.RemainingProgramTime") - if prog_time_option and self._appliance.active_program: - return prog_time_option.value + @classmethod + def get_program_run_time(cls, appliance:Appliance) -> int|None: - prog_time_option = self._appliance.get_applied_program_option("BSH.Common.Option.FinishInRelative") - if prog_time_option: - return prog_time_option.value + time_option_keys = [ + "BSH.Common.Option.RemainingProgramTime", + "BSH.Common.Option.FinishInRelative", + "BSH.Common.Option.EstimatedTotalProgramTime", + ] - prog_time_option = self._appliance.get_applied_program_option("BSH.Common.Option.EstimatedTotalProgramTime") - if prog_time_option: - return prog_time_option.value + for key in time_option_keys: + o = appliance.get_applied_program_option(key) + if o: + return o return None + @classmethod + def has_program_run_time(cls, appliance:Appliance) ->bool: + return cls.get_program_run_time(appliance) is not None + async def async_on_update(self, appliance:Appliance, key:str, value) -> None: # reset the end time clock when a different program is selected