Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
17c22fb
Implement KlapTransportV3 for new_klap
ZeliardM Sep 29, 2025
1dea040
Fix test coverages
ZeliardM Sep 29, 2025
047efc4
Fix deviceconfig test coverage
ZeliardM Sep 29, 2025
81885d3
Fix new_klap with deviceconfig and try_connect_all
ZeliardM Sep 29, 2025
ffa5960
Remove KlapTransportV3 and correct new_klap discovery
ZeliardM Oct 2, 2025
2eb3977
Fix copilot assertation comments
ZeliardM Oct 2, 2025
2b6e35b
Reverse janitoring for separate PR
ZeliardM Oct 3, 2025
11c2143
Add comment for new_klap XOR transport selection
ZeliardM Oct 3, 2025
8229dee
Change new_klap transport from XOR to KlapTransportV2
ZeliardM Oct 7, 2025
5547172
Return dump_devinfo to exclude system
ZeliardM Oct 7, 2025
0b75c26
Change device creation to async to handle new_klap and tests
ZeliardM Oct 7, 2025
12d97cc
Correct test_discovery.py to handle all code changes
ZeliardM Oct 7, 2025
0390356
Fix test parameters
ZeliardM Oct 7, 2025
3857d65
Change new_klap to boolean
ZeliardM Oct 12, 2025
be34a58
Merge branch 'python-kasa:master' into feature/new-klap
ZeliardM Oct 18, 2025
496cbb6
Quick test fixes
ZeliardM Oct 31, 2025
86349ed
Merge branch 'python-kasa:master' into feature/new-klap
ZeliardM Nov 4, 2025
e9fc5dc
Update discover and tests for new fixtures
ZeliardM Nov 7, 2025
5a6aa03
Add CLI encrypt_type KLAPV2
ZeliardM Nov 12, 2025
d3add0b
Merge remote-tracking branch 'upstream/master' into feature/new-klap
ZeliardM Nov 13, 2025
2e051e4
Update device_models for L430P Bulb
ZeliardM Nov 13, 2025
b9d96e9
Fix tests and KLAPV2 encrypt-type call
ZeliardM Dec 9, 2025
87b6741
Merge branch 'python-kasa:master' into feature/new-klap
ZeliardM Dec 9, 2025
06cc424
Merge branch 'master' into feature/new-klap
ZeliardM Jan 27, 2026
9e75565
Update device_models for new supported devices
ZeliardM Jan 27, 2026
d50176d
Rework discovery and device handling and tests
ZeliardM Feb 22, 2026
f23297a
Merge branch 'master' into feature/new-klap
ZeliardM Feb 22, 2026
0ae3bd0
Fix tests
ZeliardM Feb 22, 2026
de6e025
Clean up comments
ZeliardM Feb 22, 2026
3de1d57
Fix tests
ZeliardM Feb 22, 2026
aa8b2aa
Update dump_devinfo to handle KLAPV2 flag if used.
ZeliardM Feb 22, 2026
2d0b37b
Merge branch 'python-kasa:master' into feature/new-klap
ZeliardM Feb 22, 2026
b196082
Merge branch 'python-kasa:master' into feature/new-klap
ZeliardM Feb 27, 2026
74b0452
Merge branch 'python-kasa:master' into feature/new-klap
ZeliardM Mar 4, 2026
00847a0
Merge branch 'python-kasa:master' into feature/new-klap
ZeliardM Apr 5, 2026
f1948c5
Merge branch 'python-kasa:master' into feature/new-klap
ZeliardM Jul 8, 2026
71a4147
Address new_klap review follow-ups
ZeliardM Jul 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ The following devices have been tested and confirmed as working. If your device
### Supported Kasa devices

