From 9d84bb74e7b88b805c368ccbf3c7dc6d466f9f2e Mon Sep 17 00:00:00 2001 From: FreeKC Date: Wed, 30 Sep 2026 00:40:39 +0200 Subject: [PATCH] Discovery: accept cameras that only send the encrypt_type list (#1770) The C460 on firmware 1.2.2 answers the UDP discovery with `mgt_encrypt_schm: {"is_support_https": true}` and `encrypt_type: ["3"]`, but no `encrypt_type` inside the scheme and no `encrypt_info`. `_get_connection_parameters` only looks at those two places for the encryption type, so the camera ends up as "Unsupported device ... with no encryption type" even though it works with the same AES login as every other camera. This uses the top level list as a last resort: when nothing else names the encryption type, the device supports https and the list says 3, treat it as AES. Co-authored-by: freeKC <7538438+freeKC@users.noreply.github.com> --- kasa/discover.py | 7 +++++++ tests/test_discovery.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/kasa/discover.py b/kasa/discover.py index 911c005c..fa95618c 100755 --- a/kasa/discover.py +++ b/kasa/discover.py @@ -831,6 +831,13 @@ class Discover: # Reuse the login_version attribute to pass the max to transport login_version = max([int(i) for i in et]) + if not encrypt_type and encrypt_schm.is_support_https and login_version == 3: + # Some camera firmwares (C460 1.2.2 for one) leave encrypt_type out + # of mgt_encrypt_schm and send no encrypt_info, only the top level + # encrypt_type list. "3" is the AES login that every other camera + # reports as sym_schm AES. + encrypt_type = DeviceEncryptionType.Aes.value + if not encrypt_type: raise UnsupportedDeviceError( f"Unsupported device {discovery_result.ip} of type {type_} " diff --git a/tests/test_discovery.py b/tests/test_discovery.py index e2b5042a..8ad45b85 100644 --- a/tests/test_discovery.py +++ b/tests/test_discovery.py @@ -31,6 +31,8 @@ from kasa.device_factory import ( from kasa.deviceconfig import ( DeviceConfig, DeviceConnectionParameters, + DeviceEncryptionType, + DeviceFamily, ) from kasa.discover import ( DiscoveryResult, @@ -749,3 +751,29 @@ async def test_discovery_device_repr(discovery_mock, mocker): assert "update() needed" not in repr_ else: assert "update() needed" in repr_ + + +async def test_connection_parameters_from_encrypt_type_list_only(): + """Cameras that send only the encrypt_type list are treated as AES login.""" + result = { + "device_type": "SMART.IPCAMERA", + "device_model": "C460", + "device_id": "0000000000000000000000000000000000000000", + "ip": "127.0.0.123", + "mac": "7C-F1-7E-00-00-00", + "mgt_encrypt_schm": {"is_support_https": True}, + "encrypt_type": ["3"], + "firmware_version": "1.2.2 Build 260416 Rel.13928n", + "hardware_version": "1.0", + } + params = Discover._get_connection_parameters(DiscoveryResult.from_dict(result)) + + assert params.device_family is DeviceFamily.SmartIpCamera + assert params.encryption_type is DeviceEncryptionType.Aes + assert params.login_version == 3 + assert params.https is True + + # Without the "3" hint the device is still reported as unsupported + result["encrypt_type"] = ["9"] + with pytest.raises(UnsupportedDeviceError, match="no encryption type"): + Discover._get_connection_parameters(DiscoveryResult.from_dict(result))