From 3d0a22d005576c519ac4e67527d5efad7a428d8c Mon Sep 17 00:00:00 2001 From: xZetsubou Date: Tue, 9 Apr 2024 02:17:26 +0300 Subject: [PATCH] Refactor common #180 #194 * Groups set dp values is now set values together instead of set dp on it's own. * Sub-devices updated localkey also update the node_id and gateway id. --- custom_components/localtuya/common.py | 65 +++++++++++++++++++-------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/custom_components/localtuya/common.py b/custom_components/localtuya/common.py index 31b0170e..c7c37aa5 100644 --- a/custom_components/localtuya/common.py +++ b/custom_components/localtuya/common.py @@ -50,6 +50,7 @@ CONF_PROTOCOL_VERSION, CONF_RESET_DPIDS, CONF_RESTORE_ON_RECONNECT, + DATA_DISCOVERY, DOMAIN, DEFAULT_CATEGORIES, ENTITY_CATEGORY, @@ -58,6 +59,7 @@ CONF_DEVICE_SLEEP_TIME, CONF_DPS_STRINGS, CONF_MANUAL_DPS, + CONF_TUYA_IP, ) _LOGGER = logging.getLogger(__name__) @@ -387,6 +389,8 @@ async def check_connection(self): await self._connect_task if not self.connected and self._gwateway and self._gwateway._connect_task: await self._gwateway._connect_task + if not self._interface: + self.error(f"Not connected to device {self._device_config.name}") async def close(self): """Close connection and stop re-connect loop.""" @@ -409,46 +413,67 @@ async def update_local_key(self): dev_id = self._device_config.id cloud_api = self._hass_entry.cloud_data await cloud_api.async_get_devices_list() + discovery = self._hass.data[DOMAIN].get(DATA_DISCOVERY) + cloud_devs = cloud_api.device_list if dev_id in cloud_devs: cloud_localkey = cloud_devs[dev_id].get(CONF_LOCAL_KEY) if not cloud_localkey or self._local_key == cloud_localkey: return - self._local_key = cloud_localkey + new_data = self._config_entry.data.copy() + self._local_key = cloud_localkey + + if self.is_subdevice: + from .core.helpers import get_gateway_by_deviceid + + # Update Node ID. + if new_node_id := cloud_devs[dev_id].get(CONF_NODE_ID): + new_data[CONF_DEVICES][dev_id][CONF_NODE_ID] = new_node_id + + # Update Gateway ID and IP + new_gw = get_gateway_by_deviceid(dev_id, cloud_devs) + new_data[CONF_DEVICES][dev_id][CONF_GATEWAY_ID] = new_gw.id + if discovery and (local_gw := discovery.devices.get(new_gw.id)): + new_ip = local_gw.get(CONF_TUYA_IP, self._device_config.host) + new_data[CONF_DEVICES][dev_id][CONF_HOST] = new_ip + self.info(f"Updated informations for sub-device {dev_id}.") + new_data[CONF_DEVICES][dev_id][CONF_LOCAL_KEY] = self._local_key new_data[ATTR_UPDATED_AT] = str(int(time.time() * 1000)) self._hass.config_entries.async_update_entry( - self._config_entry, - data=new_data, + self._config_entry, data=new_data ) self.info(f"local_key updated for device {dev_id}.") - async def set_dp(self, state, dp_index): - """Change value of a DP of the Tuya device.""" + async def set_values(self): + """Send self._pending_status payload to device.""" await self.check_connection() - if self._interface is not None: + if self._interface and self._pending_status: + payload, self._pending_status = self._pending_status.copy(), {} try: - await self._interface.set_dp(state, dp_index, cid=self._node_id) + await self._interface.set_dps(payload, cid=self._node_id) except Exception: # pylint: disable=broad-except - self.debug(f"Failed to set DP {dp_index} to {str(state)}", force=True) + self.debug(f"Failed to set values {payload}", force=True) + + async def set_dp(self, state, dp_index): + """Change value of a DP of the Tuya device.""" + if self._interface is not None: + self._pending_status.update({dp_index: state}) + await asyncio.sleep(0.001) + await self.set_values() else: if self.is_sleep: return self._pending_status.update({str(dp_index): state}) - self.error(f"Not connected to device {self._device_config.name}") async def set_dps(self, states): """Change value of a DPs of the Tuya device.""" - await self.check_connection() if self._interface is not None: - try: - await self._interface.set_dps(states, cid=self._node_id) - except Exception: # pylint: disable=broad-except - self.debug(f"Failed to set DPs {states}") + self._pending_status.update(states) + await self.set_values() else: if self.is_sleep: return self._pending_status.update(states) - self.error(f"Not connected to device {self._device_config.name}") async def _async_refresh(self, _now): if self._interface is not None: @@ -588,11 +613,13 @@ def _update_handler(status): """Update entity state when status was updated.""" if status is None: status = {} + + if status == RESTORE_STATES and stored_data: + if stored_data.state not in (STATE_UNAVAILABLE, STATE_UNKNOWN): + self.debug(f"{self.name}: Restore state: {stored_data.state}") + status[self._dp_id] = stored_data.state + if self._status != status: - if status == RESTORE_STATES: - if stored_data and stored_data.state != STATE_UNAVAILABLE: - self.debug(f"{self.name}: restore state: {stored_data.state}") - status[self._dp_id] = stored_data.state self._status = status.copy() if status: