8000 Update hub children on first update and delay subsequent updates by sdb9696 · Pull Request #1438 · python-kasa/python-kasa · GitHub
[go: up one dir, main page]

Skip to content

Update hub children on first update and delay subsequent updates #1438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion kasa/smart/modules/devicemodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ async def _post_update_hook(self) -> None:

def query(self) -> dict:
"""Query to execute during the update cycle."""
if self._device._is_hub_child:
# Child devices get their device info updated by the parent device.
return {}
query = {
"get_device_info": None,
}
# Device usage is not available on older firmware versions
# or child devices of hubs
if self.supported_version >= 2 and not self._device._is_hub_child:
if self.supported_version >= 2:
query["get_device_usage"] = None

return query
15 changes: 13 additions & 2 deletions kasa/smart/smartchilddevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,22 @@ async def _update(self, update_children: bool = True) -> None:
module_queries: list[SmartModule] = []
req: dict[str, Any] = {}
for module in self.modules.values():
if module.disabled is False and (mod_query := module.query()):
if (
module.disabled is False
and (mod_query := module.query())
and module._should_update(now)
):
module_queries.append(module)
req.update(mod_query)
if req:
self._last_update = await self.protocol.query(req)
first_update = self._last_update != {}
try:
resp = await self.protocol.query(req)
except Exception as ex:
resp = await self._handle_modular_update_error(
ex, first_update, ", ".join(mod.name for mod in module_queries), req
)
self._last_update = resp

for module in self.modules.values():
await self._handle_module_post_update(
Expand Down
10 changes: 3 additions & 7 deletions kasa/smart/smartdevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def _update_internal_info(self, info_resp: dict) -> None:
"""Update the internal device info."""
self._info = self._try_get_response(info_resp, "get_device_info")

async def update(self, update_children: bool = False) -> None:
async def update(self, update_children: bool = True) -> None:
"""Update the device."""
if self.credentials is None and self.credentials_hash is None:
raise AuthenticationError("Tapo plug requires authentication.")
Expand All @@ -207,7 +207,7 @@ async def update(self, update_children: bool = False) -> None:
# devices will always update children to prevent errors on module access.
# This needs to go after updating the internal state of the children so that
# child modules have access to their sysinfo.
if update_children or self.device_type != DeviceType.Hub:
if first_update or update_children or self.device_type != DeviceType.Hub:
for child in self._children.values():
if TYPE_CHECKING:
assert isinstance(child, SmartChildDevice)
Expand Down Expand Up @@ -260,11 +260,7 @@ async def _modular_update(
if first_update and module.__class__ in self.FIRST_UPDATE_MODULES:
module._last_update_time = update_time
continue
if (
not module.update_interval
or not module._last_update_time
or (update_time - module._last_update_time) >= module.update_interval
):
if module._should_update(update_time):
module_queries.append(module)
req.update(query)

Expand Down
19 changes: 16 additions & 3 deletions kasa/smart/smartmodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class SmartModule(Module):
REGISTERED_MODULES: dict[str, type[SmartModule]] = {}

MINIMUM_UPDATE_INTERVAL_SECS = 0
MINIMUM_HUB_CHILD_UPDATE_INTERVAL_SECS = 60 * 60 * 24

UPDATE_INTERVAL_AFTER_ERROR_SECS = 30

DISABLE_AFTER_ERROR_COUNT = 10
Expand Down Expand Up @@ -107,16 +109,27 @@ def _set_error(self, err: Exception | None) -> None:
@property
def update_interval(self) -> int:
"""Time to wait between updates."""
if self._last_update_error is None:
return self.MINIMUM_UPDATE_INTERVAL_SECS
if self._last_update_error:
return self.UPDATE_INTERVAL_AFTER_ERROR_SECS * self._error_count

if self._device._is_hub_child:
return self.MINIMUM_HUB_CHILD_UPDATE_INTERVAL_SECS

return self.UPDATE_INTERVAL_AFTER_ERROR_SECS * self._error_count
return self.MINIMUM_UPDATE_INTERVAL_SECS

@property
def disabled(self) -> bool:
"""Return true if the module is disabled due to errors."""
return self._error_count >= self.DISABLE_AFTER_ERROR_COUNT

def _should_update(self, update_time: float) -> bool:
"""Return true if module should update based on delay parameters."""
return (
not self.update_interval
or not self._last_update_time
or (update_time - self._last_update_time) >= self.update_interval
)

@classmethod
def _module_name(cls) -> str:
return getattr(cls, "NAME", cls.__name__)
Expand Down
11 changes: 8 additions & 3 deletions kasa/smartcam/modules/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@

def query(self) -> dict:
"""Query to execute during the update cycle."""
if self._device._is_hub_child:
# Child devices get their device info updated by the parent device.
# and generally don't support connection type as they're not
# connected to the network
return {}

Check warning on line 23 in kasa/smartcam/modules/device.py

View check run for this annotation

Codecov / codecov/patch

kasa/smartcam/modules/device.py#L23

Added line #L23 was not covered by tests
q = super().query()
q["getConnectionType"] = {"network": {"get_connection_type": []}}

Expand Down Expand Up @@ -70,14 +75,14 @@
@property
def device_id(self) -> str:
"""Return the device id."""
return self.data[self.QUERY_GETTER_NAME]["basic_info"]["dev_id"]
return self._device._info["device_id"]

Check warning on line 78 in kasa/smartcam/modules/device.py

View check run for this annotation

Codecov / codecov/patch

kasa/smartcam/modules/device.py#L78

Added line #L78 was not covered by tests

@property
def rssi(self) -> int | None:
"""Return the device id."""
return self.data["getConnectionType"].get("rssiValue")
return self.data.get("getConnectionType", {}).get("rssiValue")

@property
def signal_level(self) -> int | None:
"""Return the device id."""
return self.data["getConnectionType"].get("rssi")
return self.data.get("getConnectionType", {}).get("rssi")
Loading
Loading
0