mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-08-09 20:24:02 +00:00
Update hub children on first update and delay subsequent updates (#1438)
Some checks are pending
CI / Perform linting checks (3.13) (push) Waiting to run
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.13) (push) Blocked by required conditions
CodeQL checks / Analyze (python) (push) Waiting to run
Some checks are pending
CI / Perform linting checks (3.13) (push) Waiting to run
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.13) (push) Blocked by required conditions
CodeQL checks / Analyze (python) (push) Waiting to run
This commit is contained in:
@@ -19,12 +19,15 @@ class DeviceModule(SmartModule):
|
||||
|
||||
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
|
||||
|
@@ -86,11 +86,22 @@ class SmartChildDevice(SmartDevice):
|
||||
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(
|
||||
|
@@ -183,7 +183,7 @@ class SmartDevice(Device):
|
||||
"""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.")
|
||||
@@ -207,7 +207,7 @@ class SmartDevice(Device):
|
||||
# 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)
|
||||
@@ -260,11 +260,7 @@ class SmartDevice(Device):
|
||||
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)
|
||||
|
||||
|
@@ -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
|
||||
@@ -107,16 +109,27 @@ class SmartModule(Module):
|
||||
@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
|
||||
|
||||
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.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__)
|
||||
|
@@ -16,6 +16,11 @@ class DeviceModule(SmartCamModule):
|
||||
|
||||
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 {}
|
||||
q = super().query()
|
||||
q["getConnectionType"] = {"network": {"get_connection_type": []}}
|
||||
|
||||
@@ -70,14 +75,14 @@ class DeviceModule(SmartCamModule):
|
||||
@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"]
|
||||
|
||||
@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")
|
||||
|
Reference in New Issue
Block a user