Make discovery on unsupported devices less noisy (#1291)

This commit is contained in:
Teemu R. 2024-11-21 19:22:54 +01:00 committed by GitHub
parent 5221fc07ca
commit f2ba23301a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 32 additions and 7 deletions

View File

@ -164,7 +164,7 @@ def get_device_class_from_family(
and device_type.startswith("SMART.") and device_type.startswith("SMART.")
and not require_exact and not require_exact
): ):
_LOGGER.warning("Unknown SMART device with %s, using SmartDevice", device_type) _LOGGER.debug("Unknown SMART device with %s, using SmartDevice", device_type)
cls = SmartDevice cls = SmartDevice
return cls return cls

View File

@ -715,6 +715,7 @@ class Discover:
raise KasaException( raise KasaException(
f"Unable to read response from device: {config.host}: {ex}" f"Unable to read response from device: {config.host}: {ex}"
) from ex ) from ex
try: try:
discovery_result = DiscoveryResult.from_dict(info["result"]) discovery_result = DiscoveryResult.from_dict(info["result"])
except Exception as ex: except Exception as ex:
@ -733,6 +734,7 @@ class Discover:
f"Unable to parse discovery from device: {config.host}: {ex}", f"Unable to parse discovery from device: {config.host}: {ex}",
host=config.host, host=config.host,
) from ex ) from ex
# Decrypt the data # Decrypt the data
if ( if (
encrypt_info := discovery_result.encrypt_info encrypt_info := discovery_result.encrypt_info
@ -746,11 +748,13 @@ class Discover:
type_ = discovery_result.device_type type_ = discovery_result.device_type
encrypt_schm = discovery_result.mgt_encrypt_schm encrypt_schm = discovery_result.mgt_encrypt_schm
try: try:
if not (encrypt_type := encrypt_schm.encrypt_type) and ( if not (encrypt_type := encrypt_schm.encrypt_type) and (
encrypt_info := discovery_result.encrypt_info encrypt_info := discovery_result.encrypt_info
): ):
encrypt_type = encrypt_info.sym_schm encrypt_type = encrypt_info.sym_schm
if not encrypt_type: if not encrypt_type:
raise UnsupportedDeviceError( raise UnsupportedDeviceError(
f"Unsupported device {config.host} of type {type_} " f"Unsupported device {config.host} of type {type_} "
@ -771,19 +775,21 @@ class Discover:
discovery_result=discovery_result.to_dict(), discovery_result=discovery_result.to_dict(),
host=config.host, host=config.host,
) from ex ) from ex
if ( if (
device_class := get_device_class_from_family( device_class := get_device_class_from_family(
type_, https=encrypt_schm.is_support_https type_, https=encrypt_schm.is_support_https
) )
) is None: ) is None:
_LOGGER.warning("Got unsupported device type: %s", type_) _LOGGER.debug("Got unsupported device type: %s", type_)
raise UnsupportedDeviceError( raise UnsupportedDeviceError(
f"Unsupported device {config.host} of type {type_}: {info}", f"Unsupported device {config.host} of type {type_}: {info}",
discovery_result=discovery_result.to_dict(), discovery_result=discovery_result.to_dict(),
host=config.host, host=config.host,
) )
if (protocol := get_protocol(config)) is None: if (protocol := get_protocol(config)) is None:
_LOGGER.warning( _LOGGER.debug(
"Got unsupported connection type: %s", config.connection_type.to_dict() "Got unsupported connection type: %s", config.connection_type.to_dict()
) )
raise UnsupportedDeviceError( raise UnsupportedDeviceError(
@ -800,6 +806,7 @@ class Discover:
else info else info
) )
_LOGGER.debug("[DISCOVERY] %s << %s", config.host, pf(data)) _LOGGER.debug("[DISCOVERY] %s << %s", config.host, pf(data))
device = device_class(config.host, protocol=protocol) device = device_class(config.host, protocol=protocol)
di = discovery_result.to_dict() di = discovery_result.to_dict()

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import copy import copy
from dataclasses import dataclass from dataclasses import dataclass
from json import dumps as json_dumps from json import dumps as json_dumps
from typing import Any, TypedDict
import pytest import pytest
@ -16,10 +17,21 @@ from .fixtureinfo import FixtureInfo, filter_fixtures, idgenerator
DISCOVERY_MOCK_IP = "127.0.0.123" DISCOVERY_MOCK_IP = "127.0.0.123"
def _make_unsupported(device_family, encrypt_type, *, omit_keys=None): class DiscoveryResponse(TypedDict):
result: dict[str, Any]
error_code: int
def _make_unsupported(
device_family,
encrypt_type,
*,
https: bool = False,
omit_keys: dict[str, Any] | None = None,
) -> DiscoveryResponse:
if omit_keys is None: if omit_keys is None:
omit_keys = {"encrypt_info": None} omit_keys = {"encrypt_info": None}
result = { result: DiscoveryResponse = {
"result": { "result": {
"device_id": "xx", "device_id": "xx",
"owner": "xx", "owner": "xx",
@ -31,7 +43,7 @@ def _make_unsupported(device_family, encrypt_type, *, omit_keys=None):
"obd_src": "tplink", "obd_src": "tplink",
"factory_default": False, "factory_default": False,
"mgt_encrypt_schm": { "mgt_encrypt_schm": {
"is_support_https": False, "is_support_https": https,
"encrypt_type": encrypt_type, "encrypt_type": encrypt_type,
"http_port": 80, "http_port": 80,
"lv": 2, "lv": 2,
@ -51,6 +63,7 @@ def _make_unsupported(device_family, encrypt_type, *, omit_keys=None):
UNSUPPORTED_DEVICES = { UNSUPPORTED_DEVICES = {
"unknown_device_family": _make_unsupported("SMART.TAPOXMASTREE", "AES"), "unknown_device_family": _make_unsupported("SMART.TAPOXMASTREE", "AES"),
"unknown_iot_device_family": _make_unsupported("IOT.IOTXMASTREE", "AES"),
"wrong_encryption_iot": _make_unsupported("IOT.SMARTPLUGSWITCH", "AES"), "wrong_encryption_iot": _make_unsupported("IOT.SMARTPLUGSWITCH", "AES"),
"wrong_encryption_smart": _make_unsupported("SMART.TAPOBULB", "IOT"), "wrong_encryption_smart": _make_unsupported("SMART.TAPOBULB", "IOT"),
"unknown_encryption": _make_unsupported("IOT.SMARTPLUGSWITCH", "FOO"), "unknown_encryption": _make_unsupported("IOT.SMARTPLUGSWITCH", "FOO"),
@ -64,6 +77,11 @@ UNSUPPORTED_DEVICES = {
"FOO", "FOO",
omit_keys={"mgt_encrypt_schm": None}, omit_keys={"mgt_encrypt_schm": None},
), ),
"invalidinstance": _make_unsupported(
"IOT.SMARTPLUGSWITCH",
"KLAP",
https=True,
),
} }

View File

@ -195,6 +195,6 @@ async def test_device_types(dev: Device):
async def test_device_class_from_unknown_family(caplog): async def test_device_class_from_unknown_family(caplog):
"""Verify that unknown SMART devices yield a warning and fallback to SmartDevice.""" """Verify that unknown SMART devices yield a warning and fallback to SmartDevice."""
dummy_name = "SMART.foo" dummy_name = "SMART.foo"
with caplog.at_level(logging.WARNING): with caplog.at_level(logging.DEBUG):
assert get_device_class_from_family(dummy_name, https=False) == SmartDevice assert get_device_class_from_family(dummy_name, https=False) == SmartDevice
assert f"Unknown SMART device with {dummy_name}" in caplog.text assert f"Unknown SMART device with {dummy_name}" in caplog.text