Skip to content

Commit

Permalink
Improve the speed of reloading the entry.
Browse files Browse the repository at this point in the history
  • Loading branch information
xZetsubou committed Apr 23, 2024
1 parent 1655ea2 commit 3a42a20
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 30 deletions.
10 changes: 3 additions & 7 deletions custom_components/localtuya/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
if no_cloud:
_LOGGER.info("Cloud API account not configured.")
# wait 1 second to make sure possible migration has finished
await asyncio.sleep(1)
# await asyncio.sleep(1)
else:
entry.async_create_background_task(
hass, tuya_api.async_connect(), "localtuya-cloudAPI"
Expand Down Expand Up @@ -389,10 +389,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# Unload the platforms.
await hass.config_entries.async_unload_platforms(entry, platforms)

# Close all connection to the devices.
if disconnect_devices:
await asyncio.wait(disconnect_devices)

hass.data[DOMAIN].pop(entry.entry_id)

return True
Expand Down Expand Up @@ -471,8 +467,8 @@ async def _async_reconnect(now):
dev_id = dev._device_config.id
if check_if_device_disabled(hass, entry, dev_id):
return
if not dev.connected:
asyncio.create_task(dev.async_connect())
# "async_connect" has to check if the device is already connected, then stop.
asyncio.create_task(dev.async_connect())

# Add unsub callbeack in unsub_listeners object.
hass_localtuya.unsub_listeners.append(
Expand Down
36 changes: 17 additions & 19 deletions custom_components/localtuya/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ def __init__(
self.dps_to_request = {}
self._is_closing = False
self._connect_task: asyncio.Task | None = None
self._disconnect_task: Callable[[], None] | None = None
self._unsub_interval: CALLBACK_TYPE[[], None] = None
self._shutdown_entities_delay: CALLBACK_TYPE[[], None] = None
self._unsub_on_close: list[CALLBACK_TYPE] = []
self._entities = []
self._local_key: str = self._device_config.local_key
self._default_reset_dpids: list | None = None
Expand Down Expand Up @@ -146,6 +144,9 @@ async def async_connect(self, _now=None) -> None:
await self._connect_task
except (TimeoutError, asyncio.CancelledError):
...
elif self.connected:
# In-case device is connected but somehow the status hasn't been sent.
self._dispatch_status()

async def _make_connection(self):
"""Subscribe localtuya entity events."""
Expand Down Expand Up @@ -183,7 +184,7 @@ async def _make_connection(self):
break # Succeed break while loop
except Exception as ex: # pylint: disable=broad-except
await self.abort_connect()
if not retry < self._connect_max_tries and not self.is_sleep:
if retry >= self._connect_max_tries and not self.is_sleep:
self.warning(f"Failed to connect to {host}: {str(ex)}")
if "key" in str(ex):
update_localkey = True
Expand All @@ -204,7 +205,7 @@ async def _make_connection(self):
self.debug("Retrieving initial state")
# Usually we use status instead of detect_available_dps, but some device doesn't reports all dps when ask for status.
status = await self._interface.status(cid=self._node_id)
if status is None: # and not self.is_subdevice
if status is None:
raise Exception("Failed to retrieve status")

self._interface.start_heartbeat()
Expand Down Expand Up @@ -238,13 +239,15 @@ def _new_entity_handler(entity_id):
self._dispatch_status()

signal = f"localtuya_entity_{self._device_config.id}"
self._disconnect_task = async_dispatcher_connect(
self._hass, signal, _new_entity_handler
self._unsub_on_close.append(
async_dispatcher_connect(self._hass, signal, _new_entity_handler)
)

if (scan_inv := int(self._device_config.scan_interval)) > 0:
self._unsub_interval = async_track_time_interval(
self._hass, self._async_refresh, timedelta(seconds=scan_inv)
self._unsub_on_close.append(
async_track_time_interval(
self._hass, self._async_refresh, timedelta(seconds=scan_inv)
)
)

self._connect_task = None
Expand Down Expand Up @@ -293,17 +296,16 @@ async def check_connection(self):
async def close(self):
"""Close connection and stop re-connect loop."""
self._is_closing = True
if self._shutdown_entities_delay is not None:
self._shutdown_entities_delay()
for callback in self._unsub_on_close:
callback()

if self._connect_task is not None:
self._connect_task.cancel()
await self._connect_task
self._connect_task = None
if self._interface is not None:
await self._interface.close()
self._interface = None
if self._disconnect_task:
self._disconnect_task()
self.debug(f"Closed connection with {self._device_config.name}", force=True)

async def update_local_key(self):
Expand Down Expand Up @@ -427,7 +429,6 @@ def fire_event(event, data: dict):

def _shutdown_entities(self, now=None):
"""Shutdown device entities"""
self._shutdown_entities_delay = None
if self.is_sleep:
return
if not self.connected:
Expand All @@ -452,9 +453,6 @@ def disconnected(self):
"""Device disconnected."""
sleep_time = self._device_config.sleep_time

if self._unsub_interval is not None:
self._unsub_interval()
self._unsub_interval = None
self._interface = None

if self._sub_devices:
Expand All @@ -471,8 +469,8 @@ def disconnected(self):
async_call_later(self._hass, 1, self.async_connect)

if not self._is_closing:
self._shutdown_entities_delay = async_call_later(
self._hass, sleep_time + 3, self._shutdown_entities
self._unsub_on_close.append(
async_call_later(self._hass, sleep_time + 3, self._shutdown_entities)
)


Expand Down
7 changes: 3 additions & 4 deletions custom_components/localtuya/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,18 @@ async def async_added_to_hass(self):
if stored_data:
self.status_restored(stored_data)

def _update_handler(_status):
def _update_handler(new_status: dict | None):
"""Update entity state when status was updated."""
status = _status.copy() if _status is not None else {}
status = self._status.clear() if new_status is None else new_status.copy()

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:
self._status = status.copy()

if status:
self._status.update(status)
self.status_updated()

# Update HA
Expand Down

0 comments on commit 3a42a20

Please sign in to comment.