- **Plugs**: EP10, EP25[^2], HS100[^2], HS103, HS105, HS110, KP100, KP105, KP115, KP125, KP125M[^1], KP401
- **Power Strips**: EP40, EP40M[^1], HS107, HS300, KP200, KP303, KP400
- **Power Strips**: EP40, EP40M[^1], HS107, HS300[^2], KP200, KP303, KP400
- **Wall Switches**: ES20M, HS200[^2], HS210, HS220[^2], KP405, KS200, KS200M, KS205[^1], KS220, KS220M, KS225[^1], KS230, KS240[^1]
- **Bulbs**: KL110, KL110B, KL120, KL125, KL130, KL135, KL50, KL60, LB100, LB110, LB130
- **Light Strips**: KL400L10, KL400L5, KL420L5, KL430
Expand Down
1 change: 1 addition & 0 deletions SUPPORTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Some newer Kasa devices require authentication. These are marked with [^1] in th
- Hardware: 1.0 (US) / Firmware: 1.0.21
- Hardware: 2.0 (US) / Firmware: 1.0.12
- Hardware: 2.0 (US) / Firmware: 1.0.3
- Hardware: 2.0 (US) / Firmware: 1.1.2[^1]
- **KP200**
- Hardware: 3.0 (US) / Firmware: 1.0.3
- **KP303**
Expand Down
6 changes: 6 additions & 0 deletions devtools/dump_devinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ def capture_raw(discovered: DiscoveredRaw):
login_version=dr.mgt_encrypt_schm.lv,
https=dr.mgt_encrypt_schm.is_support_https,
http_port=dr.mgt_encrypt_schm.http_port,
new_klap=dr.mgt_encrypt_schm.new_klap,
)
dc = DeviceConfig(
host=host,
Expand All @@ -320,11 +321,16 @@ def capture_raw(discovered: DiscoveredRaw):
batch_size=batch_size,
)
elif device_family and encrypt_type:
new_klap = None
if encrypt_type == DeviceEncryptionType.Klapv2.value:
encrypt_type = DeviceEncryptionType.Klap.value
new_klap = True
ctype = DeviceConnectionParameters(
DeviceFamily(device_family),
DeviceEncryptionType(encrypt_type),
login_version,
https,
new_klap=new_klap,
)
config = DeviceConfig(
host=host,
Expand Down
11 changes: 10 additions & 1 deletion kasa/cli/discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
Discover,
UnsupportedDeviceError,
)
from kasa.deviceconfig import DeviceConnectionParameters, DeviceEncryptionType
from kasa.discover import (
NEW_DISCOVERY_REDACTORS,
ConnectAttempt,
Expand Down Expand Up @@ -59,6 +60,13 @@ def _discover_is_root_cmd(ctx: click.Context) -> bool:
)


def _get_cli_encrypt_type(cparams: DeviceConnectionParameters) -> str:
"""Return the encryption type value needed to recreate the connection."""
if cparams.new_klap:
return DeviceEncryptionType.Klapv2.value
return cparams.encryption_type.value


