From f2ba23301a7bc3005e6acc04feda10e54497333b Mon Sep 17 00:00:00 2001 From: "Teemu R." Date: Thu, 21 Nov 2024 19:22:54 +0100 Subject: [PATCH] Make discovery on unsupported devices less noisy (#1291) --- kasa/device_factory.py | 2 +- kasa/discover.py | 11 +++++++++-- tests/discovery_fixtures.py | 24 +++++++++++++++++++++--- tests/test_device_factory.py | 2 +- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/kasa/device_factory.py b/kasa/device_factory.py index dab86799..f0b90b6e 100755 --- a/kasa/device_factory.py +++ b/kasa/device_factory.py @@ -164,7 +164,7 @@ def get_device_class_from_family( and device_type.startswith("SMART.") 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 return cls diff --git a/kasa/discover.py b/kasa/discover.py index 74b663e8..75651b7f 100755 --- a/kasa/discover.py +++ b/kasa/discover.py @@ -715,6 +715,7 @@ class Discover: raise KasaException( f"Unable to read response from device: {config.host}: {ex}" ) from ex + try: discovery_result = DiscoveryResult.from_dict(info["result"]) except Exception as ex: @@ -733,6 +734,7 @@ class Discover: f"Unable to parse discovery from device: {config.host}: {ex}", host=config.host, ) from ex + # Decrypt the data if ( encrypt_info := discovery_result.encrypt_info @@ -746,11 +748,13 @@ class Discover: type_ = discovery_result.device_type encrypt_schm = discovery_result.mgt_encrypt_schm + try: if not (encrypt_type := encrypt_schm.encrypt_type) and ( encrypt_info := discovery_result.encrypt_info ): encrypt_type = encrypt_info.sym_schm + if not encrypt_type: raise UnsupportedDeviceError( f"Unsupported device {config.host} of type {type_} " @@ -771,19 +775,21 @@ class Discover: discovery_result=discovery_result.to_dict(), host=config.host, ) from ex + if ( device_class := get_device_class_from_family( type_, https=encrypt_schm.is_support_https ) ) is None: - _LOGGER.warning("Got unsupported device type: %s", type_) + _LOGGER.debug("Got unsupported device type: %s", type_) raise UnsupportedDeviceError( f"Unsupported device {config.host} of type {type_}: {info}", discovery_result=discovery_result.to_dict(), host=config.host, ) + if (protocol := get_protocol(config)) is None: - _LOGGER.warning( + _LOGGER.debug( "Got unsupported connection type: %s", config.connection_type.to_dict() ) raise UnsupportedDeviceError( @@ -800,6 +806,7 @@ class Discover: else info ) _LOGGER.debug("[DISCOVERY] %s << %s", config.host, pf(data)) + device = device_class(config.host, protocol=protocol) di = discovery_result.to_dict() diff --git a/tests/discovery_fixtures.py b/tests/discovery_fixtures.py index e272cef8..f8df4397 100644 --- a/tests/discovery_fixtures.py +++ b/tests/discovery_fixtures.py @@ -3,6 +3,7 @@ from __future__ import annotations import copy from dataclasses import dataclass from json import dumps as json_dumps +from typing import Any, TypedDict import pytest @@ -16,10 +17,21 @@ from .fixtureinfo import FixtureInfo, filter_fixtures, idgenerator 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: omit_keys = {"encrypt_info": None} - result = { + result: DiscoveryResponse = { "result": { "device_id": "xx", "owner": "xx", @@ -31,7 +43,7 @@ def _make_unsupported(device_family, encrypt_type, *, omit_keys=None): "obd_src": "tplink", "factory_default": False, "mgt_encrypt_schm": { - "is_support_https": False, + "is_support_https": https, "encrypt_type": encrypt_type, "http_port": 80, "lv": 2, @@ -51,6 +63,7 @@ def _make_unsupported(device_family, encrypt_type, *, omit_keys=None): UNSUPPORTED_DEVICES = { "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_smart": _make_unsupported("SMART.TAPOBULB", "IOT"), "unknown_encryption": _make_unsupported("IOT.SMARTPLUGSWITCH", "FOO"), @@ -64,6 +77,11 @@ UNSUPPORTED_DEVICES = { "FOO", omit_keys={"mgt_encrypt_schm": None}, ), + "invalidinstance": _make_unsupported( + "IOT.SMARTPLUGSWITCH", + "KLAP", + https=True, + ), } diff --git a/tests/test_device_factory.py b/tests/test_device_factory.py index 9102a528..8f9f635a 100644 --- a/tests/test_device_factory.py +++ b/tests/test_device_factory.py @@ -195,6 +195,6 @@ async def test_device_types(dev: Device): async def test_device_class_from_unknown_family(caplog): """Verify that unknown SMART devices yield a warning and fallback to SmartDevice.""" 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 f"Unknown SMART device with {dummy_name}" in caplog.text