Add KE100 EU/UK 2.6.0 fixtures and capture support (#1812)

This commit is contained in:
ogent
2026-10-31 23:31:42 +00:00
committed by GitHub
parent bd4826f1b3
commit 36f72ca753
7 changed files with 700 additions and 0 deletions

View File

@@ -190,8 +190,10 @@ Some newer Kasa devices require authentication. These are marked with [^1] in th
- **KE100** - **KE100**
- Hardware: 1.0 (EU) / Firmware: 2.4.0[^1] - Hardware: 1.0 (EU) / Firmware: 2.4.0[^1]
- Hardware: 1.0 (EU) / Firmware: 2.6.0[^1]
- Hardware: 1.0 (EU) / Firmware: 2.8.0[^1] - Hardware: 1.0 (EU) / Firmware: 2.8.0[^1]
- Hardware: 1.0 (UK) / Firmware: 2.15.0[^1] - Hardware: 1.0 (UK) / Firmware: 2.15.0[^1]
- Hardware: 1.0 (UK) / Firmware: 2.6.0[^1]
- Hardware: 1.0 (UK) / Firmware: 2.8.0[^1] - Hardware: 1.0 (UK) / Firmware: 2.8.0[^1]
- **KE110** - **KE110**
- Hardware: 1.0 (EU) / Firmware: 1.4.0[^1] - Hardware: 1.0 (EU) / Firmware: 1.4.0[^1]

View File

@@ -878,6 +878,13 @@ def scrub_child_device_ids(
_LOGGER.error( _LOGGER.error(
"Cannot find device id in child get device info: %s", child_id "Cannot find device id in child get device info: %s", child_id
) )
# Thermostats can reference another child as their temperature source
if (correction := response.get("get_temperature_correction")) and (
sensor_id := correction.get("temp_sensor_device_id")
):
correction["temp_sensor_device_id"] = scrubbed_child_id_map.get(
sensor_id, "SCRUBBED_DEVICE_ID"
)
# Scrub the device ids in the parent for smart protocol # Scrub the device ids in the parent for smart protocol
if gc := main_response.get("get_child_device_component_list"): if gc := main_response.get("get_child_device_component_list"):

View File

@@ -426,6 +426,17 @@ COMPONENT_REQUESTS = {
) )
], ],
"temp_humidity_record": [SmartRequest.get_raw_request("get_temp_humidity_records")], "temp_humidity_record": [SmartRequest.get_raw_request("get_temp_humidity_records")],
"temp_record": [SmartRequest.get_raw_request("get_temperature_records")],
"temperature_correction": [
SmartRequest.get_raw_request("get_temperature_correction")
],
"smart_control_schedule": [
SmartRequest.get_raw_request("get_sc_schedule_info"),
SmartRequest.get_raw_request(
"get_sc_schedule_rules",
SmartRequest.GetScheduleRulesParams(schedule_mode="everyday"),
),
],
"double_click": [SmartRequest.get_raw_request("get_double_click_info")], "double_click": [SmartRequest.get_raw_request("get_double_click_info")],
"child_device": [ "child_device": [
SmartRequest.get_raw_request("get_child_device_list"), SmartRequest.get_raw_request("get_child_device_list"),

View File

@@ -55,6 +55,7 @@ REDACTORS: dict[str, Callable[[Any], Any] | None] = {
"lo": lambda x: 0, # lon on ks240 "lo": lambda x: 0, # lon on ks240
"device_id": lambda x: "REDACTED_" + x[9::], "device_id": lambda x: "REDACTED_" + x[9::],
"parent_device_id": lambda x: "REDACTED_" + x[9::], # Hub attached children "parent_device_id": lambda x: "REDACTED_" + x[9::], # Hub attached children
"temp_sensor_device_id": lambda x: "REDACTED_" + x[9::], # Thermostat source
"original_device_id": lambda x: "REDACTED_" + x[9::], # Strip children "original_device_id": lambda x: "REDACTED_" + x[9::], # Strip children
"nickname": lambda x: "I01BU0tFRF9OQU1FIw==" if x else "", "nickname": lambda x: "I01BU0tFRF9OQU1FIw==" if x else "",
"mac": mask_mac, "mac": mask_mac,

View File

@@ -0,0 +1,322 @@
{
"component_nego": {
"component_list": [
{
"id": "device",
"ver_code": 2
},
{
"id": "quick_setup",
"ver_code": 3
},
{
"id": "time",
"ver_code": 1
},
{
"id": "device_local_time",
"ver_code": 1
},
{
"id": "schedule",
"ver_code": 2
},
{
"id": "countdown",
"ver_code": 2
},
{
"id": "account",
"ver_code": 1
},
{
"id": "synchronize",
"ver_code": 1
},
{
"id": "sunrise_sunset",
"ver_code": 1
},
{
"id": "cloud_connect",
"ver_code": 1
},
{
"id": "iot_cloud",
"ver_code": 1
},
{
"id": "frost_protection",
"ver_code": 1
},
{
"id": "child_protection",
"ver_code": 1
},
{
"id": "temperature",
"ver_code": 1
},
{
"id": "remove_scale",
"ver_code": 1
},
{
"id": "early_start",
"ver_code": 1
},
{
"id": "screen_setting",
"ver_code": 1
},
{
"id": "night_mode",
"ver_code": 1
},
{
"id": "firmware",
"ver_code": 1
},
{
"id": "battery_detect",
"ver_code": 1
},
{
"id": "temp_record",
"ver_code": 1
},
{
"id": "progress_calibration",
"ver_code": 1
},
{
"id": "temperature_correction",
"ver_code": 1
},
{
"id": "window_open_detect",
"ver_code": 2
},
{
"id": "shutdown_mode",
"ver_code": 1
},
{
"id": "smart_control_schedule",
"ver_code": 1
},
{
"id": "temp_control",
"ver_code": 1
}
]
},
"get_connect_cloud_state": {
"status": 0
},
"get_device_info": {
"at_low_battery": false,
"avatar": "",
"battery_percentage": 100,
"bind_count": 1,
"category": "subg.trv",
"child_protection": false,
"current_temp": 23.9,
"device_id": "SCRUBBED_CHILD_DEVICE_ID_4",
"frost_protection_on": false,
"fw_ver": "2.6.0 Build 231027 Rel.121035",
"hidden": false,
"hw_id": "00000000000000000000000000000000",
"hw_ver": "1.0",
"jamming_rssi": -121,
"jamming_signal_level": 1,
"lastOnboardingTimestamp": 1792686811,
"location": "",
"mac": "B8FBB3000000",
"max_control_temp": 30,
"min_control_temp": 5,
"model": "KE100",
"nickname": "I01BU0tFRF9OQU1FIw==",
"oem_id": "00000000000000000000000000000000",
"parent_device_id": "0000000000000000000000000000000000000000",
"region": "Europe/London",
"rssi": -43,
"signal_level": 3,
"specs": "EU",
"status": "online",
"target_temp": 20.0,
"temp_offset": 0,
"temp_unit": "celsius",
"trv_states": [],
"type": "SMART.KASAENERGY"
},
"get_fw_download_state": {
"cloud_cache_seconds": 1,
"download_progress": 0,
"reboot_time": 5,
"status": 0,
"upgrade_time": 5
},
"get_latest_fw": {
"fw_ver": "2.15.0 Build 260212 Rel.072732",
"hw_id": "00000000000000000000000000000000",
"need_to_upgrade": true,
"oem_id": "00000000000000000000000000000000",
"release_date": "2026-03-12",
"release_note": "Modifications and Bug Fixes:\n1. Added support for Standard, Powerful and Gentle valve control modes in Device Settings -> Valve Control, for better adaptation to various usage scenarios.\n2. Added support for 0.5 degrees Celsius precise temperature adjustment.\n3. Optimized device performance.",
"type": 2
},
"get_sc_schedule_info": {
"enable": true,
"mode": "everyday"
},
"get_sc_schedule_rules": {
"day_segment": 6,
"schedule_list": [
{
"id": "everyday:everyday",
"rule_list": [
{
"desired_states": {
"frost_protection_on": false,
"target_temp": 18,
"target_temp_float": 180,
"temp_unit": "celsius"
},
"end_min": 419,
"start_min": 0
},
{
"desired_states": {
"frost_protection_on": false,
"target_temp": 20,
"target_temp_float": 200,
"temp_unit": "celsius"
},
"end_min": 1319,
"start_min": 420
},
{
"desired_states": {
"frost_protection_on": false,
"target_temp": 18,
"target_temp_float": 180,
"temp_unit": "celsius"
},
"end_min": 1439,
"start_min": 1320
}
]
}
],
"schedule_mode": "everyday",
"start_index": 0,
"sum": 1
},
"get_temperature_correction": {
"offset": 0,
"temp_sensor_device_id": "SCRUBBED_CHILD_DEVICE_ID_4",
"use_other_temp_sensor": false,
"using_other_temp_sensor": false
},
"get_temperature_records": {
"temp_data": [
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
267,
266,
256,
241,
229,
237,
243,
240,
230,
236,
242,
243
]
}
}

View File

@@ -0,0 +1,334 @@
{
"component_nego": {
"component_list": [
{
"id": "device",
"ver_code": 2
},
{
"id": "quick_setup",
"ver_code": 3
},
{
"id": "time",
"ver_code": 1
},
{
"id": "device_local_time",
"ver_code": 1
},
{
"id": "schedule",
"ver_code": 2
},
{
"id": "countdown",
"ver_code": 2
},
{
"id": "account",
"ver_code": 1
},
{
"id": "synchronize",
"ver_code": 1
},
{
"id": "sunrise_sunset",
"ver_code": 1
},
{
"id": "cloud_connect",
"ver_code": 1
},
{
"id": "iot_cloud",
"ver_code": 1
},
{
"id": "frost_protection",
"ver_code": 1
},
{
"id": "child_protection",
"ver_code": 1
},
{
"id": "temperature",
"ver_code": 1
},
{
"id": "remove_scale",
"ver_code": 1
},
{
"id": "early_start",
"ver_code": 1
},
{
"id": "screen_setting",
"ver_code": 1
},
{
"id": "night_mode",
"ver_code": 1
},
{
"id": "firmware",
"ver_code": 1
},
{
"id": "battery_detect",
"ver_code": 1
},
{
"id": "temp_record",
"ver_code": 1
},
{
"id": "progress_calibration",
"ver_code": 1
},
{
"id": "temperature_correction",
"ver_code": 1
},
{
"id": "window_open_detect",
"ver_code": 2
},
{
"id": "shutdown_mode",
"ver_code": 1
},
{
"id": "smart_control_schedule",
"ver_code": 1
},
{
"id": "temp_control",
"ver_code": 1
}
]
},
"get_connect_cloud_state": {
"status": 0
},
"get_device_info": {
"at_low_battery": false,
"avatar": "",
"battery_percentage": 100,
"bind_count": 1,
"category": "subg.trv",
"child_protection": false,
"current_temp": 22.9,
"device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
"frost_protection_on": false,
"fw_ver": "2.6.0 Build 231027 Rel.121035",
"hidden": false,
"hw_id": "00000000000000000000000000000000",
"hw_ver": "1.0",
"jamming_rssi": -116,
"jamming_signal_level": 1,
"lastOnboardingTimestamp": 1792687045,
"location": "",
"mac": "0CEF15000000",
"max_control_temp": 30,
"min_control_temp": 5,
"model": "KE100",
"nickname": "I01BU0tFRF9OQU1FIw==",
"oem_id": "00000000000000000000000000000000",
"parent_device_id": "0000000000000000000000000000000000000000",
"region": "Europe/London",
"rssi": -54,
"signal_level": 3,
"specs": "UK",
"status": "online",
"target_temp": 23.0,
"temp_offset": 0,
"temp_unit": "celsius",
"trv_states": [
"heating"
],
"type": "SMART.KASAENERGY"
},
"get_fw_download_state": {
"cloud_cache_seconds": 1,
"download_progress": 0,
"reboot_time": 5,
"status": 0,
"upgrade_time": 5
},
"get_latest_fw": {
"fw_ver": "2.15.0 Build 260212 Rel.072732",
"hw_id": "00000000000000000000000000000000",
"need_to_upgrade": true,
"oem_id": "00000000000000000000000000000000",
"release_date": "2026-03-12",
"release_note": "Modifications and Bug Fixes:\n1. Added support for Standard, Powerful and Gentle valve control modes in Device Settings -> Valve Control, for better adaptation to various usage scenarios.\n2. Added support for 0.5 degrees Celsius precise temperature adjustment.\n3. Optimized device performance.",
"type": 2
},
"get_sc_schedule_info": {
"enable": true,
"mode": "everyday"
},
"get_sc_schedule_rules": {
"day_segment": 6,
"schedule_list": [
{
"id": "everyday:everyday",
"rule_list": [
{
"desired_states": {
"frost_protection_on": false,
"target_temp": 18,
"target_temp_float": 180,
"temp_unit": "celsius"
},
"end_min": 479,
"start_min": 0
},
{
"desired_states": {
"frost_protection_on": false,
"target_temp": 23,
"target_temp_float": 230,
"temp_unit": "celsius"
},
"end_min": 1319,
"start_min": 1081
},
{
"desired_states": {
"frost_protection_on": false,
"target_temp": 18,
"target_temp_float": 180,
"temp_unit": "celsius"
},
"end_min": 1439,
"start_min": 1320
},
{
"desired_states": {
"frost_protection_on": false,
"target_temp": 20,
"target_temp_float": 200,
"temp_unit": "celsius"
},
"end_min": 1080,
"start_min": 480
}
]
}
],
"schedule_mode": "everyday",
"start_index": 0,
"sum": 1
},
"get_temperature_correction": {
"offset": 0,
"temp_sensor_device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
"use_other_temp_sensor": false,
"using_other_temp_sensor": false
},
"get_temperature_records": {
"temp_data": [
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
-1000,
231,
230,
225,
222,
227,
231,
229,
227,
236,
240,
238,
235
]
}
}

View File

@@ -8,6 +8,7 @@ from devtools.dump_devinfo import (
_wrap_redactors, _wrap_redactors,
get_legacy_fixture, get_legacy_fixture,
get_smart_fixtures, get_smart_fixtures,
scrub_child_device_ids,
) )
from kasa.iot import IotDevice from kasa.iot import IotDevice
from kasa.protocols import IotProtocol from kasa.protocols import IotProtocol
@@ -157,3 +158,25 @@ async def test_iot_fixtures(fixture_info: FixtureInfo) -> None:
key: val for key, val in fixture_info.data.items() if "err_code" not in val key: val for key, val in fixture_info.data.items() if "err_code" not in val
} }
assert saved_fixture == created_fixture assert saved_fixture == created_fixture
def test_scrub_child_temperature_sensor_ids():
"""Test thermostat temperature sources are mapped to scrubbed child ids."""
children = {
"trv": {
"get_device_info": {"device_id": "trv"},
"get_temperature_correction": {"temp_sensor_device_id": "sensor"},
},
"sensor": {"get_device_info": {"device_id": "sensor"}},
"other": {
"get_device_info": {"device_id": "other"},
"get_temperature_correction": {"temp_sensor_device_id": "not-a-child"},
},
}
id_map = scrub_child_device_ids({}, children)
trv_source = children["trv"]["get_temperature_correction"]
assert trv_source["temp_sensor_device_id"] == id_map["sensor"]
other_source = children["other"]["get_temperature_correction"]
assert other_source["temp_sensor_device_id"] == "SCRUBBED_DEVICE_ID"