@discover.command()
@click.pass_context
async def detail(ctx: click.Context) -> DeviceDict:
Expand Down Expand Up @@ -275,10 +283,11 @@ def on_attempt(connect_attempt: ConnectAttempt, success: bool) -> None:
)
if dev:
cparams = dev.config.connection_type
encrypt_type = _get_cli_encrypt_type(cparams)
echo("Managed to connect, cli options to connect are:")
echo(
f"--device-family {cparams.device_family.value} "
f"--encrypt-type {cparams.encryption_type.value} "
f"--encrypt-type {encrypt_type} "
f"{'--https' if cparams.https else '--no-https'}"
)
return {host: dev}
Expand Down
6 changes: 6 additions & 0 deletions kasa/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,11 +325,17 @@ async def cli(
if not encrypt_type:
encrypt_type = "KLAP"

new_klap = None
if encrypt_type and encrypt_type == DeviceEncryptionType.Klapv2.value:
encrypt_type = DeviceEncryptionType.Klap.value
new_klap = True

ctype = DeviceConnectionParameters(
DeviceFamily(device_family),
DeviceEncryptionType(encrypt_type),
login_version,
https,
new_klap=new_klap,
)
config = DeviceConfig(
host=host,
Expand Down
32 changes: 18 additions & 14 deletions kasa/device_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,20 @@ def _perf_log(has_params: bool, perf_type: str) -> None:
device_class: type[Device] | None
device: Device | None = None

if isinstance(protocol, IotProtocol) and isinstance(
protocol._transport, XorTransport
):
info = await protocol.query(GET_SYSINFO_QUERY)
_perf_log(True, "get_sysinfo")
device_class = get_device_class_from_sys_info(info)
device = device_class(config.host, protocol=protocol)
device.update_from_discover_info(info)
await device.update()
_perf_log(True, "update")
return device
elif device_class := get_device_class_from_family(
if device_class := get_device_class_from_family(
config.connection_type.device_family.value, https=config.connection_type.https
):
device = device_class(host=config.host, protocol=protocol)
if issubclass(device_class, IotDevice):
# IoT devices report a generic device family (e.g. IOT.SMARTPLUGSWITCH)
# that does not distinguish plug/strip/switch/etc. Query sysinfo for
# the precise subclass regardless of which transport is in use.
info = await protocol.query(GET_SYSINFO_QUERY)
_perf_log(True, "get_sysinfo")
device_class = get_device_class_from_sys_info(info)
Comment thread
ZeliardM marked this conversation as resolved.
device = device_class(config.host, protocol=protocol)
device.update_from_discover_info(info)
else:
device = device_class(host=config.host, protocol=protocol)
await device.update()
_perf_log(True, "update")
return device
Expand Down Expand Up @@ -146,7 +145,10 @@ def get_device_class_from_sys_info(sysinfo: dict[str, Any]) -> type[IotDevice]:


def get_device_class_from_family(
device_type: str, *, https: bool, require_exact: bool = False
device_type: str,
*,
https: bool,
require_exact: bool = False,
) -> type[Device] | None:
"""Return the device class from the type name."""
supported_device_types: dict[str, type[Device]] = {
Expand Down Expand Up @@ -221,6 +223,7 @@ def get_protocol(config: DeviceConfig, *, strict: bool = False) -> BaseProtocol
+ "."
+ ctype.encryption_type.value
+ (".HTTPS" if ctype.https else "")
+ (".NEW_KLAP" if ctype.new_klap else "")
)

_LOGGER.debug("Finding transport for %s", protocol_transport_key)
Expand All @@ -229,6 +232,7 @@ def get_protocol(config: DeviceConfig, *, strict: bool = False) -> BaseProtocol
] = {
"IOT.XOR": (IotProtocol, XorTransport),
"IOT.KLAP": (IotProtocol, KlapTransport),
"IOT.KLAP.NEW_KLAP": (IotProtocol, KlapTransportV2),
"SMART.AES": (SmartProtocol, AesTransport),
"SMART.KLAP": (SmartProtocol, KlapTransportV2),
"SMART.KLAP.HTTPS": (SmartProtocol, KlapTransportV2),
Expand Down
4 changes: 4 additions & 0 deletions kasa/deviceconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class DeviceEncryptionType(Enum):
Klap = "KLAP"
Aes = "AES"
Xor = "XOR"
Klapv2 = "KLAPV2"


class DeviceFamily(Enum):
Expand Down Expand Up @@ -101,6 +102,7 @@ class DeviceConnectionParameters(_DeviceConfigBaseMixin):
login_version: int | None = None
https: bool = False
http_port: int | None = None
new_klap: bool | None = None

@staticmethod
def from_values(
Expand All @@ -110,6 +112,7 @@ def from_values(
login_version: int | None = None,
https: bool | None = None,
http_port: int | None = None,
new_klap: bool | None = None,
) -> DeviceConnectionParameters:
"""Return connection parameters from string values."""
try:
Expand All @@ -121,6 +124,7 @@ def from_values(
login_version,
https,
http_port=http_port,
new_klap=new_klap,
)
except (ValueError, TypeError) as ex:
raise KasaException(
Expand Down
Loading
Loading