Update dump_devinfo for smart camera protocol (#1169)

Introduces the child camera protocol wrapper, required to get the child device info with the new protocol.
This commit is contained in:
Steven B.
2024-10-18 12:06:22 +01:00
committed by GitHub
parent 486984fff8
commit acd0202cab
6 changed files with 1076 additions and 97 deletions

View File

@@ -6,7 +6,12 @@ import logging
from pprint import pformat as pf
from typing import Any
from ..exceptions import AuthenticationError, DeviceError, _RetryableError
from ..exceptions import (
AuthenticationError,
DeviceError,
KasaException,
_RetryableError,
)
from ..json import dumps as json_dumps
from ..smartprotocol import SmartProtocol
from .sslaestransport import (
@@ -65,22 +70,28 @@ class SmartCameraProtocol(SmartProtocol):
if isinstance(request, dict):
if len(request) == 1:
multi_method = next(iter(request))
module = next(iter(request[multi_method]))
req = {
"method": multi_method[:3],
module: request[multi_method][module],
}
method = next(iter(request))
if method == "multipleRequest":
params = request["multipleRequest"]
req = {"method": "multipleRequest", "params": params}
elif method[:3] == "set":
params = next(iter(request[method]))
req = {
"method": method[:3],
params: request[method][params],
}
else:
return await self._execute_multiple_query(request, retry_count)
else:
return await self._execute_multiple_query(request, retry_count)
else:
# If method like getSomeThing then module will be some_thing
multi_method = request
method = request
snake_name = "".join(
["_" + i.lower() if i.isupper() else i for i in multi_method]
["_" + i.lower() if i.isupper() else i for i in method]
).lstrip("_")
module = snake_name[4:]
req = {"method": snake_name[:3], module: {}}
params = snake_name[4:]
req = {"method": snake_name[:3], params: {}}
smart_request = json_dumps(req)
if debug_enabled:
@@ -100,10 +111,71 @@ class SmartCameraProtocol(SmartProtocol):
if "error_code" in response_data:
# H200 does not return an error code
self._handle_response_error_code(response_data, multi_method)
self._handle_response_error_code(response_data, method)
# TODO need to update handle response lists
if multi_method[:3] == "set":
if method[:3] == "set":
return {}
return {multi_method: {module: response_data[module]}}
if method == "multipleRequest":
return {method: response_data["result"]}
return {method: {params: response_data[params]}}
class _ChildCameraProtocolWrapper(SmartProtocol):
"""Protocol wrapper for controlling child devices.
This is an internal class used to communicate with child devices,
and should not be used directly.
This class overrides query() method of the protocol to modify all
outgoing queries to use ``controlChild`` command, and unwraps the
device responses before returning to the caller.
"""
def __init__(self, device_id: str, base_protocol: SmartProtocol):
self._device_id = device_id
self._protocol = base_protocol
self._transport = base_protocol._transport
async def query(self, request: str | dict, retry_count: int = 3) -> dict:
"""Wrap request inside controlChild envelope."""
return await self._query(request, retry_count)
async def _query(self, request: str | dict, retry_count: int = 3) -> dict:
"""Wrap request inside controlChild envelope."""
if not isinstance(request, dict):
raise KasaException("Child requests must be dictionaries.")
requests = []
methods = []
for key, val in request.items():
request = {
"method": "controlChild",
"params": {
"childControl": {
"device_id": self._device_id,
"request_data": {"method": key, "params": val},
}
},
}
methods.append(key)
requests.append(request)
multipleRequest = {"multipleRequest": {"requests": requests}}
response = await self._protocol.query(multipleRequest, retry_count)
responses = response["multipleRequest"]["responses"]
response_dict = {}
for index_id, response in enumerate(responses):
response_data = response["result"]["response_data"]
method = methods[index_id]
self._handle_response_error_code(
response_data, method, raise_on_error=False
)
response_dict[method] = response_data.get("result")
return response_dict
async def close(self) -> None:
"""Do nothing as the parent owns the protocol."""

View File

@@ -507,5 +507,5 @@ SMART_RETRYABLE_ERRORS = [
]
SMART_AUTHENTICATION_ERRORS = [
SmartErrorCode.INVALID_ARGUMENTS,
SmartErrorCode.HOMEKIT_LOGIN_FAIL,
]

View File

@@ -163,6 +163,7 @@ class SmartProtocol(BaseProtocol):
]
end = len(multi_requests)
# Break the requests down as there can be a size limit
step = self._multi_request_batch_size
if step == 1:
@@ -175,6 +176,10 @@ class SmartProtocol(BaseProtocol):
multi_result[method] = resp["result"]
return multi_result
# The SmartCameraProtocol sends requests with a length 1 as a
# multipleRequest. The SmartProtocol doesn't so will never
# raise_on_error
raise_on_error = end == 1
for batch_num, i in enumerate(range(0, end, step)):
requests_step = multi_requests[i : i + step]
@@ -222,7 +227,9 @@ class SmartProtocol(BaseProtocol):
responses = response_step["result"]["responses"]
for response in responses:
method = response["method"]
self._handle_response_error_code(response, method, raise_on_error=False)
self._handle_response_error_code(
response, method, raise_on_error=raise_on_error
)
result = response.get("result", None)
await self._handle_response_lists(
result, method, retry_count=retry_count

View File

@@ -0,0 +1,606 @@
{
"discovery_result": {
"decrypted_data": {
"connect_ssid": "0000000000",
"connect_type": "wireless",
"device_id": "0000000000000000000000000000000000000000",
"http_port": 443,
"last_alarm_time": "0",
"last_alarm_type": "",
"owner": "00000000000000000000000000000000",
"sd_status": "offline"
},
"device_id": "00000000000000000000000000000000",
"device_model": "C210",
"device_name": "00000 000",
"device_type": "SMART.IPCAMERA",
"encrypt_info": {
"data": "",
"key": "",
"sym_schm": "AES"
},
"encrypt_type": [
"3"
],
"factory_default": false,
"firmware_version": "1.4.2 Build 240829 Rel.54953n",
"hardware_version": "2.0",
"ip": "127.0.0.123",
"is_support_iot_cloud": true,
"mac": "40-AE-30-00-00-00",
"mgt_encrypt_schm": {
"is_support_https": true
}
},
"getAlertConfig": {
"msg_alarm": {
"capability": {
"alarm_duration_support": "1",
"alarm_volume_support": "1",
"alert_event_type_support": "1",
"usr_def_audio_alarm_max_num": "15",
"usr_def_audio_alarm_support": "1",
"usr_def_audio_max_duration": "15",
"usr_def_audio_type": "0",
"usr_def_start_file_id": "8195"
},
"chn1_msg_alarm_info": {
"alarm_duration": "0",
"alarm_mode": [
"sound",
"light"
],
"alarm_type": "0",
"alarm_volume": "high",
"enabled": "off",
"light_alarm_enabled": "on",
"light_type": "1",
"sound_alarm_enabled": "on"
},
"usr_def_audio": []
}
},
"getAlertTypeList": {
"msg_alarm": {
"alert_type": {
"alert_type_list": [
"Siren",
"Tone"
]
}
}
},
"getAudioConfig": {
"audio_config": {
"microphone": {
"bitrate": "64",
"channels": "1",
"echo_cancelling": "off",
"encode_type": "G711alaw",
"input_device_type": "MicIn",
"mute": "off",
"noise_cancelling": "on",
"sampling_rate": "8",
"volume": "100"
},
"speaker": {
"mute": "off",
"output_device_type": "SpeakerOut",
"volume": "100"
}
}
},
"getBCDConfig": {
"sound_detection": {
"bcd": {
"digital_sensitivity": "50",
"enabled": "off",
"sensitivity": "medium"
}
}
},
"getCircularRecordingConfig": {
"harddisk_manage": {
"harddisk": {
"loop": "on"
}
}
},
"getConnectionType": {
"link_type": "wifi",
"rssi": "2",
"rssiValue": -64,
"ssid": "I01BU0tFRF9TU0lEIw=="
},
"getDetectionConfig": {
"motion_detection": {
"motion_det": {
"digital_sensitivity": "50",
"enabled": "on",
"non_vehicle_enabled": "off",
"people_enabled": "off",
"sensitivity": "medium",
"vehicle_enabled": "off"
}
}
},
"getDeviceInfo": {
"device_info": {
"basic_info": {
"avatar": "Home",
"barcode": "",
"dev_id": "0000000000000000000000000000000000000000",
"device_alias": "#MASKED_NAME#",
"device_info": "C210 2.0 IPC",
"device_model": "C210",
"device_name": "0000 0.0",
"device_type": "SMART.IPCAMERA",
"features": 3,
"ffs": false,
"has_set_location_info": 1,
"hw_desc": "00000000000000000000000000000000",
"hw_id": "00000000000000000000000000000000",
"hw_version": "2.0",
"is_cal": true,
"latitude": 0,
"longitude": 0,
"mac": "40-AE-30-00-00-00",
"manufacturer_name": "TP-LINK",
"mobile_access": "0",
"oem_id": "00000000000000000000000000000000",
"region": "EU",
"sw_version": "1.4.2 Build 240829 Rel.54953n"
}
}
},
"getFirmwareAutoUpgradeConfig": {
"auto_upgrade": {
"common": {
"enabled": "on",
"random_range": "120",
"time": "03:00"
}
}
},
"getFirmwareUpdateStatus": {
"cloud_config": {
"upgrade_status": {
"lastUpgradingSuccess": true,
"state": "normal"
}
}
},
"getLastAlarmInfo": {
"msg_alarm": {
"chn1_msg_alarm_info": {
"alarm_duration": "0",
"alarm_mode": [
"sound",
"light"
],
"alarm_type": "0",
"alarm_volume": "high",
"enabled": "off",
"light_alarm_enabled": "on",
"light_type": "1",
"sound_alarm_enabled": "on"
}
}
},
"getLdc": {
"image": {
"common": {
"area_compensation": "default",
"auto_exp_antiflicker": "off",
"auto_exp_gain_max": "0",
"backlight": "off",
"chroma": "50",
"contrast": "50",
"dehaze": "off",
"eis": "off",
"exp_gain": "0",
"exp_level": "0",
"exp_type": "auto",
"focus_limited": "10",
"focus_type": "manual",
"high_light_compensation": "off",
"inf_delay": "5",
"inf_end_time": "21600",
"inf_sensitivity": "1",
"inf_sensitivity_day2night": "1400",
"inf_sensitivity_night2day": "9100",
"inf_start_time": "64800",
"inf_type": "auto",
"iris_level": "160",
"light_freq_mode": "auto",
"lock_blue_colton": "0",
"lock_blue_gain": "0",
"lock_gb_gain": "0",
"lock_gr_gain": "0",
"lock_green_colton": "0",
"lock_red_colton": "0",
"lock_red_gain": "0",
"lock_source": "local",
"luma": "50",
"saturation": "50",
"sharpness": "50",
"shutter": "1/25",
"smartir": "off",
"smartir_level": "100",
"smartwtl": "auto_wtl",
"smartwtl_digital_level": "100",
"smartwtl_level": "5",
"style": "standard",
"wb_B_gain": "50",
"wb_G_gain": "50",
"wb_R_gain": "50",
"wb_type": "auto",
"wd_gain": "50",
"wide_dynamic": "off",
"wtl_delay": "5",
"wtl_end_time": "21600",
"wtl_sensitivity": "4",
"wtl_sensitivity_day2night": "1400",
"wtl_sensitivity_night2day": "9100",
"wtl_start_time": "64800",
"wtl_type": "auto"
},
"switch": {
"best_view_distance": "0",
"clear_licence_plate_mode": "off",
"flip_type": "off",
"full_color_min_keep_time": "5",
"full_color_people_enhance": "off",
"image_scene_mode": "normal",
"image_scene_mode_autoday": "normal",
"image_scene_mode_autonight": "normal",
"image_scene_mode_common": "normal",
"image_scene_mode_shedday": "normal",
"image_scene_mode_shednight": "normal",
"ldc": "off",
"night_vision_mode": "inf_night_vision",
"overexposure_people_suppression": "off",
"rotate_type": "off",
"schedule_end_time": "64800",
"schedule_start_time": "21600",
"switch_mode": "common",
"wtl_force_time": "300",
"wtl_intensity_level": "5",
"wtl_manual_start_flag": "off"
}
}
},
"getLedStatus": {
"led": {
"config": {
"enabled": "on"
}
}
},
"getLensMaskConfig": {
"lens_mask": {
"lens_mask_info": {
"enabled": "off"
}
}
},
"getLightFrequencyInfo": {
"image": {
"common": {
"area_compensation": "default",
"auto_exp_antiflicker": "off",
"auto_exp_gain_max": "0",
"backlight": "off",
"chroma": "50",
"contrast": "50",
"dehaze": "off",
"eis": "off",
"exp_gain": "0",
"exp_level": "0",
"exp_type": "auto",
"focus_limited": "10",
"focus_type": "manual",
"high_light_compensation": "off",
"inf_delay": "5",
"inf_end_time": "21600",
"inf_sensitivity": "1",
"inf_sensitivity_day2night": "1400",
"inf_sensitivity_night2day": "9100",
"inf_start_time": "64800",
"inf_type": "auto",
"iris_level": "160",
"light_freq_mode": "auto",
"lock_blue_colton": "0",
"lock_blue_gain": "0",
"lock_gb_gain": "0",
"lock_gr_gain": "0",
"lock_green_colton": "0",
"lock_red_colton": "0",
"lock_red_gain": "0",
"lock_source": "local",
"luma": "50",
"saturation": "50",
"sharpness": "50",
"shutter": "1/25",
"smartir": "off",
"smartir_level": "100",
"smartwtl": "auto_wtl",
"smartwtl_digital_level": "100",
"smartwtl_level": "5",
"style": "standard",
"wb_B_gain": "50",
"wb_G_gain": "50",
"wb_R_gain": "50",
"wb_type": "auto",
"wd_gain": "50",
"wide_dynamic": "off",
"wtl_delay": "5",
"wtl_end_time": "21600",
"wtl_sensitivity": "4",
"wtl_sensitivity_day2night": "1400",
"wtl_sensitivity_night2day": "9100",
"wtl_start_time": "64800",
"wtl_type": "auto"
}
}
},
"getMediaEncrypt": {
"cet": {
"media_encrypt": {
"enabled": "on"
}
}
},
"getMsgPushConfig": {
"msg_push": {
"chn1_msg_push_info": {
"notification_enabled": "on",
"rich_notification_enabled": "off"
}
}
},
"getNightVisionCapability": {
"image_capability": {
"supplement_lamp": {
"night_vision_mode_range": [
"inf_night_vision"
],
"supplement_lamp_type": [
"infrared_lamp"
]
}
}
},
"getNightVisionModeConfig": {
"image": {
"switch": {
"best_view_distance": "0",
"clear_licence_plate_mode": "off",
"flip_type": "off",
"full_color_min_keep_time": "5",
"full_color_people_enhance": "off",
"image_scene_mode": "normal",
"image_scene_mode_autoday": "normal",
"image_scene_mode_autonight": "normal",
"image_scene_mode_common": "normal",
"image_scene_mode_shedday": "normal",
"image_scene_mode_shednight": "normal",
"ldc": "off",
"night_vision_mode": "inf_night_vision",
"overexposure_people_suppression": "off",
"rotate_type": "off",
"schedule_end_time": "64800",
"schedule_start_time": "21600",
"switch_mode": "common",
"wtl_force_time": "300",
"wtl_intensity_level": "5",
"wtl_manual_start_flag": "off"
}
}
},
"getPersonDetectionConfig": {
"people_detection": {
"detection": {
"enabled": "on",
"sensitivity": "50"
}
}
},
"getPresetConfig": {
"preset": {
"preset": {
"id": [],
"name": [],
"position_pan": [],
"position_tilt": [],
"position_zoom": [],
"read_only": []
}
}
},
"getRecordPlan": {
"record_plan": {
"chn1_channel": {
"enabled": "on",
"friday": "[\"0000-2400:2\"]",
"monday": "[\"0000-2400:2\"]",
"saturday": "[\"0000-2400:2\"]",
"sunday": "[\"0000-2400:2\"]",
"thursday": "[\"0000-2400:2\"]",
"tuesday": "[\"0000-2400:2\"]",
"wednesday": "[\"0000-2400:2\"]"
}
}
},
"getRotationStatus": {
"image": {
"switch": {
"best_view_distance": "0",
"clear_licence_plate_mode": "off",
"flip_type": "off",
"full_color_min_keep_time": "5",
"full_color_people_enhance": "off",
"image_scene_mode": "normal",
"image_scene_mode_autoday": "normal",
"image_scene_mode_autonight": "normal",
"image_scene_mode_common": "normal",
"image_scene_mode_shedday": "normal",
"image_scene_mode_shednight": "normal",
"ldc": "off",
"night_vision_mode": "inf_night_vision",
"overexposure_people_suppression": "off",
"rotate_type": "off",
"schedule_end_time": "64800",
"schedule_start_time": "21600",
"switch_mode": "common",
"wtl_force_time": "300",
"wtl_intensity_level": "5",
"wtl_manual_start_flag": "off"
}
}
},
"getSdCardStatus": {
"harddisk_manage": {
"hd_info": [
{
"hd_info_1": {
"crossline_free_space": "0B",
"crossline_free_space_accurate": "0B",
"crossline_total_space": "0B",
"crossline_total_space_accurate": "0B",
"detect_status": "offline",
"disk_name": "1",
"free_space": "0B",
"free_space_accurate": "0B",
"loop_record_status": "0",
"msg_push_free_space": "0B",
"msg_push_free_space_accurate": "0B",
"msg_push_total_space": "0B",
"msg_push_total_space_accurate": "0B",
"percent": "0",
"picture_free_space": "0B",
"picture_free_space_accurate": "0B",
"picture_total_space": "0B",
"picture_total_space_accurate": "0B",
"record_duration": "0",
"record_free_duration": "0",
"record_start_time": "0",
"rw_attr": "r",
"status": "offline",
"total_space": "0B",
"total_space_accurate": "0B",
"type": "local",
"video_free_space": "0B",
"video_free_space_accurate": "0B",
"video_total_space": "0B",
"video_total_space_accurate": "0B",
"write_protect": "0"
}
}
]
}
},
"getTamperDetectionConfig": {
"tamper_detection": {
"tamper_det": {
"digital_sensitivity": "50",
"enabled": "off",
"sensitivity": "medium"
}
}
},
"getTargetTrackConfig": {
"target_track": {
"target_track_info": {
"back_time": "30",
"enabled": "off",
"track_mode": "pantilt",
"track_time": "0"
}
}
},
"getVideoCapability": {
"video_capability": {
"main": {
"bitrate_types": [
"cbr",
"vbr"
],
"bitrates": [
"256",
"512",
"1024",
"1382",
"2048"
],
"change_fps_support": "1",
"encode_types": [
"H264",
"H265"
],
"frame_rates": [
"65551",
"65556",
"65561"
],
"minor_stream_support": "0",
"qualitys": [
"1",
"3",
"5"
],
"resolutions": [
"2304*1296",
"1920*1080",
"1280*720"
]
}
}
},
"getVideoQualities": {
"video": {
"main": {
"bitrate": "1382",
"bitrate_type": "vbr",
"default_bitrate": "1382",
"encode_type": "H264",
"frame_rate": "65551",
"name": "VideoEncoder_1",
"quality": "3",
"resolution": "1920*1080",
"smart_codec": "off"
}
}
},
"getWhitelampConfig": {
"image": {
"switch": {
"best_view_distance": "0",
"clear_licence_plate_mode": "off",
"flip_type": "off",
"full_color_min_keep_time": "5",
"full_color_people_enhance": "off",
"image_scene_mode": "normal",
"image_scene_mode_autoday": "normal",
"image_scene_mode_autonight": "normal",
"image_scene_mode_common": "normal",
"image_scene_mode_shedday": "normal",
"image_scene_mode_shednight": "normal",
"ldc": "off",
"night_vision_mode": "inf_night_vision",
"overexposure_people_suppression": "off",
"rotate_type": "off",
"schedule_end_time": "64800",
"schedule_start_time": "21600",
"switch_mode": "common",
"wtl_force_time": "300",
"wtl_intensity_level": "5",
"wtl_manual_start_flag": "off"
}
}
},
"getWhitelampStatus": {
"rest_time": 0,
"status": 0
}
}