From 364569bad8bf928b3b3b55cf056bab89bb3b2b59 Mon Sep 17 00:00:00 2001 From: sibowler Date: Wed, 13 Jul 2022 20:35:42 +1000 Subject: [PATCH 01/11] Rebase from upstream --- custom_components/localtuya/binary_sensor.py | 7 ++ custom_components/localtuya/common.py | 117 +++++++++++++++++- custom_components/localtuya/config_flow.py | 22 ++++ custom_components/localtuya/const.py | 16 +++ custom_components/localtuya/cover.py | 1 + custom_components/localtuya/number.py | 26 ++-- custom_components/localtuya/select.py | 32 ++++- custom_components/localtuya/sensor.py | 5 + custom_components/localtuya/switch.py | 17 ++- .../localtuya/translations/en.json | 10 +- 10 files changed, 235 insertions(+), 18 deletions(-) diff --git a/custom_components/localtuya/binary_sensor.py b/custom_components/localtuya/binary_sensor.py index 1a3d28a..0011c2f 100644 --- a/custom_components/localtuya/binary_sensor.py +++ b/custom_components/localtuya/binary_sensor.py @@ -52,6 +52,8 @@ class LocaltuyaBinarySensor(LocalTuyaEntity, BinarySensorEntity): return self._config.get(CONF_DEVICE_CLASS) def status_updated(self): + super().status_updated() + """Device status was updated.""" state = str(self.dps(self._dp_id)).lower() if state == self._config[CONF_STATE_ON].lower(): @@ -63,6 +65,11 @@ class LocaltuyaBinarySensor(LocalTuyaEntity, BinarySensorEntity): "State for entity %s did not match state patterns", self.entity_id ) + # No need to restore state for a sensor + async def restore_state_when_connected(self): + """Do nothing for a sensor""" + return + async_setup_entry = partial( async_setup_entry, DOMAIN, LocaltuyaBinarySensor, flow_schema diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index 79eadc9..1dcdee0 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -13,6 +13,7 @@ from homeassistant.const import ( CONF_ID, CONF_PLATFORM, CONF_SCAN_INTERVAL, + STATE_UNKNOWN, ) from homeassistant.core import callback from homeassistant.helpers.dispatcher import ( @@ -31,6 +32,9 @@ from .const import ( DATA_CLOUD, DOMAIN, TUYA_DEVICES, + CONF_DEFAULT_VALUE, + ATTR_STATE, + CONF_RESTORE_ON_RECONNECT, ) _LOGGER = logging.getLogger(__name__) @@ -91,6 +95,8 @@ async def async_setup_entry( entity_config[CONF_ID], ) ) + #Once the entities have been created, add to the TuyaDevice instance + tuyainterface.add_entities(entities) async_add_entities(entities) @@ -135,6 +141,7 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): self._connect_task = None self._disconnect_task = None self._unsub_interval = None + self._entities = [] self._local_key = self._dev_config_entry[CONF_LOCAL_KEY] self.set_logger(_LOGGER, self._dev_config_entry[CONF_DEVICE_ID]) @@ -142,6 +149,10 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): for entity in self._dev_config_entry[CONF_ENTITIES]: self.dps_to_request[entity[CONF_ID]] = None + def add_entities(self, entities): + """Set the entities associated with this device""" + self._entities.extend(entities) + @property def connected(self): """Return if connected to device.""" @@ -173,6 +184,10 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): self.status_updated(status) + # Attempt to restore status for all entites that need to first set the DPS value before the device will respond with status. + for entity in self._entities: + await entity.restore_state_when_connected() + def _new_entity_handler(entity_id): self.debug( "New entity %s was added to %s", @@ -254,7 +269,7 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): try: await self._interface.set_dp(state, dp_index) except Exception: # pylint: disable=broad-except - self.exception("Failed to set DP %d to %d", dp_index, state) + self.exception("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] @@ -305,6 +320,16 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): self._config = get_entity_config(config_entry, dp_id) self._dp_id = dp_id self._status = {} + self._state = None + self._last_state = None + + #Default value is available to be provided by Platform entities if required + self._default_value = self._config.get(CONF_DEFAULT_VALUE) + + #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]) async def async_added_to_hass(self): @@ -325,6 +350,8 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): self._status = status.copy() if status: self.status_updated() + + # Update HA self.schedule_update_ha_state() signal = f"localtuya_{self._dev_config_entry[CONF_DEVICE_ID]}" @@ -336,6 +363,20 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): signal = f"localtuya_entity_{self._dev_config_entry[CONF_DEVICE_ID]}" async_dispatcher_send(self.hass, signal, self.entity_id) + @property + def extra_state_attributes(self): + """Return entity specific state attributes to be saved & then available for restore + when the entity is restored at startup. + """ + attributes = {} + if self._state is not None: + attributes[ATTR_STATE] = self._state + elif self._last_state is not None: + attributes[ATTR_STATE] = self._last_state + + self.debug("Entity %s - Additional attributes: %s", self.name, attributes) + return attributes + @property def device_info(self): """Return device information for the device registry.""" @@ -408,9 +449,83 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): Override in subclasses and update entity specific state. """ + state = self.dps(self._dp_id) + self._state = state + + # Keep record in last_state as long as not during connection/re-connection, + # as last state will be used to restore the previous state + if (state is not None) and (self._device._connect_task is None): + self._last_state = state def status_restored(self, stored_state): """Device status was restored. Override in subclasses and update entity specific state. """ + raw_state = stored_state.attributes.get(ATTR_STATE) + if raw_state is not None: + # (stored_state.state == "unavailable") | (stored_state.state == "unknown") + # ): + self._last_state = raw_state + self.debug( + "Restoring state for entity: %s - state: %s", + self.name, + str(self._last_state), + ) + + def default_value(self): + """Default value of this entity + + Override in subclasses to specify the default value for the entity. + """ + # Check if default value has been set - if not, default to the entity defaults. + if self._default_value is None: + self._default_value = self.entity_default_value() + + return self._default_value + + def entity_default_value(self): + """Default value of the entity type + + Override in subclasses to specify the default value for the entity. + """ + return 0 + + @property + def restore_on_reconnect(self): + """Returns 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): + self.debug( + "Entity %s (DP %d) - Not restoring as restore on reconnect is disabled for this entity and the entity has an initial status", + self.name, + self._dp_id, + ) + return + + self.debug("Attempting to restore state for entity: %s", self.name) + # Attempt to restore the current state - in case reset. + restore_state = self._state + + # If no state stored in the entity currently, go from last saved state + if (restore_state == STATE_UNKNOWN) | (restore_state is None): + self.debug("No current state for entity") + restore_state = self._last_state + + # If no current or saved state, then use the default value + if restore_state is None: + self.debug("No last restored state - using default") + restore_state = self.default_value() + + self.debug( + "Entity %s (DP %d) - Restoring state: %s", + self.name, + self._dp_id, + str(restore_state), + ) + + # Manually initialise + await self._device.set_dp(restore_state, self._dp_id) diff --git a/custom_components/localtuya/config_flow.py b/custom_components/localtuya/config_flow.py index 695baa9..203c0c6 100644 --- a/custom_components/localtuya/config_flow.py +++ b/custom_components/localtuya/config_flow.py @@ -44,6 +44,7 @@ from .const import ( DATA_DISCOVERY, DOMAIN, PLATFORMS, + CONF_MANUAL_DPS, ) from .discovery import discover @@ -88,6 +89,7 @@ CONFIGURE_DEVICE_SCHEMA = vol.Schema( vol.Required(CONF_DEVICE_ID): str, vol.Required(CONF_PROTOCOL_VERSION, default="3.3"): vol.In(["3.1", "3.3"]), vol.Optional(CONF_SCAN_INTERVAL): int, + vol.Optional(CONF_MANUAL_DPS): str, } ) @@ -99,6 +101,7 @@ DEVICE_SCHEMA = vol.Schema( vol.Required(CONF_FRIENDLY_NAME): cv.string, vol.Required(CONF_PROTOCOL_VERSION, default="3.3"): vol.In(["3.1", "3.3"]), vol.Optional(CONF_SCAN_INTERVAL): int, + vol.Optional(CONF_MANUAL_DPS): cv.string, } ) @@ -140,6 +143,7 @@ def options_schema(entities): vol.Required(CONF_LOCAL_KEY): str, vol.Required(CONF_PROTOCOL_VERSION, default="3.3"): vol.In(["3.1", "3.3"]), vol.Optional(CONF_SCAN_INTERVAL): int, + vol.Optional(CONF_MANUAL_DPS): str, vol.Required( CONF_ENTITIES, description={"suggested_value": entity_names} ): cv.multi_select(entity_names), @@ -240,6 +244,22 @@ async def validate_input(hass: core.HomeAssistant, data): ) detected_dps = await interface.detect_available_dps() + + # if manual DPs are set, merge these. + _LOGGER.debug("Detected DPS: %s", detected_dps) + if CONF_MANUAL_DPS in data: + + manual_dps_list = data[CONF_MANUAL_DPS].split(",") + _LOGGER.debug( + "Manual DPS Setting: %s (%s)", data[CONF_MANUAL_DPS], manual_dps_list + ) + # merge the lists + for new_dps in manual_dps_list: + # trim off any whitespace + new_dps = new_dps.strip() + if new_dps not in detected_dps: + detected_dps[new_dps] = -1 + except (ConnectionRefusedError, ConnectionResetError) as ex: raise CannotConnect from ex except ValueError as ex: @@ -253,6 +273,8 @@ async def validate_input(hass: core.HomeAssistant, data): if not detected_dps: raise EmptyDpsList + _LOGGER.debug("Total DPS: %s", detected_dps) + return dps_string_list(detected_dps) diff --git a/custom_components/localtuya/const.py b/custom_components/localtuya/const.py index c940304..993a1f1 100644 --- a/custom_components/localtuya/const.py +++ b/custom_components/localtuya/const.py @@ -35,11 +35,14 @@ CONF_PRODUCT_KEY = "product_key" CONF_PRODUCT_NAME = "product_name" CONF_USER_ID = "user_id" + CONF_ACTION = "action" CONF_ADD_DEVICE = "add_device" CONF_EDIT_DEVICE = "edit_device" CONF_SETUP_CLOUD = "setup_cloud" CONF_NO_CLOUD = "no_cloud" +CONF_MANUAL_DPS = "manual_dps_strings" +CONF_DEFAULT_VALUE = "dps_default_value" # light CONF_BRIGHTNESS_LOWER = "brightness_lower" @@ -113,3 +116,16 @@ CONF_FAULT_DP = "fault_dp" CONF_PAUSED_STATE = "paused_state" CONF_RETURN_MODE = "return_mode" CONF_STOP_STATUS = "stop_status" + +# number +CONF_MIN_VALUE = "min_value" +CONF_MAX_VALUE = "max_value" +CONF_STEPSIZE_VALUE = "step_size" + +# select +CONF_OPTIONS = "select_options" +CONF_OPTIONS_FRIENDLY = "select_options_friendly" + +# States +ATTR_STATE = "raw_state" +CONF_RESTORE_ON_RECONNECT = "restore_on_reconnect" diff --git a/custom_components/localtuya/cover.py b/custom_components/localtuya/cover.py index 2a3eb8b..d8e426f 100644 --- a/custom_components/localtuya/cover.py +++ b/custom_components/localtuya/cover.py @@ -189,6 +189,7 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity): self.debug("Restored cover position %s", self._current_cover_position) def status_updated(self): + super.status_updated(self) """Device status was updated.""" self._previous_state = self._state self._state = self.dps(self._dp_id) diff --git a/custom_components/localtuya/number.py b/custom_components/localtuya/number.py index 596eb01..eae033f 100644 --- a/custom_components/localtuya/number.py +++ b/custom_components/localtuya/number.py @@ -5,13 +5,19 @@ from functools import partial import voluptuous as vol from homeassistant.components.number import DOMAIN, NumberEntity from homeassistant.const import CONF_DEVICE_CLASS, STATE_UNKNOWN +from homeassistant.helpers.restore_state import RestoreEntity from .common import LocalTuyaEntity, async_setup_entry _LOGGER = logging.getLogger(__name__) -CONF_MIN_VALUE = "min_value" -CONF_MAX_VALUE = "max_value" +from .const import ( + CONF_DEFAULT_VALUE, + CONF_MIN_VALUE, + CONF_MAX_VALUE, + CONF_DEFAULT_VALUE, + CONF_RESTORE_ON_RECONNECT, +) DEFAULT_MIN = 0 DEFAULT_MAX = 100000 @@ -28,10 +34,12 @@ def flow_schema(dps): vol.Coerce(float), vol.Range(min=-1000000.0, max=1000000.0), ), + vol.Optional(CONF_DEFAULT_VALUE): str, + vol.Required(CONF_RESTORE_ON_RECONNECT): bool, } -class LocaltuyaNumber(LocalTuyaEntity, NumberEntity): +class LocaltuyaNumber(LocalTuyaEntity, NumberEntity, RestoreEntity): """Representation of a Tuya Number.""" def __init__( @@ -51,6 +59,11 @@ class LocaltuyaNumber(LocalTuyaEntity, NumberEntity): self._max_value = self._config.get(CONF_MAX_VALUE) + #Override standard default value handling to cast to a float + default_value = self._config.get(CONF_DEFAULT_VALUE) + if default_value is not None: + self._default_value = float(default_value) + @property def value(self) -> float: """Return sensor state.""" @@ -75,10 +88,9 @@ class LocaltuyaNumber(LocalTuyaEntity, NumberEntity): """Update the current value.""" await self._device.set_dp(value, self._dp_id) - def status_updated(self): - """Device status was updated.""" - state = self.dps(self._dp_id) - self._state = state + # Default value is the minimum value + def entity_default_value(self): + return self._min_value async_setup_entry = partial(async_setup_entry, DOMAIN, LocaltuyaNumber, flow_schema) diff --git a/custom_components/localtuya/select.py b/custom_components/localtuya/select.py index 29d11c9..71f98cb 100644 --- a/custom_components/localtuya/select.py +++ b/custom_components/localtuya/select.py @@ -4,14 +4,21 @@ from functools import partial import voluptuous as vol from homeassistant.components.select import DOMAIN, SelectEntity -from homeassistant.const import CONF_DEVICE_CLASS, STATE_UNKNOWN +from homeassistant.const import ( + CONF_DEVICE_CLASS, + STATE_UNKNOWN, +) from .common import LocalTuyaEntity, async_setup_entry _LOGGER = logging.getLogger(__name__) -CONF_OPTIONS = "select_options" -CONF_OPTIONS_FRIENDLY = "select_options_friendly" +from .const import ( + CONF_OPTIONS, + CONF_OPTIONS_FRIENDLY, + CONF_DEFAULT_VALUE, + CONF_RESTORE_ON_RECONNECT, +) def flow_schema(dps): @@ -19,6 +26,8 @@ def flow_schema(dps): return { vol.Required(CONF_OPTIONS): str, vol.Optional(CONF_OPTIONS_FRIENDLY): str, + vol.Optional(CONF_DEFAULT_VALUE): str, + vol.Required(CONF_RESTORE_ON_RECONNECT): bool, } @@ -91,10 +100,23 @@ class LocaltuyaSelect(LocalTuyaEntity, SelectEntity): await self._device.set_dp(option_value, self._dp_id) def status_updated(self): + super().status_updated() """Device status was updated.""" state = self.dps(self._dp_id) - self._state_friendly = self._display_options[self._valid_options.index(state)] - self._state = state + + # Check that received status update for this entity. + if state is not None: + try: + self._state_friendly = self._display_options[ + self._valid_options.index(state) + ] + except Exception: # pylint: disable=broad-except + # Friendly value couldn't be mapped + self._state_friendly = state + + # Default value is the first option + def entity_default_value(self): + return self._valid_options[0] async_setup_entry = partial(async_setup_entry, DOMAIN, LocaltuyaSelect, flow_schema) diff --git a/custom_components/localtuya/sensor.py b/custom_components/localtuya/sensor.py index c8b2ddb..e769f4e 100644 --- a/custom_components/localtuya/sensor.py +++ b/custom_components/localtuya/sensor.py @@ -66,5 +66,10 @@ class LocaltuyaSensor(LocalTuyaEntity): state = round(state * scale_factor, DEFAULT_PRECISION) self._state = state + # No need to restore state for a sensor + async def restore_state_when_connected(self): + """Do nothing for a sensor""" + return + async_setup_entry = partial(async_setup_entry, DOMAIN, LocaltuyaSensor, flow_schema) diff --git a/custom_components/localtuya/switch.py b/custom_components/localtuya/switch.py index e884095..c448ff5 100644 --- a/custom_components/localtuya/switch.py +++ b/custom_components/localtuya/switch.py @@ -10,9 +10,12 @@ from .const import ( ATTR_CURRENT, ATTR_CURRENT_CONSUMPTION, ATTR_VOLTAGE, + ATTR_STATE, CONF_CURRENT, CONF_CURRENT_CONSUMPTION, CONF_VOLTAGE, + CONF_DEFAULT_VALUE, + CONF_RESTORE_ON_RECONNECT, ) _LOGGER = logging.getLogger(__name__) @@ -24,6 +27,8 @@ def flow_schema(dps): vol.Optional(CONF_CURRENT): vol.In(dps), vol.Optional(CONF_CURRENT_CONSUMPTION): vol.In(dps), vol.Optional(CONF_VOLTAGE): vol.In(dps), + vol.Optional(CONF_DEFAULT_VALUE): str, + vol.Required(CONF_RESTORE_ON_RECONNECT): bool, } @@ -59,6 +64,12 @@ class LocaltuyaSwitch(LocalTuyaEntity, SwitchEntity): ) if self.has_config(CONF_VOLTAGE): attrs[ATTR_VOLTAGE] = self.dps(self._config[CONF_VOLTAGE]) / 10 + + # Store the state + if self._state is not None: + attrs[ATTR_STATE] = self._state + elif self._last_state is not None: + attrs[ATTR_STATE] = self._last_state return attrs async def async_turn_on(self, **kwargs): @@ -69,9 +80,9 @@ class LocaltuyaSwitch(LocalTuyaEntity, SwitchEntity): """Turn Tuya switch off.""" await self._device.set_dp(False, self._dp_id) - def status_updated(self): - """Device status was updated.""" - self._state = self.dps(self._dp_id) + # Default value is the "OFF" state + def entity_default_value(self): + return False async_setup_entry = partial(async_setup_entry, DOMAIN, LocaltuyaSwitch, flow_schema) diff --git a/custom_components/localtuya/translations/en.json b/custom_components/localtuya/translations/en.json index 82f4064..a97f120 100644 --- a/custom_components/localtuya/translations/en.json +++ b/custom_components/localtuya/translations/en.json @@ -96,7 +96,8 @@ "local_key": "Local key", "protocol_version": "Protocol Version", "scan_interval": "Scan interval (seconds, only when not updating automatically)", - "entities": "Entities (uncheck an entity to remove it)" + "entities": "Entities (uncheck an entity to remove it)", + "manual_dps_strings": "Manual DPS to add (separated by commas ',') - used when detection is not working (optional)" } }, "pick_entity_type": { @@ -181,7 +182,12 @@ "preset_set": "Presets Set (optional)", "eco_dp": "Eco DP (optional)", "eco_value": "Eco value (optional)", - "heuristic_action": "Enable heuristic action (optional)" + "heuristic_action": "Enable heuristic action (optional)", + "dps_default_value": "Default value when un-initialised (optional)", + "restore_on_reconnect": "Restore the last set value in HomeAssistant after a lost connection", + "min_value": "Minimum Value", + "max_value": "Maximum Value", + "step_size": "Minimum increment between numbers" } } } From 0fe550576a306f9f93e356554628f4fdd9e7a8fd Mon Sep 17 00:00:00 2001 From: sibowler Date: Thu, 14 Jul 2022 06:29:56 +1000 Subject: [PATCH 02/11] Fix NumberEntity HA changes and add step control --- custom_components/localtuya/common.py | 6 ++--- custom_components/localtuya/number.py | 32 +++++++++++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index 1dcdee0..0e7fc8b 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -323,10 +323,10 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): self._state = None self._last_state = None - #Default value is available to be provided by Platform entities if required + # Default value is available to be provided by Platform entities if required self._default_value = self._config.get(CONF_DEFAULT_VALUE) - #Restore on connect setting is available to be provided by Platform entities if required + # 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 ) @@ -366,7 +366,7 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): @property def extra_state_attributes(self): """Return entity specific state attributes to be saved & then available for restore - when the entity is restored at startup. + when the entity is restored at startup. """ attributes = {} if self._state is not None: diff --git a/custom_components/localtuya/number.py b/custom_components/localtuya/number.py index eae033f..85974e8 100644 --- a/custom_components/localtuya/number.py +++ b/custom_components/localtuya/number.py @@ -5,7 +5,6 @@ from functools import partial import voluptuous as vol from homeassistant.components.number import DOMAIN, NumberEntity from homeassistant.const import CONF_DEVICE_CLASS, STATE_UNKNOWN -from homeassistant.helpers.restore_state import RestoreEntity from .common import LocalTuyaEntity, async_setup_entry @@ -17,10 +16,12 @@ from .const import ( CONF_MAX_VALUE, CONF_DEFAULT_VALUE, CONF_RESTORE_ON_RECONNECT, + CONF_STEPSIZE_VALUE, ) DEFAULT_MIN = 0 DEFAULT_MAX = 100000 +DEFAULT_STEP = 1.0 def flow_schema(dps): @@ -34,12 +35,16 @@ def flow_schema(dps): vol.Coerce(float), vol.Range(min=-1000000.0, max=1000000.0), ), + vol.Required(CONF_STEPSIZE_VALUE, default=DEFAULT_STEP): vol.All( + vol.Coerce(float), + vol.Range(min=0.0, max=1000000.0), + ), vol.Optional(CONF_DEFAULT_VALUE): str, vol.Required(CONF_RESTORE_ON_RECONNECT): bool, } -class LocaltuyaNumber(LocalTuyaEntity, NumberEntity, RestoreEntity): +class LocaltuyaNumber(LocalTuyaEntity, NumberEntity): """Representation of a Tuya Number.""" def __init__( @@ -57,34 +62,47 @@ class LocaltuyaNumber(LocalTuyaEntity, NumberEntity, RestoreEntity): if CONF_MIN_VALUE in self._config: self._min_value = self._config.get(CONF_MIN_VALUE) - self._max_value = self._config.get(CONF_MAX_VALUE) + self._max_value = DEFAULT_MAX + if CONF_MAX_VALUE in self._config: + self._max_value = self._config.get(CONF_MAX_VALUE) + + + self._step_size = DEFAULT_STEP + if CONF_STEPSIZE_VALUE in self._config: + self._step_size = self._config.get(CONF_STEPSIZE_VALUE) #Override standard default value handling to cast to a float default_value = self._config.get(CONF_DEFAULT_VALUE) if default_value is not None: self._default_value = float(default_value) + @property - def value(self) -> float: + def native_value(self) -> float: """Return sensor state.""" return self._state @property - def min_value(self) -> float: + def native_min_value(self) -> float: """Return the minimum value.""" return self._min_value @property - def max_value(self) -> float: + def native_max_value(self) -> float: """Return the maximum value.""" return self._max_value + @property + def native_step(self) -> float: + """Return the maximum value.""" + return self._step_size + @property def device_class(self): """Return the class of this device.""" return self._config.get(CONF_DEVICE_CLASS) - async def async_set_value(self, value: float) -> None: + async def async_set_native_value(self, value: float) -> None: """Update the current value.""" await self._device.set_dp(value, self._dp_id) From 06968d8a9c8456256cc932da81ff3de6e57b6c74 Mon Sep 17 00:00:00 2001 From: sibowler Date: Thu, 14 Jul 2022 06:58:00 +1000 Subject: [PATCH 03/11] Rebase merge fix. Earlier commit also included changes for manually specifying DPS where entity detection failed, restoring DPS values on reconnect and also supporting devices which don't report DPS status until it has been set once. --- custom_components/localtuya/strings.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/custom_components/localtuya/strings.json b/custom_components/localtuya/strings.json index 4db7e70..a669d56 100644 --- a/custom_components/localtuya/strings.json +++ b/custom_components/localtuya/strings.json @@ -120,7 +120,12 @@ "preset_set": "Presets Set (optional)", "eco_dp": "Eco DP (optional)", "eco_value": "Eco value (optional)", - "heuristic_action": "Enable heuristic action (optional)" + "heuristic_action": "Enable heuristic action (optional)", + "dps_default_value": "Default value when un-initialised (optional)", + "restore_on_reconnect": "Restore the last set value in HomeAssistant after a lost connection", + "min_value": "Minimum Value", + "max_value": "Maximum Value", + "step_size": "Minimum increment between numbers" } }, "yaml_import": { From f85b25dea903287cf1efd35e3935fab076c6ff6e Mon Sep 17 00:00:00 2001 From: sibowler Date: Thu, 14 Jul 2022 08:59:54 +1000 Subject: [PATCH 04/11] Fixing formatting/style errors --- custom_components/localtuya/binary_sensor.py | 4 +- custom_components/localtuya/common.py | 45 +++++++++++++------- custom_components/localtuya/cover.py | 3 +- custom_components/localtuya/number.py | 10 ++--- custom_components/localtuya/select.py | 9 ++-- custom_components/localtuya/sensor.py | 2 +- custom_components/localtuya/switch.py | 1 + 7 files changed, 46 insertions(+), 28 deletions(-) diff --git a/custom_components/localtuya/binary_sensor.py b/custom_components/localtuya/binary_sensor.py index 0011c2f..273880c 100644 --- a/custom_components/localtuya/binary_sensor.py +++ b/custom_components/localtuya/binary_sensor.py @@ -52,9 +52,9 @@ class LocaltuyaBinarySensor(LocalTuyaEntity, BinarySensorEntity): return self._config.get(CONF_DEVICE_CLASS) def status_updated(self): + """Device status was updated.""" super().status_updated() - """Device status was updated.""" state = str(self.dps(self._dp_id)).lower() if state == self._config[CONF_STATE_ON].lower(): self._is_on = True @@ -67,7 +67,7 @@ class LocaltuyaBinarySensor(LocalTuyaEntity, BinarySensorEntity): # No need to restore state for a sensor async def restore_state_when_connected(self): - """Do nothing for a sensor""" + """Do nothing for a sensor.""" return diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index 0e7fc8b..38a5f40 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -95,7 +95,7 @@ async def async_setup_entry( entity_config[CONF_ID], ) ) - #Once the entities have been created, add to the TuyaDevice instance + # Once the entities have been created, add to the TuyaDevice instance tuyainterface.add_entities(entities) async_add_entities(entities) @@ -150,9 +150,14 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): self.dps_to_request[entity[CONF_ID]] = None def add_entities(self, entities): - """Set the entities associated with this device""" + """Set the entities associated with this device.""" self._entities.extend(entities) + @property + def is_connecting(self): + """Return whether device is currently connecting.""" + return self._connect_task is not None + @property def connected(self): """Return if connected to device.""" @@ -184,7 +189,8 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): self.status_updated(status) - # Attempt to restore status for all entites that need to first set the DPS value before the device will respond with status. + # Attempt to restore status for all entites that need to first set + # the DPS value before the device will respond with status. for entity in self._entities: await entity.restore_state_when_connected() @@ -326,7 +332,8 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): # Default value is available to be provided by Platform entities if required self._default_value = self._config.get(CONF_DEFAULT_VALUE) - # Restore on connect setting is available to be provided by Platform entities if required + """ 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 ) @@ -365,8 +372,10 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): @property def extra_state_attributes(self): - """Return entity specific state attributes to be saved & then available for restore - when the entity is restored at startup. + """Return entity specific state attributes to be saved. + + These attributes are then available for restore when the + entity is restored at startup. """ attributes = {} if self._state is not None: @@ -454,7 +463,7 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): # Keep record in last_state as long as not during connection/re-connection, # as last state will be used to restore the previous state - if (state is not None) and (self._device._connect_task is None): + if (state is not None) and (not self._device.is_connecting): self._last_state = state def status_restored(self, stored_state): @@ -464,8 +473,6 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): """ raw_state = stored_state.attributes.get(ATTR_STATE) if raw_state is not None: - # (stored_state.state == "unavailable") | (stored_state.state == "unknown") - # ): self._last_state = raw_state self.debug( "Restoring state for entity: %s - state: %s", @@ -474,7 +481,7 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): ) def default_value(self): - """Default value of this entity + """Return default value of this entity. Override in subclasses to specify the default value for the entity. """ @@ -484,8 +491,8 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): return self._default_value - def entity_default_value(self): - """Default value of the entity type + def entity_default_value(self): # pylint: disable=no-self-use + """Return default value of the entity type. Override in subclasses to specify the default value for the entity. """ @@ -493,14 +500,22 @@ class LocalTuyaEntity(RestoreEntity, pytuya.ContextualLogger): @property def restore_on_reconnect(self): - """Returns whether the last state should be restored on a reconnect - useful where the device loses settings if powered off""" + """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""" + """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): self.debug( - "Entity %s (DP %d) - Not restoring as restore on reconnect is disabled for this entity and the entity has an initial status", + "Entity %s (DP %d) - Not restoring as restore on reconnect is \ + disabled for this entity and the entity has an initial status", self.name, self._dp_id, ) diff --git a/custom_components/localtuya/cover.py b/custom_components/localtuya/cover.py index d8e426f..b9c10f7 100644 --- a/custom_components/localtuya/cover.py +++ b/custom_components/localtuya/cover.py @@ -189,8 +189,9 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity): self.debug("Restored cover position %s", self._current_cover_position) def status_updated(self): - super.status_updated(self) """Device status was updated.""" + super.status_updated(self) + self._previous_state = self._state self._state = self.dps(self._dp_id) if self._state.isupper(): diff --git a/custom_components/localtuya/number.py b/custom_components/localtuya/number.py index 85974e8..e8ab53d 100644 --- a/custom_components/localtuya/number.py +++ b/custom_components/localtuya/number.py @@ -8,10 +8,7 @@ from homeassistant.const import CONF_DEVICE_CLASS, STATE_UNKNOWN from .common import LocalTuyaEntity, async_setup_entry -_LOGGER = logging.getLogger(__name__) - from .const import ( - CONF_DEFAULT_VALUE, CONF_MIN_VALUE, CONF_MAX_VALUE, CONF_DEFAULT_VALUE, @@ -19,6 +16,8 @@ from .const import ( CONF_STEPSIZE_VALUE, ) +_LOGGER = logging.getLogger(__name__) + DEFAULT_MIN = 0 DEFAULT_MAX = 100000 DEFAULT_STEP = 1.0 @@ -66,16 +65,14 @@ class LocaltuyaNumber(LocalTuyaEntity, NumberEntity): if CONF_MAX_VALUE in self._config: self._max_value = self._config.get(CONF_MAX_VALUE) - self._step_size = DEFAULT_STEP if CONF_STEPSIZE_VALUE in self._config: self._step_size = self._config.get(CONF_STEPSIZE_VALUE) - #Override standard default value handling to cast to a float + # Override standard default value handling to cast to a float default_value = self._config.get(CONF_DEFAULT_VALUE) if default_value is not None: self._default_value = float(default_value) - @property def native_value(self) -> float: @@ -108,6 +105,7 @@ class LocaltuyaNumber(LocalTuyaEntity, NumberEntity): # Default value is the minimum value def entity_default_value(self): + """Return the minimum value as the default for this entity type.""" return self._min_value diff --git a/custom_components/localtuya/select.py b/custom_components/localtuya/select.py index 71f98cb..75dd217 100644 --- a/custom_components/localtuya/select.py +++ b/custom_components/localtuya/select.py @@ -11,8 +11,6 @@ from homeassistant.const import ( from .common import LocalTuyaEntity, async_setup_entry -_LOGGER = logging.getLogger(__name__) - from .const import ( CONF_OPTIONS, CONF_OPTIONS_FRIENDLY, @@ -31,6 +29,9 @@ def flow_schema(dps): } +_LOGGER = logging.getLogger(__name__) + + class LocaltuyaSelect(LocalTuyaEntity, SelectEntity): """Representation of a Tuya Enumeration.""" @@ -100,8 +101,9 @@ class LocaltuyaSelect(LocalTuyaEntity, SelectEntity): await self._device.set_dp(option_value, self._dp_id) def status_updated(self): - super().status_updated() """Device status was updated.""" + super().status_updated() + state = self.dps(self._dp_id) # Check that received status update for this entity. @@ -116,6 +118,7 @@ class LocaltuyaSelect(LocalTuyaEntity, SelectEntity): # Default value is the first option def entity_default_value(self): + """Return the first option as the default value for this entity type.""" return self._valid_options[0] diff --git a/custom_components/localtuya/sensor.py b/custom_components/localtuya/sensor.py index e769f4e..0eb0ae4 100644 --- a/custom_components/localtuya/sensor.py +++ b/custom_components/localtuya/sensor.py @@ -68,7 +68,7 @@ class LocaltuyaSensor(LocalTuyaEntity): # No need to restore state for a sensor async def restore_state_when_connected(self): - """Do nothing for a sensor""" + """Do nothing for a sensor.""" return diff --git a/custom_components/localtuya/switch.py b/custom_components/localtuya/switch.py index c448ff5..40e8ea1 100644 --- a/custom_components/localtuya/switch.py +++ b/custom_components/localtuya/switch.py @@ -82,6 +82,7 @@ class LocaltuyaSwitch(LocalTuyaEntity, SwitchEntity): # Default value is the "OFF" state def entity_default_value(self): + """Return False as the defaualt value for this entity type.""" return False From 41b5be03a3775fe77baf45dd98f609a535aefc9e Mon Sep 17 00:00:00 2001 From: sibowler Date: Thu, 14 Jul 2022 11:41:23 +1000 Subject: [PATCH 05/11] Adding notes to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 01cbba9..2201253 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,8 @@ If you have selected one entry, you only need to input the device's Friendly Nam Setting the scan interval is optional, it is only needed if energy/power values are not updating frequently enough by default. Values less than 10 seconds may cause stability issues. +Setting the 'Manual DPS To Add' is optional, it is only needed if the device doesn't advertise the DPS correctly until the entity has been properly initiailised. This setting can often be avoided by first connecting/initialising the device with the Tuya App, then closing the app and then adding the device in the integration. + Once you press "Submit", the connection is tested to check that everything works. ![image](https://user-images.githubusercontent.com/1082213/146664103-ac40319e-f934-4933-90cf-2beaff1e6bac.png) From 1c9a1e4e4bc1792f6ae759041ad4e30a310bc098 Mon Sep 17 00:00:00 2001 From: sibowler Date: Thu, 14 Jul 2022 15:26:58 +1000 Subject: [PATCH 06/11] Spelling correction --- custom_components/localtuya/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index 38a5f40..38401bc 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -189,7 +189,7 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): self.status_updated(status) - # Attempt to restore status for all entites that need to first set + # Attempt to restore status for all entities that need to first set # the DPS value before the device will respond with status. for entity in self._entities: await entity.restore_state_when_connected() From 489a6f09feb82aad01768277e04ad7aef50c0f59 Mon Sep 17 00:00:00 2001 From: sibowler Date: Thu, 14 Jul 2022 18:59:38 +1000 Subject: [PATCH 07/11] Updating documentation --- README.md | 2 +- img/2-device.png | Bin 27833 -> 27806 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2201253..756347f 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ Setting the 'Manual DPS To Add' is optional, it is only needed if the device doe Once you press "Submit", the connection is tested to check that everything works. -![image](https://user-images.githubusercontent.com/1082213/146664103-ac40319e-f934-4933-90cf-2beaff1e6bac.png) +![image](https://github.com/rospogrigio/localtuya-homeassistant/blob/master/img/2-device.png) Then, it's time to add the entities: this step will take place several times. First, select the entity type from the drop-down menu to set it up. diff --git a/img/2-device.png b/img/2-device.png index b82b2353c2e99631ef26c40eedd272f544a24db6..335d787033860e2b249bf04698cdce77d8afba8c 100644 GIT binary patch literal 27806 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 literal 27833 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 From ad1f7578188a0156f031a1aceb25baedc0dd932b Mon Sep 17 00:00:00 2001 From: sibowler Date: Wed, 20 Jul 2022 06:14:12 +1000 Subject: [PATCH 08/11] Implementing RESET Tuya function to enable devices which are stuck in a zombie mode to start responding to commands. Added configurable DPS for Reset command as found devices wouldn't 'wake up' unless they had exactly the right entries --- README.md | 2 + custom_components/localtuya/common.py | 80 +++++++++++++----- custom_components/localtuya/config_flow.py | 35 ++++++-- custom_components/localtuya/const.py | 1 + .../localtuya/pytuya/__init__.py | 55 +++++++++--- .../localtuya/translations/en.json | 3 +- img/2-device.png | Bin 27806 -> 29877 bytes 7 files changed, 140 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 756347f..edb7fbd 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,8 @@ Setting the scan interval is optional, it is only needed if energy/power values Setting the 'Manual DPS To Add' is optional, it is only needed if the device doesn't advertise the DPS correctly until the entity has been properly initiailised. This setting can often be avoided by first connecting/initialising the device with the Tuya App, then closing the app and then adding the device in the integration. +Setting the 'DPIDs to send in RESET command' is optional. It is used when a device doesn't respond to any Tuya commands after a power cycle, but can be connected to (zombie state). The DPids will vary between devices, but typically "18,19,20" is used (and will be the default if none specified). If the wrong entries are added here, then the device may not come out of the zombie state. Typically only sensor DPIDs entered here. + Once you press "Submit", the connection is tested to check that everything works. ![image](https://github.com/rospogrigio/localtuya-homeassistant/blob/master/img/2-device.png) diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index 38401bc..5eb6d81 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -35,6 +35,7 @@ from .const import ( CONF_DEFAULT_VALUE, ATTR_STATE, CONF_RESTORE_ON_RECONNECT, + CONF_RESET_DPIDS, ) _LOGGER = logging.getLogger(__name__) @@ -143,6 +144,14 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): self._unsub_interval = None self._entities = [] self._local_key = self._dev_config_entry[CONF_LOCAL_KEY] + self._default_reset_dpids = None + if CONF_RESET_DPIDS in self._dev_config_entry: + reset_ids_str = self._dev_config_entry[CONF_RESET_DPIDS].split(",") + + self._default_reset_dpids = [] + for reset_id in reset_ids_str: + self._default_reset_dpids.append(int(reset_id.strip())) + self.set_logger(_LOGGER, self._dev_config_entry[CONF_DEVICE_ID]) # This has to be done in case the device type is type_0d @@ -181,14 +190,60 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): self, ) self._interface.add_dps_to_request(self.dps_to_request) + except Exception: # pylint: disable=broad-except + self.exception(f"Connect to {self._dev_config_entry[CONF_HOST]} failed") + if self._interface is not None: + await self._interface.close() + self._interface = None - self.debug("Retrieving initial state") - status = await self._interface.status() - if status is None: - raise Exception("Failed to retrieve status") + if self._interface is not None: + try: + self.debug("Retrieving initial state") + status = await self._interface.status() + if status is None: + raise Exception("Failed to retrieve status") - self.status_updated(status) + self._interface.start_heartbeat() + self.status_updated(status) + except Exception as ex: # pylint: disable=broad-except + try: + self.debug( + "Initial state update failed, trying reset command " + + "for DP IDs: %s", + self._default_reset_dpids, + ) + await self._interface.reset(self._default_reset_dpids) + + self.debug("Update completed, retrying initial state") + status = await self._interface.status() + if status is None or not status: + raise Exception("Failed to retrieve status") from ex + + self._interface.start_heartbeat() + self.status_updated(status) + + except UnicodeDecodeError as e: # pylint: disable=broad-except + self.exception( + f"Connect to {self._dev_config_entry[CONF_HOST]} failed: %s", + type(e), + ) + if self._interface is not None: + await self._interface.close() + self._interface = None + + except Exception as e: # pylint: disable=broad-except + self.exception( + f"Connect to {self._dev_config_entry[CONF_HOST]} failed" + ) + if "json.decode" in str(type(e)): + await self.update_local_key() + + if self._interface is not None: + await self._interface.close() + self._interface = None + + if self._interface is not None: # Attempt to restore status for all entities that need to first set # the DPS value before the device will respond with status. for entity in self._entities: @@ -216,22 +271,7 @@ class TuyaDevice(pytuya.TuyaListener, pytuya.ContextualLogger): self._async_refresh, timedelta(seconds=self._dev_config_entry[CONF_SCAN_INTERVAL]), ) - except UnicodeDecodeError as e: # pylint: disable=broad-except - self.exception( - f"Connect to {self._dev_config_entry[CONF_HOST]} failed: %s", type(e) - ) - if self._interface is not None: - await self._interface.close() - self._interface = None - except Exception as e: # pylint: disable=broad-except - self.exception(f"Connect to {self._dev_config_entry[CONF_HOST]} failed") - if "json.decode" in str(type(e)): - await self.update_local_key() - - if self._interface is not None: - await self._interface.close() - self._interface = None self._connect_task = None async def update_local_key(self): diff --git a/custom_components/localtuya/config_flow.py b/custom_components/localtuya/config_flow.py index 203c0c6..e70076f 100644 --- a/custom_components/localtuya/config_flow.py +++ b/custom_components/localtuya/config_flow.py @@ -38,6 +38,7 @@ from .const import ( CONF_NO_CLOUD, CONF_PRODUCT_NAME, CONF_PROTOCOL_VERSION, + CONF_RESET_DPIDS, CONF_SETUP_CLOUD, CONF_USER_ID, DATA_CLOUD, @@ -90,6 +91,7 @@ CONFIGURE_DEVICE_SCHEMA = vol.Schema( vol.Required(CONF_PROTOCOL_VERSION, default="3.3"): vol.In(["3.1", "3.3"]), vol.Optional(CONF_SCAN_INTERVAL): int, vol.Optional(CONF_MANUAL_DPS): str, + vol.Optional(CONF_RESET_DPIDS): str, } ) @@ -102,6 +104,7 @@ DEVICE_SCHEMA = vol.Schema( vol.Required(CONF_PROTOCOL_VERSION, default="3.3"): vol.In(["3.1", "3.3"]), vol.Optional(CONF_SCAN_INTERVAL): int, vol.Optional(CONF_MANUAL_DPS): cv.string, + vol.Optional(CONF_RESET_DPIDS): str, } ) @@ -144,6 +147,7 @@ def options_schema(entities): vol.Required(CONF_PROTOCOL_VERSION, default="3.3"): vol.In(["3.1", "3.3"]), vol.Optional(CONF_SCAN_INTERVAL): int, vol.Optional(CONF_MANUAL_DPS): str, + vol.Optional(CONF_RESET_DPIDS): str, vol.Required( CONF_ENTITIES, description={"suggested_value": entity_names} ): cv.multi_select(entity_names), @@ -235,6 +239,8 @@ async def validate_input(hass: core.HomeAssistant, data): detected_dps = {} interface = None + + reset_ids = None try: interface = await pytuya.connect( data[CONF_HOST], @@ -243,20 +249,39 @@ async def validate_input(hass: core.HomeAssistant, data): float(data[CONF_PROTOCOL_VERSION]), ) - detected_dps = await interface.detect_available_dps() + try: + detected_dps = await interface.detect_available_dps() + except Exception: # pylint: disable=broad-except + try: + _LOGGER.debug("Initial state update failed, trying reset command") + if CONF_RESET_DPIDS in data: + reset_ids_str = data[CONF_RESET_DPIDS].split(",") + reset_ids = [] + for reset_id in reset_ids_str: + reset_ids.append(int(reset_id.strip())) + _LOGGER.debug( + "Reset DPIDs configured: %s (%s)", + data[CONF_RESET_DPIDS], + reset_ids, + ) + await interface.reset(reset_ids) + detected_dps = await interface.detect_available_dps() + except Exception: # pylint: disable=broad-except + _LOGGER.debug("No DPS able to be detected") + detected_dps = {} # if manual DPs are set, merge these. _LOGGER.debug("Detected DPS: %s", detected_dps) if CONF_MANUAL_DPS in data: - manual_dps_list = data[CONF_MANUAL_DPS].split(",") + manual_dps_list = [dps.strip() for dps in data[CONF_MANUAL_DPS].split(",")] _LOGGER.debug( "Manual DPS Setting: %s (%s)", data[CONF_MANUAL_DPS], manual_dps_list ) # merge the lists - for new_dps in manual_dps_list: - # trim off any whitespace - new_dps = new_dps.strip() + for new_dps in manual_dps_list + (reset_ids or []): + # If the DPS not in the detected dps list, then add with a + # default value indicating that it has been manually added if new_dps not in detected_dps: detected_dps[new_dps] = -1 diff --git a/custom_components/localtuya/const.py b/custom_components/localtuya/const.py index 993a1f1..9ae3902 100644 --- a/custom_components/localtuya/const.py +++ b/custom_components/localtuya/const.py @@ -43,6 +43,7 @@ CONF_SETUP_CLOUD = "setup_cloud" CONF_NO_CLOUD = "no_cloud" CONF_MANUAL_DPS = "manual_dps_strings" CONF_DEFAULT_VALUE = "dps_default_value" +CONF_RESET_DPIDS = "reset_dpids" # light CONF_BRIGHTNESS_LOWER = "brightness_lower" diff --git a/custom_components/localtuya/pytuya/__init__.py b/custom_components/localtuya/pytuya/__init__.py index b7645ec..d36cd5e 100644 --- a/custom_components/localtuya/pytuya/__init__.py +++ b/custom_components/localtuya/pytuya/__init__.py @@ -62,6 +62,7 @@ TuyaMessage = namedtuple("TuyaMessage", "seqno cmd retcode payload crc") SET = "set" STATUS = "status" HEARTBEAT = "heartbeat" +RESET = "reset" UPDATEDPS = "updatedps" # Request refresh of DPS PROTOCOL_VERSION_BYTES_31 = b"3.1" @@ -96,6 +97,16 @@ PAYLOAD_DICT = { SET: {"hexByte": 0x07, "command": {"devId": "", "uid": "", "t": ""}}, HEARTBEAT: {"hexByte": 0x09, "command": {}}, UPDATEDPS: {"hexByte": 0x12, "command": {"dpId": [18, 19, 20]}}, + RESET: { + "hexByte": 0x12, + "command": { + "gwId": "", + "devId": "", + "uid": "", + "t": "", + "dpId": [18, 19, 20], + }, + }, }, "type_0d": { STATUS: {"hexByte": 0x0D, "command": {"devId": "", "uid": "", "t": ""}}, @@ -217,6 +228,7 @@ class MessageDispatcher(ContextualLogger): # Heartbeats always respond with sequence number 0, so they can't be waited for like # other messages. This is a hack to allow waiting for heartbeats. HEARTBEAT_SEQNO = -100 + RESET_SEQNO = -101 def __init__(self, dev_id, listener): """Initialize a new MessageBuffer.""" @@ -301,9 +313,19 @@ class MessageDispatcher(ContextualLogger): sem.release() elif msg.cmd == 0x12: self.debug("Got normal updatedps response") + if self.RESET_SEQNO in self.listeners: + sem = self.listeners[self.RESET_SEQNO] + self.listeners[self.RESET_SEQNO] = msg + sem.release() elif msg.cmd == 0x08: - self.debug("Got status update") - self.listener(msg) + if self.RESET_SEQNO in self.listeners: + self.debug("Got reset status update") + sem = self.listeners[self.RESET_SEQNO] + self.listeners[self.RESET_SEQNO] = msg + sem.release() + else: + self.debug("Got status update") + self.listener(msg) else: self.debug( "Got message type %d for unknown listener %d: %s", @@ -381,6 +403,11 @@ class TuyaProtocol(asyncio.Protocol, ContextualLogger): def connection_made(self, transport): """Did connect to the device.""" + self.transport = transport + self.on_connected.set_result(True) + + def start_heartbeat(self): + """Start the heartbeat transmissions with the device.""" async def heartbeat_loop(): """Continuously send heart beat updates.""" @@ -403,8 +430,6 @@ class TuyaProtocol(asyncio.Protocol, ContextualLogger): self.transport = None transport.close() - self.transport = transport - self.on_connected.set_result(True) self.heartbeater = self.loop.create_task(heartbeat_loop()) def data_received(self, data): @@ -449,12 +474,13 @@ class TuyaProtocol(asyncio.Protocol, ContextualLogger): payload = self._generate_payload(command, dps) dev_type = self.dev_type - # Wait for special sequence number if heartbeat - seqno = ( - MessageDispatcher.HEARTBEAT_SEQNO - if command == HEARTBEAT - else (self.seqno - 1) - ) + # Wait for special sequence number if heartbeat or reset + seqno = self.seqno - 1 + + if command == HEARTBEAT: + seqno = MessageDispatcher.HEARTBEAT_SEQNO + elif command == RESET: + seqno = MessageDispatcher.RESET_SEQNO self.transport.write(payload) msg = await self.dispatcher.wait_for(seqno) @@ -487,6 +513,15 @@ class TuyaProtocol(asyncio.Protocol, ContextualLogger): """Send a heartbeat message.""" return await self.exchange(HEARTBEAT) + async def reset(self, dpIds=None): + """Send a reset message (3.3 only).""" + if self.version == 3.3: + self.dev_type = "type_0a" + self.debug("reset switching to dev_type %s", self.dev_type) + return await self.exchange(RESET, dpIds) + + return True + async def update_dps(self, dps=None): """ Request device to update index. diff --git a/custom_components/localtuya/translations/en.json b/custom_components/localtuya/translations/en.json index a97f120..d1da446 100644 --- a/custom_components/localtuya/translations/en.json +++ b/custom_components/localtuya/translations/en.json @@ -97,7 +97,8 @@ "protocol_version": "Protocol Version", "scan_interval": "Scan interval (seconds, only when not updating automatically)", "entities": "Entities (uncheck an entity to remove it)", - "manual_dps_strings": "Manual DPS to add (separated by commas ',') - used when detection is not working (optional)" + "manual_dps_strings": "Manual DPS to add (separated by commas ',') - used when detection is not working (optional)", + "reset_dpids": "DPIDs to send in RESET command (separated by commas ',')- Used when device does not respond to status requests after turning on (optional)" } }, "pick_entity_type": { diff --git a/img/2-device.png b/img/2-device.png index 335d787033860e2b249bf04698cdce77d8afba8c..4e6623d11dbaa187d29a9afa11e4b63f4442c312 100644 GIT binary patch literal 29877 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 B9gP40 literal 27806 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 From 8de987b2a0d4d090cfe9868bb5e3aa5742d2e360 Mon Sep 17 00:00:00 2001 From: sibowler Date: Thu, 1 Sep 2022 22:25:24 +1000 Subject: [PATCH 09/11] Fix for cover defect --- custom_components/localtuya/cover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/localtuya/cover.py b/custom_components/localtuya/cover.py index b9c10f7..060dbb6 100644 --- a/custom_components/localtuya/cover.py +++ b/custom_components/localtuya/cover.py @@ -190,7 +190,7 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity): def status_updated(self): """Device status was updated.""" - super.status_updated(self) + super().status_updated() self._previous_state = self._state self._state = self.dps(self._dp_id) From 8c4894371f245d90242cc329212c98d30ffd41b9 Mon Sep 17 00:00:00 2001 From: sibowler Date: Sun, 4 Sep 2022 14:02:06 +1000 Subject: [PATCH 10/11] Fix for cover issues with new state restore functionality --- custom_components/localtuya/cover.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/custom_components/localtuya/cover.py b/custom_components/localtuya/cover.py index 060dbb6..fa7a4fd 100644 --- a/custom_components/localtuya/cover.py +++ b/custom_components/localtuya/cover.py @@ -190,7 +190,6 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity): def status_updated(self): """Device status was updated.""" - super().status_updated() self._previous_state = self._state self._state = self.dps(self._dp_id) @@ -230,5 +229,10 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity): # store the time of the last movement change self._timer_start = time.time() + # Keep record in last_state as long as not during connection/re-connection, + # as last state will be used to restore the previous state + if (self._state is not None) and (not self._device.is_connecting): + self._last_state = self._state + async_setup_entry = partial(async_setup_entry, DOMAIN, LocaltuyaCover, flow_schema) From 19a0cb6d15009e32b49fa780b3cc5d2882a1c875 Mon Sep 17 00:00:00 2001 From: sibowler Date: Sun, 4 Sep 2022 14:06:10 +1000 Subject: [PATCH 11/11] Fixing slight format error --- custom_components/localtuya/cover.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/localtuya/cover.py b/custom_components/localtuya/cover.py index fa7a4fd..3b6b86d 100644 --- a/custom_components/localtuya/cover.py +++ b/custom_components/localtuya/cover.py @@ -190,7 +190,6 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity): def status_updated(self): """Device status was updated.""" - self._previous_state = self._state self._state = self.dps(self._dp_id) if self._state.isupper():