mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-08-04 09:44:14 +00:00
Use _get_device_info methods for smart and iot devs in devtools (#1265)
This commit is contained in:
@@ -21,6 +21,7 @@ import traceback
|
||||
from collections import defaultdict, namedtuple
|
||||
from pathlib import Path
|
||||
from pprint import pprint
|
||||
from typing import Any
|
||||
|
||||
import asyncclick as click
|
||||
|
||||
@@ -40,12 +41,13 @@ from kasa.device_factory import get_protocol
|
||||
from kasa.deviceconfig import DeviceEncryptionType, DeviceFamily
|
||||
from kasa.discover import DiscoveryResult
|
||||
from kasa.exceptions import SmartErrorCode
|
||||
from kasa.protocols import IotProtocol
|
||||
from kasa.protocols.smartcameraprotocol import (
|
||||
SmartCameraProtocol,
|
||||
_ChildCameraProtocolWrapper,
|
||||
)
|
||||
from kasa.protocols.smartprotocol import SmartProtocol, _ChildProtocolWrapper
|
||||
from kasa.smart import SmartChildDevice
|
||||
from kasa.smart import SmartChildDevice, SmartDevice
|
||||
from kasa.smartcamera import SmartCamera
|
||||
|
||||
Call = namedtuple("Call", "module method")
|
||||
@@ -389,7 +391,9 @@ async def cli(
|
||||
)
|
||||
|
||||
|
||||
async def get_legacy_fixture(protocol, *, discovery_info):
|
||||
async def get_legacy_fixture(
|
||||
protocol: IotProtocol, *, discovery_info: dict[str, Any] | None
|
||||
) -> FixtureResult:
|
||||
"""Get fixture for legacy IOT style protocol."""
|
||||
items = [
|
||||
Call(module="system", method="get_sysinfo"),
|
||||
@@ -422,8 +426,8 @@ async def get_legacy_fixture(protocol, *, discovery_info):
|
||||
finally:
|
||||
await protocol.close()
|
||||
|
||||
final_query = defaultdict(defaultdict)
|
||||
final = defaultdict(defaultdict)
|
||||
final_query: dict = defaultdict(defaultdict)
|
||||
final: dict = defaultdict(defaultdict)
|
||||
for succ, resp in successes:
|
||||
final_query[succ.module][succ.method] = {}
|
||||
final[succ.module][succ.method] = resp
|
||||
@@ -433,16 +437,14 @@ async def get_legacy_fixture(protocol, *, discovery_info):
|
||||
try:
|
||||
final = await protocol.query(final_query)
|
||||
except Exception as ex:
|
||||
_echo_error(f"Unable to query all successes at once: {ex}", bold=True, fg="red")
|
||||
_echo_error(f"Unable to query all successes at once: {ex}")
|
||||
finally:
|
||||
await protocol.close()
|
||||
if discovery_info and not discovery_info.get("system"):
|
||||
# Need to recreate a DiscoverResult here because we don't want the aliases
|
||||
# in the fixture, we want the actual field names as returned by the device.
|
||||
dr = DiscoveryResult.from_dict(protocol._discovery_info)
|
||||
final["discovery_result"] = dr.dict(
|
||||
by_alias=False, exclude_unset=True, exclude_none=True, exclude_defaults=True
|
||||
)
|
||||
dr = DiscoveryResult.from_dict(discovery_info)
|
||||
final["discovery_result"] = dr.to_dict()
|
||||
|
||||
click.echo("Got %s successes" % len(successes))
|
||||
click.echo(click.style("## device info file ##", bold=True))
|
||||
@@ -817,23 +819,21 @@ async def get_smart_test_calls(protocol: SmartProtocol):
|
||||
|
||||
def get_smart_child_fixture(response):
|
||||
"""Get a seperate fixture for the child device."""
|
||||
info = response["get_device_info"]
|
||||
hw_version = info["hw_ver"]
|
||||
sw_version = info["fw_ver"]
|
||||
sw_version = sw_version.split(" ", maxsplit=1)[0]
|
||||
model = info["model"]
|
||||
if region := info.get("specs"):
|
||||
model += f"({region})"
|
||||
|
||||
save_filename = f"{model}_{hw_version}_{sw_version}.json"
|
||||
model_info = SmartDevice._get_device_info(response, None)
|
||||
hw_version = model_info.hardware_version
|
||||
fw_version = model_info.firmware_version
|
||||
model = model_info.long_name
|
||||
if model_info.region is not None:
|
||||
model = f"{model}({model_info.region})"
|
||||
save_filename = f"{model}_{hw_version}_{fw_version}.json"
|
||||
return FixtureResult(
|
||||
filename=save_filename, folder=SMART_CHILD_FOLDER, data=response
|
||||
)
|
||||
|
||||
|
||||
async def get_smart_fixtures(
|
||||
protocol: SmartProtocol, *, discovery_info=None, batch_size: int
|
||||
):
|
||||
protocol: SmartProtocol, *, discovery_info: dict[str, Any] | None, batch_size: int
|
||||
) -> list[FixtureResult]:
|
||||
"""Get fixture for new TAPO style protocol."""
|
||||
if isinstance(protocol, SmartCameraProtocol):
|
||||
test_calls, successes = await get_smart_camera_test_calls(protocol)
|
||||
@@ -964,23 +964,17 @@ async def get_smart_fixtures(
|
||||
|
||||
if "get_device_info" in final:
|
||||
# smart protocol
|
||||
hw_version = final["get_device_info"]["hw_ver"]
|
||||
sw_version = final["get_device_info"]["fw_ver"]
|
||||
if discovery_info:
|
||||
model = discovery_info["device_model"]
|
||||
else:
|
||||
model = final["get_device_info"]["model"] + "(XX)"
|
||||
sw_version = sw_version.split(" ", maxsplit=1)[0]
|
||||
model_info = SmartDevice._get_device_info(final, discovery_info)
|
||||
copy_folder = SMART_FOLDER
|
||||
else:
|
||||
# smart camera protocol
|
||||
model_info = SmartCamera._get_device_info(final, discovery_info)
|
||||
model = model_info.long_name
|
||||
hw_version = model_info.hardware_version
|
||||
sw_version = model_info.firmare_version
|
||||
if model_info.region is not None:
|
||||
model = f"{model}({model_info.region})"
|
||||
copy_folder = SMARTCAMERA_FOLDER
|
||||
hw_version = model_info.hardware_version
|
||||
sw_version = model_info.firmware_version
|
||||
model = model_info.long_name
|
||||
if model_info.region is not None:
|
||||
model = f"{model}({model_info.region})"
|
||||
|
||||
save_filename = f"{model}_{hw_version}_{sw_version}.json"
|
||||
|
||||
|
@@ -1,15 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
"""Script that checks supported devices and updates README.md and SUPPORTED.md."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from string import Template
|
||||
from typing import NamedTuple
|
||||
from typing import Any, NamedTuple
|
||||
|
||||
from kasa.device_factory import _get_device_type_from_sys_info
|
||||
from kasa.device_type import DeviceType
|
||||
from kasa.iot import IotDevice
|
||||
from kasa.smart import SmartDevice
|
||||
from kasa.smartcamera import SmartCamera
|
||||
|
||||
@@ -17,7 +19,7 @@ from kasa.smartcamera import SmartCamera
|
||||
class SupportedVersion(NamedTuple):
|
||||
"""Supported version."""
|
||||
|
||||
region: str
|
||||
region: str | None
|
||||
hw: str
|
||||
fw: str
|
||||
auth: bool
|
||||
@@ -45,6 +47,7 @@ README_FILENAME = "README.md"
|
||||
|
||||
IOT_FOLDER = "tests/fixtures/"
|
||||
SMART_FOLDER = "tests/fixtures/smart/"
|
||||
SMART_CHILD_FOLDER = "tests/fixtures/smart/child"
|
||||
SMARTCAMERA_FOLDER = "tests/fixtures/smartcamera/"
|
||||
|
||||
|
||||
@@ -59,9 +62,10 @@ def generate_supported(args):
|
||||
|
||||
supported = {"kasa": {}, "tapo": {}}
|
||||
|
||||
_get_iot_supported(supported)
|
||||
_get_smart_supported(supported)
|
||||
_get_smartcamera_supported(supported)
|
||||
_get_supported_devices(supported, IOT_FOLDER, IotDevice)
|
||||
_get_supported_devices(supported, SMART_FOLDER, SmartDevice)
|
||||
_get_supported_devices(supported, SMART_CHILD_FOLDER, SmartDevice)
|
||||
_get_supported_devices(supported, SMARTCAMERA_FOLDER, SmartCamera)
|
||||
|
||||
readme_updated = _update_supported_file(
|
||||
README_FILENAME, _supported_summary(supported), print_diffs
|
||||
@@ -201,49 +205,16 @@ def _supported_text(
|
||||
return brands
|
||||
|
||||
|
||||
def _get_smart_supported(supported):
|
||||
for file in Path(SMART_FOLDER).glob("**/*.json"):
|
||||
def _get_supported_devices(
|
||||
supported: dict[str, Any],
|
||||
fixture_location: str,
|
||||
device_cls: type[IotDevice | SmartDevice | SmartCamera],
|
||||
):
|
||||
for file in Path(fixture_location).glob("*.json"):
|
||||
with file.open() as f:
|
||||
fixture_data = json.load(f)
|
||||
|
||||
if "discovery_result" in fixture_data:
|
||||
model, _, region = fixture_data["discovery_result"][
|
||||
"device_model"
|
||||
].partition("(")
|
||||
device_type = fixture_data["discovery_result"]["device_type"]
|
||||
else: # child devices of hubs do not have discovery result
|
||||
model = fixture_data["get_device_info"]["model"]
|
||||
region = fixture_data["get_device_info"].get("specs")
|
||||
device_type = fixture_data["get_device_info"]["type"]
|
||||
# P100 doesn't have region HW
|
||||
region = region.replace(")", "") if region else ""
|
||||
|
||||
_protocol, devicetype = device_type.split(".")
|
||||
brand = devicetype[:4].lower()
|
||||
components = [
|
||||
component["id"]
|
||||
for component in fixture_data["component_nego"]["component_list"]
|
||||
]
|
||||
dt = SmartDevice._get_device_type_from_components(components, device_type)
|
||||
supported_type = DEVICE_TYPE_TO_PRODUCT_GROUP[dt]
|
||||
|
||||
hw_version = fixture_data["get_device_info"]["hw_ver"]
|
||||
fw_version = fixture_data["get_device_info"]["fw_ver"]
|
||||
fw_version = fw_version.split(" ", maxsplit=1)[0]
|
||||
|
||||
stype = supported[brand].setdefault(supported_type, {})
|
||||
smodel = stype.setdefault(model, [])
|
||||
smodel.append(
|
||||
SupportedVersion(region=region, hw=hw_version, fw=fw_version, auth=True)
|
||||
)
|
||||
|
||||
|
||||
def _get_smartcamera_supported(supported):
|
||||
for file in Path(SMARTCAMERA_FOLDER).glob("**/*.json"):
|
||||
with file.open() as f:
|
||||
fixture_data = json.load(f)
|
||||
|
||||
model_info = SmartCamera._get_device_info(
|
||||
model_info = device_cls._get_device_info(
|
||||
fixture_data, fixture_data.get("discovery_result")
|
||||
)
|
||||
|
||||
@@ -255,30 +226,12 @@ def _get_smartcamera_supported(supported):
|
||||
SupportedVersion(
|
||||
region=model_info.region,
|
||||
hw=model_info.hardware_version,
|
||||
fw=model_info.firmare_version,
|
||||
fw=model_info.firmware_version,
|
||||
auth=model_info.requires_auth,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _get_iot_supported(supported):
|
||||
for file in Path(IOT_FOLDER).glob("*.json"):
|
||||
with file.open() as f:
|
||||
fixture_data = json.load(f)
|
||||
sysinfo = fixture_data["system"]["get_sysinfo"]
|
||||
dt = _get_device_type_from_sys_info(fixture_data)
|
||||
supported_type = DEVICE_TYPE_TO_PRODUCT_GROUP[dt]
|
||||
|
||||
model, _, region = sysinfo["model"][:-1].partition("(")
|
||||
auth = "discovery_result" in fixture_data
|
||||
stype = supported["kasa"].setdefault(supported_type, {})
|
||||
smodel = stype.setdefault(model, [])
|
||||
fw = sysinfo["sw_ver"].split(" ", maxsplit=1)[0]
|
||||
smodel.append(
|
||||
SupportedVersion(region=region, hw=sysinfo["hw_ver"], fw=fw, auth=auth)
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
"""Entry point to module."""
|
||||
generate_supported(sys.argv[1:])
|
||||
|
Reference in New Issue
Block a user