From e7d160cba824ef694b6061083770f3b64d718af1 Mon Sep 17 00:00:00 2001 From: xZetsubou Date: Fri, 27 Oct 2023 04:18:17 +0300 Subject: [PATCH 1/4] Initialized msg to `common.py` and del: `dp_value_conf` --- custom_components/localtuya/button.py | 1 - custom_components/localtuya/climate.py | 17 ++- custom_components/localtuya/common.py | 130 ++++++++++------------ custom_components/localtuya/cover.py | 3 +- custom_components/localtuya/fan.py | 6 +- custom_components/localtuya/humidifier.py | 8 +- custom_components/localtuya/light.py | 16 +-- custom_components/localtuya/switch.py | 1 - custom_components/localtuya/vacuum.py | 15 ++- 9 files changed, 90 insertions(+), 107 deletions(-) diff --git a/custom_components/localtuya/button.py b/custom_components/localtuya/button.py index 00f90b39c..6625771c6 100644 --- a/custom_components/localtuya/button.py +++ b/custom_components/localtuya/button.py @@ -33,7 +33,6 @@ def __init__( """Initialize the Tuya button.""" super().__init__(device, config_entry, buttonid, _LOGGER, **kwargs) self._state = None - _LOGGER.debug("Initialized button [%s]", self.name) async def async_press(self): """Press the button.""" diff --git a/custom_components/localtuya/climate.py b/custom_components/localtuya/climate.py index 1010be627..930569452 100644 --- a/custom_components/localtuya/climate.py +++ b/custom_components/localtuya/climate.py @@ -217,7 +217,6 @@ def __init__( self._has_presets = self.has_config(CONF_ECO_DP) or self.has_config( CONF_PRESET_DP ) - _LOGGER.debug("Initialized climate [%s]", self.name) @property def supported_features(self): @@ -375,7 +374,7 @@ async def async_set_preset_mode(self, preset_mode): def min_temp(self): """Return the minimum temperature.""" if _min_temp := self._config.get(CONF_MIN_TEMP_DP): - return self.dp_value_conf(CONF_MIN_TEMP_DP) + return self.dp_value(CONF_MIN_TEMP_DP) # DEFAULT_MIN_TEMP is in C if self.temperature_unit == TEMP_FAHRENHEIT: return DEFAULT_MIN_TEMP * 1.8 + 32 @@ -386,7 +385,7 @@ def min_temp(self): def max_temp(self): """Return the maximum temperature.""" if self.has_config(CONF_MAX_TEMP_DP): - return self.dp_value_conf(CONF_MAX_TEMP_DP) + return self.dp_value(CONF_MAX_TEMP_DP) # DEFAULT_MAX_TEMP is in C if self.temperature_unit == TEMP_FAHRENHEIT: return DEFAULT_MAX_TEMP * 1.8 + 32 @@ -399,23 +398,23 @@ def status_updated(self): if self.has_config(CONF_TARGET_TEMPERATURE_DP): self._target_temperature = ( - self.dp_value_conf(CONF_TARGET_TEMPERATURE_DP) * self._target_precision + self.dp_value(CONF_TARGET_TEMPERATURE_DP) * self._target_precision ) if self.has_config(CONF_CURRENT_TEMPERATURE_DP): self._current_temperature = ( - self.dp_value_conf(CONF_CURRENT_TEMPERATURE_DP) * self._precision + self.dp_value(CONF_CURRENT_TEMPERATURE_DP) * self._precision ) if self._has_presets: if ( self.has_config(CONF_ECO_DP) - and self.dp_value_conf(CONF_ECO_DP) == self._conf_eco_value + and self.dp_value(CONF_ECO_DP) == self._conf_eco_value ): self._preset_mode = PRESET_ECO else: for preset, value in self._conf_preset_set.items(): # todo remove - if self.dp_value_conf(CONF_PRESET_DP) == value: + if self.dp_value(CONF_PRESET_DP) == value: self._preset_mode = preset break else: @@ -427,7 +426,7 @@ def status_updated(self): self._hvac_mode = HVACMode.OFF else: for mode, value in self._conf_hvac_mode_set.items(): - if self.dp_value_conf(CONF_HVAC_MODE_DP) == value: + if self.dp_value(CONF_HVAC_MODE_DP) == value: self._hvac_mode = mode break else: @@ -436,7 +435,7 @@ def status_updated(self): # Update the current action for action, value in self._conf_hvac_action_set.items(): - if self.dp_value_conf(CONF_HVAC_ACTION_DP) == value: + if self.dp_value(CONF_HVAC_ACTION_DP) == value: self._hvac_action = action diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index 58c14c1cf..821739cb3 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -128,7 +128,7 @@ def get_dps_for_platform(flow_schema): yield key.schema -def get_entity_config(config_entry, dp_id): +def get_entity_config(config_entry, dp_id) -> dict: """Return entity config for a given DPS id.""" for entity in config_entry[CONF_ENTITIES]: if entity[CONF_ID] == dp_id: @@ -164,10 +164,10 @@ def __init__( super().__init__() self._hass = hass self._config_entry = config_entry - self._dev_config_entry: dict = config_entry.data[CONF_DEVICES][dev_id].copy() + self._device_config: dict = config_entry.data[CONF_DEVICES][dev_id].copy() self._interface = None # For SubDevices - self._node_id: str = self._dev_config_entry.get(CONF_NODE_ID) + self._node_id: str = self._device_config.get(CONF_NODE_ID) self._fake_gateway = gateway self._gwateway: TuyaDevice = None self._sub_devices = {} @@ -179,9 +179,9 @@ def __init__( self._disconnect_task = None self._unsub_interval = None self._entities = [] - self._local_key = self._dev_config_entry[CONF_LOCAL_KEY] + self._local_key = self._device_config[CONF_LOCAL_KEY] self._default_reset_dpids = None - if reset_dps := self._dev_config_entry.get(CONF_RESET_DPIDS): + if reset_dps := self._device_config.get(CONF_RESET_DPIDS): reset_ids_str = reset_dps.split(",") self._default_reset_dpids = [] @@ -190,12 +190,12 @@ def __init__( self.set_logger( _LOGGER, - self._dev_config_entry.get(CONF_DEVICE_ID), - self._dev_config_entry.get(CONF_ENABLE_DEBUG), + self._device_config.get(CONF_DEVICE_ID), + self._device_config.get(CONF_ENABLE_DEBUG), ) # This has to be done in case the device type is type_0d - for entity in self._dev_config_entry[CONF_ENTITIES]: + for entity in self._device_config[CONF_ENTITIES]: self.dps_to_request[entity[CONF_ID]] = None def add_entities(self, entities): @@ -222,7 +222,7 @@ async def get_gateway(self): if not self._node_id: return entry_id = self._config_entry.entry_id - node_host = self._dev_config_entry.get(CONF_HOST) + node_host = self._device_config.get(CONF_HOST) devices: dict = self._hass.data[DOMAIN][entry_id][TUYA_DEVICES] # Sub to gateway. @@ -248,8 +248,8 @@ async def async_connect(self): async def _make_connection(self): """Subscribe localtuya entity events.""" self._connect_task = True - host = self._dev_config_entry.get(CONF_HOST) - name = self._dev_config_entry.get(CONF_FRIENDLY_NAME) + host = self._device_config.get(CONF_HOST) + name = self._device_config.get(CONF_FRIENDLY_NAME) try: if self.is_subdevice: @@ -263,11 +263,11 @@ async def _make_connection(self): else: # self.info("Trying to connect to %s...", host) self._interface = await pytuya.connect( - self._dev_config_entry[CONF_HOST], - self._dev_config_entry[CONF_DEVICE_ID], + self._device_config[CONF_HOST], + self._device_config[CONF_DEVICE_ID], self._local_key, - float(self._dev_config_entry[CONF_PROTOCOL_VERSION]), - self._dev_config_entry.get(CONF_ENABLE_DEBUG, False), + float(self._device_config[CONF_PROTOCOL_VERSION]), + self._device_config.get(CONF_ENABLE_DEBUG, False), self, ) self._interface.add_dps_to_request(self.dps_to_request) @@ -321,19 +321,19 @@ def _new_entity_handler(entity_id): self.debug("New entity %s was added to %s", entity_id, host) self._dispatch_status() - signal = f"localtuya_entity_{self._dev_config_entry[CONF_DEVICE_ID]}" + signal = f"localtuya_entity_{self._device_config[CONF_DEVICE_ID]}" self._disconnect_task = async_dispatcher_connect( self._hass, signal, _new_entity_handler ) if ( - CONF_SCAN_INTERVAL in self._dev_config_entry - and int(self._dev_config_entry[CONF_SCAN_INTERVAL]) > 0 + CONF_SCAN_INTERVAL in self._device_config + and int(self._device_config[CONF_SCAN_INTERVAL]) > 0 ): self._unsub_interval = async_track_time_interval( self._hass, self._async_refresh, - timedelta(seconds=int(self._dev_config_entry[CONF_SCAN_INTERVAL])), + timedelta(seconds=int(self._device_config[CONF_SCAN_INTERVAL])), ) self._is_closing = False @@ -359,7 +359,7 @@ async def abort_connect(self): async def update_local_key(self): """Retrieve updated local_key from Cloud API and update the config_entry.""" - dev_id = self._dev_config_entry[CONF_DEVICE_ID] + dev_id = self._device_config[CONF_DEVICE_ID] entry_id = self._config_entry.entry_id await self._hass.data[DOMAIN][entry_id][DATA_CLOUD].async_get_devices_list() cloud_devs = self._hass.data[DOMAIN][entry_id][DATA_CLOUD].device_list @@ -393,7 +393,7 @@ async def close(self): self._disconnect_task() self.info( "Closed connection with device %s.", - self._dev_config_entry[CONF_FRIENDLY_NAME], + self._device_config[CONF_FRIENDLY_NAME], ) async def set_dp(self, state, dp_index): @@ -405,7 +405,7 @@ async def set_dp(self, state, dp_index): self.debug("Failed to set DP %d to %s", dp_index, str(state)) else: self.error( - "Not connected to device %s", self._dev_config_entry[CONF_FRIENDLY_NAME] + "Not connected to device %s", self._device_config[CONF_FRIENDLY_NAME] ) async def set_dps(self, states): @@ -417,7 +417,7 @@ async def set_dps(self, states): self.debug("Failed to set DPs %r", states) else: self.error( - "Not connected to device %s", self._dev_config_entry[CONF_FRIENDLY_NAME] + "Not connected to device %s", self._device_config[CONF_FRIENDLY_NAME] ) @callback @@ -432,7 +432,7 @@ def status_updated(self, status: dict): self._dispatch_status() def _dispatch_status(self): - signal = f"localtuya_{self._dev_config_entry[CONF_DEVICE_ID]}" + signal = f"localtuya_{self._device_config[CONF_DEVICE_ID]}" async_dispatcher_send(self._hass, signal, self._status) def _handle_event(self, old_status, new_status, deviceID=None): @@ -440,7 +440,7 @@ def _handle_event(self, old_status, new_status, deviceID=None): def fire_event(event, data: dict): event_data = { - CONF_DEVICE_ID: deviceID or self._dev_config_entry[CONF_DEVICE_ID], + CONF_DEVICE_ID: deviceID or self._device_config[CONF_DEVICE_ID], CONF_TYPE: event, } event_data.update(data) @@ -475,7 +475,7 @@ def fire_event(event, data: dict): @callback def disconnected(self): """Device disconnected.""" - signal = f"localtuya_{self._dev_config_entry[CONF_DEVICE_ID]}" + signal = f"localtuya_{self._device_config[CONF_DEVICE_ID]}" async_dispatcher_send(self._hass, signal, None) if self._unsub_interval is not None: self._unsub_interval() @@ -503,12 +503,14 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): _attr_has_entity_name = True - def __init__(self, device, config_entry, dp_id, logger, **kwargs): + def __init__( + self, device: TuyaDevice, config_entry: dict, dp_id: str, logger, **kwargs + ): """Initialize the Tuya entity.""" super().__init__() - self._device: TuyaDevice = device - self._dev_config_entry = config_entry - self._config: dict = get_entity_config(config_entry, dp_id) + self._device = device + self._device_config = config_entry + self._config = get_entity_config(config_entry, dp_id) self._dp_id = dp_id self._status = {} self._state = None @@ -518,14 +520,13 @@ def __init__(self, device, config_entry, dp_id, logger, **kwargs): self._default_value = self._config.get(CONF_DEFAULT_VALUE) # Determine whether is a passive entity - self._is_passive_entity = self._config.get(CONF_PASSIVE_ENTITY) or False + self._is_passive_entity = self._config.get(CONF_PASSIVE_ENTITY, False) """ Restore on connect setting is available to be provided by Platform entities if required""" - self._restore_on_reconnect = ( - self._config.get(CONF_RESTORE_ON_RECONNECT) or False - ) - self.set_logger(logger, self._dev_config_entry[CONF_DEVICE_ID]) + self._restore_on_reconnect = self._config.get(CONF_RESTORE_ON_RECONNECT, False) + self.set_logger(logger, self._device_config[CONF_DEVICE_ID]) + _LOGGER.debug(f"Initialized {self._config.get(CONF_PLATFORM)} [{self.name}]") async def async_added_to_hass(self): """Subscribe localtuya events.""" @@ -549,13 +550,13 @@ def _update_handler(status): # Update HA self.schedule_update_ha_state() - signal = f"localtuya_{self._dev_config_entry[CONF_DEVICE_ID]}" + signal = f"localtuya_{self._device_config[CONF_DEVICE_ID]}" self.async_on_remove( async_dispatcher_connect(self.hass, signal, _update_handler) ) - signal = f"localtuya_entity_{self._dev_config_entry[CONF_DEVICE_ID]}" + signal = f"localtuya_entity_{self._device_config[CONF_DEVICE_ID]}" async_dispatcher_send(self.hass, signal, self.entity_id) @property @@ -577,16 +578,14 @@ def extra_state_attributes(self): @property def device_info(self): """Return device information for the device registry.""" - model = self._dev_config_entry.get(CONF_MODEL, "Tuya generic") + model = self._device_config.get(CONF_MODEL, "Tuya generic") return { - "identifiers": { - # Serial numbers are unique identifiers within a specific domain - (DOMAIN, f"local_{self._dev_config_entry[CONF_DEVICE_ID]}") - }, - "name": self._dev_config_entry[CONF_FRIENDLY_NAME], + # Serial numbers are unique identifiers within a specific domain + "identifiers": {(DOMAIN, f"local_{self._device_config[CONF_DEVICE_ID]}")}, + "name": self._device_config[CONF_FRIENDLY_NAME], "manufacturer": "Tuya", - "model": f"{model} ({self._dev_config_entry[CONF_DEVICE_ID]})", - "sw_version": self._dev_config_entry[CONF_PROTOCOL_VERSION], + "model": f"{model} ({self._device_config[CONF_DEVICE_ID]})", + "sw_version": self._device_config[CONF_PROTOCOL_VERSION], } @property @@ -597,10 +596,7 @@ def name(self): @property def icon(self) -> str | None: """Icon of the entity.""" - if icon := self._config.get(CONF_ICON, False): - return icon - - return None + return self._config.get(CONF_ICON, None) @property def should_poll(self): @@ -610,7 +606,7 @@ def should_poll(self): @property def unique_id(self): """Return unique device identifier.""" - return f"local_{self._dev_config_entry[CONF_DEVICE_ID]}_{self._dp_id}" + return f"local_{self._device_config[CONF_DEVICE_ID]}_{self._dp_id}" def has_config(self, attr): """Return if a config parameter has a valid value.""" @@ -651,28 +647,22 @@ def device_class(self): """Return the class of this device.""" return self._config.get(CONF_DEVICE_CLASS, None) - def dp_value(self, dp_index): - """Return cached value for DPS index.""" - value = self._status.get(str(dp_index)) - if value is None and not self._dev_config_entry.get(CONF_NODE_ID): - self.warning( - "Entity %s is requesting unknown DPS index %s", - self.entity_id, - dp_index, - ) + def dp_value(self, key): + """Return cached value for DPS index or Entity Config Key.""" + requested_dp = str(key) + # If requested_dp in DP ID, get cached value. + if value := self._status.get(requested_dp): + return value - return value + # If requested_dp is an config key get config dp then get cached value. + if conf_key := self._config.get(requested_dp): + if value := self._status.get(conf_key): + return value - def dp_value_conf(self, conf_item): - """Return DP Value based on config key, If entity has the key.""" - dp_index = self._config.get(conf_item) - if dp_index is None: - self.warning( - "Entity %s is requesting unset index for option %s", - self.entity_id, - conf_item, - ) - return self.dp_value(dp_index) + if value is None: + self.warning(f"{self.entity_id}: is requesting unknown DP Value {key}") + + return value def status_updated(self): """Device status was updated. diff --git a/custom_components/localtuya/cover.py b/custom_components/localtuya/cover.py index 174a8f711..f5355cbd8 100644 --- a/custom_components/localtuya/cover.py +++ b/custom_components/localtuya/cover.py @@ -97,7 +97,6 @@ def __init__(self, device, config_entry, switchid, **kwargs): self._current_cover_position = 0 self._current_state_action = STATE_STOPPED # Default. self._set_new_position = int | None - _LOGGER.debug("Initialized cover [%s]", self.name) @property def supported_features(self): @@ -249,7 +248,7 @@ def status_updated(self): self._stop_cmd = self._stop_cmd.upper() if self.has_config(CONF_CURRENT_POSITION_DP): - curr_pos = self.dp_value_conf(CONF_CURRENT_POSITION_DP) + curr_pos = self.dp_value(CONF_CURRENT_POSITION_DP) if self._config.get(CONF_POSITION_INVERTED): self._current_cover_position = 100 - curr_pos else: diff --git a/custom_components/localtuya/fan.py b/custom_components/localtuya/fan.py index 1c4c2d43d..d6ce192be 100644 --- a/custom_components/localtuya/fan.py +++ b/custom_components/localtuya/fan.py @@ -216,7 +216,7 @@ def status_updated(self): """Get state of Tuya fan.""" self._is_on = self.dp_value(self._dp_id) - current_speed = self.dp_value_conf(CONF_FAN_SPEED_CONTROL) + current_speed = self.dp_value(CONF_FAN_SPEED_CONTROL) if self._use_ordered_list: _LOGGER.debug( "Fan current_speed ordered_list_item_to_percentage: %s from %s", @@ -242,11 +242,11 @@ def status_updated(self): _LOGGER.debug("Fan current_percentage: %s", self._percentage) if self.has_config(CONF_FAN_OSCILLATING_CONTROL): - self._oscillating = self.dp_value_conf(CONF_FAN_OSCILLATING_CONTROL) + self._oscillating = self.dp_value(CONF_FAN_OSCILLATING_CONTROL) _LOGGER.debug("Fan current_oscillating : %s", self._oscillating) if self.has_config(CONF_FAN_DIRECTION): - value = self.dp_value_conf(CONF_FAN_DIRECTION) + value = self.dp_value(CONF_FAN_DIRECTION) if value is not None: if value == self._config.get(CONF_FAN_DIRECTION_FWD): self._direction = DIRECTION_FORWARD diff --git a/custom_components/localtuya/humidifier.py b/custom_components/localtuya/humidifier.py index 2d2e621b9..022503bdf 100644 --- a/custom_components/localtuya/humidifier.py +++ b/custom_components/localtuya/humidifier.py @@ -72,8 +72,6 @@ def __init__( ATTR_MAX_HUMIDITY, DEFAULT_MAX_HUMIDITY ) - _LOGGER.debug("Initialized Humidifier [%s]", self.name) - @property def is_on(self) -> bool: """Return the device is on or off.""" @@ -82,21 +80,21 @@ def is_on(self) -> bool: @property def mode(self) -> str | None: """Return the current mode.""" - return self.dp_value_conf(self._dp_mode) + return self.dp_value(self._dp_mode) @property def target_humidity(self) -> int | None: """Return the humidity we try to reach.""" target_dp = self._config.get(self._dp_set_humidity, None) - return self.dp_value_conf(target_dp) if target_dp else None + return self.dp_value(target_dp) if target_dp else None @property def current_humidity(self) -> int | None: """Return the current humidity.""" curr_humidity = self._config.get(self._dp_current_humidity) - return self.dp_value_conf(self._dp_current_humidity) if curr_humidity else None + return self.dp_value(self._dp_current_humidity) if curr_humidity else None async def async_turn_on(self, **kwargs): """Turn the device on.""" diff --git a/custom_components/localtuya/light.py b/custom_components/localtuya/light.py index 39b79081c..c7d48c970 100644 --- a/custom_components/localtuya/light.py +++ b/custom_components/localtuya/light.py @@ -298,7 +298,7 @@ def is_music_mode(self): return color_mode is not None and color_mode == MODE_MUSIC def __is_color_rgb_encoded(self): - return len(self.dp_value_conf(CONF_COLOR)) > 12 + return len(self.dp_value(CONF_COLOR)) > 12 def __find_scene_by_scene_data(self, data): return next( @@ -308,7 +308,7 @@ def __find_scene_by_scene_data(self, data): def __get_color_mode(self): return ( - self.dp_value_conf(CONF_COLOR_MODE) + self.dp_value(CONF_COLOR_MODE) if self.has_config(CONF_COLOR_MODE) else MODE_WHITE ) @@ -420,10 +420,10 @@ def status_updated(self): supported = self.supported_features self._effect = None if supported & SUPPORT_BRIGHTNESS and self.has_config(CONF_BRIGHTNESS): - self._brightness = self.dp_value_conf(CONF_BRIGHTNESS) + self._brightness = self.dp_value(CONF_BRIGHTNESS) if supported & SUPPORT_COLOR: - color = self.dp_value_conf(CONF_COLOR) + color = self.dp_value(CONF_COLOR) if color is not None and not self.is_white_mode: if self.__is_color_rgb_encoded(): hue = int(color[6:10], 16) @@ -439,16 +439,16 @@ def status_updated(self): self._brightness = value if supported & SUPPORT_COLOR_TEMP: - self._color_temp = self.dp_value_conf(CONF_COLOR_TEMP) + self._color_temp = self.dp_value(CONF_COLOR_TEMP) if self.is_scene_mode and supported & SUPPORT_EFFECT: - if self.dp_value_conf(CONF_COLOR_MODE) != MODE_SCENE: + if self.dp_value(CONF_COLOR_MODE) != MODE_SCENE: self._effect = self.__find_scene_by_scene_data( - self.dp_value_conf(CONF_COLOR_MODE) + self.dp_value(CONF_COLOR_MODE) ) else: self._effect = self.__find_scene_by_scene_data( - self.dp_value_conf(CONF_SCENE) + self.dp_value(CONF_SCENE) ) if self._effect == SCENE_CUSTOM: if SCENE_CUSTOM not in self._effect_list: diff --git a/custom_components/localtuya/switch.py b/custom_components/localtuya/switch.py index 9e7d845c9..0976e70a5 100644 --- a/custom_components/localtuya/switch.py +++ b/custom_components/localtuya/switch.py @@ -57,7 +57,6 @@ def __init__( """Initialize the Tuya switch.""" super().__init__(device, config_entry, switchid, _LOGGER, **kwargs) self._state = None - _LOGGER.debug("Initialized switch [%s]", self.name) @property def is_on(self): diff --git a/custom_components/localtuya/vacuum.py b/custom_components/localtuya/vacuum.py index 4d3c827d1..2ac755fe7 100644 --- a/custom_components/localtuya/vacuum.py +++ b/custom_components/localtuya/vacuum.py @@ -118,7 +118,6 @@ def __init__(self, device, config_entry, switchid, **kwargs): self._fan_speed = "" self._cleaning_mode = "" - _LOGGER.debug("Initialized vacuum [%s]", self.name) @property def supported_features(self): @@ -228,28 +227,28 @@ def status_updated(self): self._state = STATE_CLEANING if self.has_config(CONF_BATTERY_DP): - self._battery_level = self.dp_value_conf(CONF_BATTERY_DP) + self._battery_level = self.dp_value(CONF_BATTERY_DP) self._cleaning_mode = "" if self.has_config(CONF_MODES): - self._cleaning_mode = self.dp_value_conf(CONF_MODE_DP) + self._cleaning_mode = self.dp_value(CONF_MODE_DP) self._attrs[MODE] = self._cleaning_mode self._fan_speed = "" if self.has_config(CONF_FAN_SPEEDS): - self._fan_speed = self.dp_value_conf(CONF_FAN_SPEED_DP) + self._fan_speed = self.dp_value(CONF_FAN_SPEED_DP) if self.has_config(CONF_CLEAN_TIME_DP): - self._attrs[CLEAN_TIME] = self.dp_value_conf(CONF_CLEAN_TIME_DP) + self._attrs[CLEAN_TIME] = self.dp_value(CONF_CLEAN_TIME_DP) if self.has_config(CONF_CLEAN_AREA_DP): - self._attrs[CLEAN_AREA] = self.dp_value_conf(CONF_CLEAN_AREA_DP) + self._attrs[CLEAN_AREA] = self.dp_value(CONF_CLEAN_AREA_DP) if self.has_config(CONF_CLEAN_RECORD_DP): - self._attrs[CLEAN_RECORD] = self.dp_value_conf(CONF_CLEAN_RECORD_DP) + self._attrs[CLEAN_RECORD] = self.dp_value(CONF_CLEAN_RECORD_DP) if self.has_config(CONF_FAULT_DP): - self._attrs[FAULT] = self.dp_value_conf(CONF_FAULT_DP) + self._attrs[FAULT] = self.dp_value(CONF_FAULT_DP) if self._attrs[FAULT] != 0: self._state = STATE_ERROR From ac0d9b77cc9aa9419fdf6fe116586ebfd7662d87 Mon Sep 17 00:00:00 2001 From: xZetsubou Date: Fri, 27 Oct 2023 06:36:13 +0300 Subject: [PATCH 2/4] def should_pull to _attr_should_pull and refactor restore_on_reconnect --- custom_components/localtuya/common.py | 38 +++++++++------------------ 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index 821739cb3..8206d90d7 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -502,6 +502,7 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): """Representation of a Tuya entity.""" _attr_has_entity_name = True + _attr_should_poll = False def __init__( self, device: TuyaDevice, config_entry: dict, dp_id: str, logger, **kwargs @@ -519,12 +520,8 @@ def __init__( # Default value is available to be provided by Platform entities if required self._default_value = self._config.get(CONF_DEFAULT_VALUE) - # Determine whether is a passive entity - self._is_passive_entity = self._config.get(CONF_PASSIVE_ENTITY, False) - """ Restore on connect setting is available to be provided by Platform entities if required""" - self._restore_on_reconnect = self._config.get(CONF_RESTORE_ON_RECONNECT, False) self.set_logger(logger, self._device_config[CONF_DEVICE_ID]) _LOGGER.debug(f"Initialized {self._config.get(CONF_PLATFORM)} [{self.name}]") @@ -598,21 +595,11 @@ def icon(self) -> str | None: """Icon of the entity.""" return self._config.get(CONF_ICON, None) - @property - def should_poll(self): - """Return if platform should poll for updates.""" - return False - @property def unique_id(self): """Return unique device identifier.""" return f"local_{self._device_config[CONF_DEVICE_ID]}_{self._dp_id}" - def has_config(self, attr): - """Return if a config parameter has a valid value.""" - value = self._config.get(attr, "-1") - return value is not None and value != "-1" - @property def available(self): """Return if device is available or not.""" @@ -647,6 +634,11 @@ def device_class(self): """Return the class of this device.""" return self._config.get(CONF_DEVICE_CLASS, None) + def has_config(self, attr): + """Return if a config parameter has a valid value.""" + value = self._config.get(attr, "-1") + return value is not None and value != "-1" + def dp_value(self, key): """Return cached value for DPS index or Entity Config Key.""" requested_dp = str(key) @@ -709,23 +701,17 @@ def entity_default_value(self): # pylint: disable=no-self-use """ return 0 - @property - def restore_on_reconnect(self): - """Return whether the last state should be restored on a reconnect. - - Useful where the device loses settings if powered off - """ - return self._restore_on_reconnect - async def restore_state_when_connected(self): """Restore if restore_on_reconnect is set, or if no status has been yet found. Which indicates a DPS that needs to be set before it starts returning status. """ - if (not self.restore_on_reconnect) and ( - (str(self._dp_id) in self._status) or (not self._is_passive_entity) - ): + restore_on_reconnect = self._config.get(CONF_RESTORE_ON_RECONNECT, False) + passive_entity = self._config.get(CONF_PASSIVE_ENTITY, False) + dp_id = str(self._dp_id) + + if not restore_on_reconnect and (dp_id in self._status or not passive_entity): self.debug( "Entity %s (DP %d) - Not restoring as restore on reconnect is " + "disabled for this entity and the entity has an initial status " @@ -746,7 +732,7 @@ async def restore_state_when_connected(self): # If no current or saved state, then use the default value if restore_state is None: - if self._is_passive_entity: + if passive_entity: self.debug("No last restored state - using default") restore_state = self.default_value() else: From c13b9a001b44470587b6938933c91bc2c04bd297 Mon Sep 17 00:00:00 2001 From: xZetsubou Date: Fri, 27 Oct 2023 06:55:41 +0300 Subject: [PATCH 3/4] refactor entity category --- custom_components/localtuya/common.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index 8206d90d7..cd840110f 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -608,19 +608,11 @@ def available(self): @property def entity_category(self) -> str: """Return the category of the entity.""" - if self.has_config(CONF_ENTITY_CATEGORY): - category = self._config[CONF_ENTITY_CATEGORY] - if EntityCategory.CONFIG in category: - category = EntityCategory.CONFIG - elif EntityCategory.DIAGNOSTIC in category: - category = EntityCategory.DIAGNOSTIC - else: - category = None - return category + if category := self._config.get(CONF_ENTITY_CATEGORY): + return EntityCategory(category) if category != "None" else None else: # Set Default values for unconfigured devices. - if self.has_config(CONF_PLATFORM): - platform = self._config.get(CONF_PLATFORM) + if platform := self._config.get(CONF_PLATFORM): # Call default_category from config_flow to set default values! # This will be removed after a while, this is only made to convert who came from main integration. # new users will be forced to choose category from config_flow. From 0ddd0fd658a6b0e15654fc62537a3e035c6c4820 Mon Sep 17 00:00:00 2001 From: xZetsubou Date: Fri, 27 Oct 2023 09:00:45 +0300 Subject: [PATCH 4/4] Refactor: `device_info` and properties annotation --- custom_components/localtuya/common.py | 32 ++++++++++++++------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index cd840110f..89d2232c9 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -24,6 +24,7 @@ CONF_ICON, ) from homeassistant.core import callback +from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.dispatcher import ( async_dispatcher_connect, async_dispatcher_send, @@ -573,20 +574,21 @@ def extra_state_attributes(self): return attributes @property - def device_info(self): + def device_info(self) -> DeviceInfo: """Return device information for the device registry.""" model = self._device_config.get(CONF_MODEL, "Tuya generic") - return { + + return DeviceInfo( # Serial numbers are unique identifiers within a specific domain - "identifiers": {(DOMAIN, f"local_{self._device_config[CONF_DEVICE_ID]}")}, - "name": self._device_config[CONF_FRIENDLY_NAME], - "manufacturer": "Tuya", - "model": f"{model} ({self._device_config[CONF_DEVICE_ID]})", - "sw_version": self._device_config[CONF_PROTOCOL_VERSION], - } + identifiers={(DOMAIN, f"local_{self._device_config[CONF_DEVICE_ID]}")}, + name=self._device_config[CONF_FRIENDLY_NAME], + manufacturer="Tuya", + model=f"{model} ({self._device_config[CONF_DEVICE_ID]})", + sw_version=self._device_config[CONF_PROTOCOL_VERSION], + ) @property - def name(self): + def name(self) -> str: """Get name of Tuya entity.""" return self._config.get(CONF_FRIENDLY_NAME) @@ -596,12 +598,12 @@ def icon(self) -> str | None: return self._config.get(CONF_ICON, None) @property - def unique_id(self): + def unique_id(self) -> str: """Return unique device identifier.""" return f"local_{self._device_config[CONF_DEVICE_ID]}_{self._dp_id}" @property - def available(self): + def available(self) -> bool: """Return if device is available or not.""" return str(self._dp_id) in self._status @@ -626,7 +628,7 @@ def device_class(self): """Return the class of this device.""" return self._config.get(CONF_DEVICE_CLASS, None) - def has_config(self, attr): + def has_config(self, attr) -> bool: """Return if a config parameter has a valid value.""" value = self._config.get(attr, "-1") return value is not None and value != "-1" @@ -648,7 +650,7 @@ def dp_value(self, key): return value - def status_updated(self): + def status_updated(self) -> None: """Device status was updated. Override in subclasses and update entity specific state. @@ -661,7 +663,7 @@ def status_updated(self): if (state is not None) and (not self._device.is_connecting): self._last_state = state - def status_restored(self, stored_state): + def status_restored(self, stored_state) -> None: """Device status was restored. Override in subclasses and update entity specific state. @@ -693,7 +695,7 @@ def entity_default_value(self): # pylint: disable=no-self-use """ return 0 - async def restore_state_when_connected(self): + async def restore_state_when_connected(self) -> None: """Restore if restore_on_reconnect is set, or if no status has been yet found. Which indicates a DPS that needs to be set before it starts returning