8000 Use component queries to select smartcamera modules by sdb9696 · Pull Request #1248 · python-kasa/python-kasa · GitHub
[go: up one dir, main page]

Skip to content

Use component queries to select smartcamera modules #1248

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 4 commits into from
Nov 13, 2024
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
1 change: 1 addition & 0 deletions kasa/experimental/modules/childdevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
class ChildDevice(SmartCameraModule):
"""Implementation for child devices."""

REQUIRED_COMPONENT = "childControl"
NAME = "childdevice"
QUERY_GETTER_NAME = "getChildDeviceList"
# This module is unusual in that QUERY_MODULE_NAME in the response is not
Expand Down
52 changes: 36 additions & 16 deletions kasa/experimental/smartcamera.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,16 @@ def _update_children_info(self) -> None:
for info in child_info["child_device_list"]:
self._children[info["device_id"]]._update_internal_state(info)

async def _initialize_smart_child(self, info: dict) -> SmartDevice:
async def _initialize_smart_child(
self, info: dict, child_components: dict
) -> SmartDevice:
"""Initialize a smart child device attached to a smartcamera."""
child_id = info["device_id"]
child_protocol = _ChildCameraProtocolWrapper(child_id, self.protocol)
try:
initial_response = await child_protocol.query(
{"component_nego": None, "get_connect_cloud_state": None}
{"get_connect_cloud_state": None}
)
child_components = {
item["id"]: item["ver_code"]
for item in initial_response["component_nego"]["component_list"]
}
except Exception as ex:
_LOGGER.exception("Error initialising child %s: %s", child_id, ex)

Expand All @@ -68,20 +66,28 @@ async def _initialize_smart_child(self, info: dict) -> SmartDevice:

async def _initialize_children(self) -> None:
"""Initialize children for hubs."""
if not (
child_info := self._try_get_response(
self._last_update, "getChildDeviceList", {}
)
):
return
child_info_query = {
"getChildDeviceList": {"childControl": {"start_index": 0}},
"getChildDeviceComponentList": {"childControl": {"start_index": 0}},
}
resp = await self.protocol.query(child_info_query)
10000 self.internal_state.update(resp)

children_components = {
child["device_id"]: {
comp["id"]: int(comp["ver_code"]) for comp in child["component_list"]
}
for child in resp["getChildDeviceComponentList"]["child_component_list"]
}
children = {}
for info in child_info["child_device_list"]:
for info in resp["getChildDeviceList"]["child_device_list"]:
if (
category := info.get("category")
) and category in SmartChildDevice.CHILD_DEVICE_TYPE_MAP:
child_id = info["device_id"]
children[child_id] = await self._initialize_smart_child(info)
children[child_id] = await self._initialize_smart_child(
info, children_components[child_id]
)
else:
_LOGGER.debug("Child device type not supported: %s", info)

Expand All @@ -90,6 +96,11 @@ async def _initialize_children(self) -> None:
async def _initialize_modules(self) -> None:
"""Initialize modules based on component negotiation response."""
for mod in SmartCameraModule.REGISTERED_MODULES.values():
if (
mod.REQUIRED_COMPONENT
and mod.REQUIRED_COMPONENT not in self._components
):
continue
module = mod(self, mod._module_name())
if await module._check_supported():
self._modules[module.name] = module
Expand Down Expand Up @@ -126,12 +137,21 @@ async def _negotiate(self) -> None:
"""
initial_query = {
"getDeviceInfo": {"device_info": {"name": ["basic_info", "info"]}},
"getChildDeviceList": {"childControl": {"start_index": 0}},
"getAppComponentList": {"app_component": {"name": "app_component_list"}},
}
resp = await self.protocol.query(initial_query)
self._last_update.update(resp)
self._update_internal_info(resp)
await self._initialize_children()

self._components = {
comp["name"]: int(comp["version"])
for comp in resp["getAppComponentList"]["app_component"][
"app_component_list"
]
}

if "childControl" in self._components and not self.children:
await self._initialize_children()

def _map_info(self, device_info: dict) -> dict:
basic_info = device_info["basic_info"]
Expand Down
4 changes: 2 additions & 2 deletions kasa/experimental/smartcameramodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def data(self) -> dict:
if isinstance(query_resp, SmartErrorCode):
raise DeviceError(
f"Error accessing module data in {self._module}",
error_code=SmartErrorCode,
error_code=query_resp,
)

if not query_resp:
Expand All @@ -95,6 +95,6 @@ def data(self) -> dict:
if isinstance(found[key], SmartErrorCode):
raise DeviceError(
f"Error accessing module data {key} in {self._module}",
error_code=SmartErrorCode,
error_code=found[key],
)
return found
Loading
0