Fix devtools for P100 and add fixture (#753)

This commit is contained in:
Steven B
2024-02-14 19:43:10 +00:00
committed by GitHub
parent 13d8d94bd5
commit 57835276e3
3 changed files with 236 additions and 27 deletions

View File

@@ -12,6 +12,7 @@ import collections.abc
import json
import logging
import re
import traceback
from collections import defaultdict, namedtuple
from pathlib import Path
from pprint import pprint
@@ -19,7 +20,7 @@ from typing import Dict, List, Union
import asyncclick as click
from devtools.helpers.smartrequests import COMPONENT_REQUESTS, SmartRequest
from devtools.helpers.smartrequests import SmartRequest, get_component_requests
from kasa import (
AuthenticationException,
Credentials,
@@ -35,6 +36,8 @@ from kasa.smart import SmartDevice
Call = namedtuple("Call", "module method")
SmartCall = namedtuple("SmartCall", "module request should_succeed")
_LOGGER = logging.getLogger(__name__)
def scrub(res):
"""Remove identifiers from the given dict."""
@@ -228,6 +231,8 @@ async def get_legacy_fixture(device):
else:
click.echo(click.style("OK", fg="green"))
successes.append((test_call, info))
finally:
await device.protocol.close()
final_query = defaultdict(defaultdict)
final = defaultdict(defaultdict)
@@ -241,7 +246,8 @@ async def get_legacy_fixture(device):
final = await device.protocol.query(final_query)
except Exception as ex:
_echo_error(f"Unable to query all successes at once: {ex}", bold=True, fg="red")
finally:
await device.protocol.close()
if device._discovery_info and not device._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.
@@ -316,7 +322,11 @@ async def _make_requests_or_exit(
_echo_error(
f"Unexpected exception querying {name} at once: {ex}",
)
if _LOGGER.isEnabledFor(logging.DEBUG):
traceback.print_stack()
exit(1)
finally:
await device.protocol.close()
async def get_smart_fixture(device: SmartDevice, batch_size: int):
@@ -367,14 +377,15 @@ async def get_smart_fixture(device: SmartDevice, batch_size: int):
for item in component_info_response["component_list"]:
component_id = item["id"]
if requests := COMPONENT_REQUESTS.get(component_id):
ver_code = item["ver_code"]
if (requests := get_component_requests(component_id, ver_code)) is not None:
component_test_calls = [
SmartCall(module=component_id, request=request, should_succeed=True)
for request in requests
]
test_calls.extend(component_test_calls)
should_succeed.extend(component_test_calls)
elif component_id not in COMPONENT_REQUESTS:
else:
click.echo(f"Skipping {component_id}..", nl=False)
click.echo(click.style("UNSUPPORTED", fg="yellow"))
@@ -396,7 +407,11 @@ async def get_smart_fixture(device: SmartDevice, batch_size: int):
if (
not test_call.should_succeed
and hasattr(ex, "error_code")
and ex.error_code == SmartErrorCode.UNKNOWN_METHOD_ERROR
and ex.error_code
in [
SmartErrorCode.UNKNOWN_METHOD_ERROR,
SmartErrorCode.TRANSPORT_NOT_AVAILABLE_ERROR,
]
):
click.echo(click.style("FAIL - EXPECTED", fg="green"))
else:
@@ -410,6 +425,8 @@ async def get_smart_fixture(device: SmartDevice, batch_size: int):
else:
click.echo(click.style("OK", fg="green"))
successes.append(test_call)
finally:
await device.protocol.close()
requests = []
for succ in successes:

View File

@@ -133,11 +133,14 @@ class SmartRequest:
return SmartRequest("get_device_usage")
@staticmethod
def device_info_list() -> List["SmartRequest"]:
def device_info_list(ver_code) -> List["SmartRequest"]:
"""Get device info list."""
if ver_code == 1:
return [SmartRequest.get_device_info()]
return [
SmartRequest.get_device_info(),
SmartRequest.get_device_usage(),
SmartRequest.get_auto_update_info(),
]
@staticmethod
@@ -149,7 +152,6 @@ class SmartRequest:
def firmware_info_list() -> List["SmartRequest"]:
"""Get info list."""
return [
SmartRequest.get_auto_update_info(),
SmartRequest.get_raw_request("get_fw_download_state"),
SmartRequest.get_raw_request("get_latest_fw"),
]
@@ -165,9 +167,13 @@ class SmartRequest:
return SmartRequest("get_device_time")
@staticmethod
def get_wireless_scan_info() -> "SmartRequest":
def get_wireless_scan_info(
params: Optional[GetRulesParams] = None
) -> "SmartRequest":
"""Get wireless scan info."""
return SmartRequest("get_wireless_scan_info")
return SmartRequest(
"get_wireless_scan_info", params or SmartRequest.GetRulesParams()
)
@staticmethod
def get_schedule_rules(params: Optional[GetRulesParams] = None) -> "SmartRequest":
@@ -294,9 +300,13 @@ class SmartRequest:
@staticmethod
def get_component_info_requests(component_nego_response) -> List["SmartRequest"]:
"""Get a list of requests based on the component info response."""
request_list = []
request_list: List["SmartRequest"] = []
for component in component_nego_response["component_list"]:
if requests := COMPONENT_REQUESTS.get(component["id"]):
if (
requests := get_component_requests(
component["id"], int(component["ver_code"])
)
) is not None:
request_list.extend(requests)
return request_list
@@ -314,8 +324,17 @@ class SmartRequest:
return request
def get_component_requests(component_id, ver_code):
"""Get the requests supported by the component and version."""
if (cr := COMPONENT_REQUESTS.get(component_id)) is None:
return None
if callable(cr):
return cr(ver_code)
return cr
COMPONENT_REQUESTS = {
"device": SmartRequest.device_info_list(),
"device": SmartRequest.device_info_list,
"firmware": SmartRequest.firmware_info_list(),
"quick_setup": [SmartRequest.qs_component_nego()],
"inherit": [SmartRequest.get_raw_request("get_inherit_info")],
@@ -324,33 +343,33 @@ COMPONENT_REQUESTS = {
"schedule": SmartRequest.schedule_info_list(),
"countdown": [SmartRequest.get_countdown_rules()],
"antitheft": [SmartRequest.get_antitheft_rules()],
"account": None,
"synchronize": None, # sync_env
"sunrise_sunset": None, # for schedules
"account": [],
"synchronize": [], # sync_env
"sunrise_sunset": [], # for schedules
"led": [SmartRequest.get_led_info()],
"cloud_connect": [SmartRequest.get_raw_request("get_connect_cloud_state")],
"iot_cloud": None,
"device_local_time": None,
"default_states": None, # in device_info
"iot_cloud": [],
"device_local_time": [],
"default_states": [], # in device_info
"auto_off": [SmartRequest.get_auto_off_config()],
"localSmart": None,
"localSmart": [],
"energy_monitoring": SmartRequest.energy_monitoring_list(),
"power_protection": SmartRequest.power_protection_list(),
"current_protection": None, # overcurrent in device_info
"matter": None,
"current_protection": [], # overcurrent in device_info
"matter": [],
"preset": [SmartRequest.get_preset_rules()],
"brightness": None, # in device_info
"color": None, # in device_info
"color_temperature": None, # in device_info
"brightness": [], # in device_info
"color": [], # in device_info
"color_temperature": [], # in device_info
"auto_light": [SmartRequest.get_auto_light_info()],
"light_effect": [SmartRequest.get_dynamic_light_effect_rules()],
"bulb_quick_control": None,
"bulb_quick_control": [],
"on_off_gradually": [SmartRequest.get_raw_request("get_on_off_gradually_info")],
"light_strip": None,
"light_strip": [],
"light_strip_lighting_effect": [
SmartRequest.get_raw_request("get_lighting_effect")
],
"music_rhythm": None, # music_rhythm_enable in device_info
"music_rhythm": [], # music_rhythm_enable in device_info
"segment": [SmartRequest.get_raw_request("get_device_segment")],
"segment_effect": [SmartRequest.get_raw_request("get_segment_effect_rule")],
}