UNPKG

iobroker.roborock

Version:
2,071 lines (1,949 loc) 128 kB
import { V1VacuumFeatures, VacuumProfile, BASE_FAN, BASE_WATER, BASE_MOP } from "./v1VacuumFeatures"; import { RegisterModel, DeviceModelConfig, FeatureDependencies } from "../baseDeviceFeatures"; import { Feature } from "../features.enum"; // --- DEVICE PROFILE (a179) --- const PROFILE_A179: VacuumProfile = { name: "Roborock Saros Z70 (a179)", features: { hasSmartPlan: true, hasDistanceOff: true, maxSuctionValue: 110, ultraWaterValue: 209 }, mappings: { fan_power: { ...BASE_FAN, 110: "Max+" }, water_box_mode: { ...BASE_WATER, 209: "Ultra" }, mop_mode: { ...BASE_MOP, 306: "Intense/Smart" } }, cleanMotorModePresets: { '{"fan_power":110,"mop_mode":306,"water_box_mode":209}': "SmartPlan", '{"fan_power":102,"mop_mode":300,"water_box_mode":200}': "Vacuum", '{"fan_power":105,"mop_mode":300,"water_box_mode":202}': "Mop", '{"fan_power":102,"mop_mode":300,"water_box_mode":202}': "Vac & Mop" } }; const a179Config: DeviceModelConfig = { staticFeatures: [ Feature.InWarmup, Feature.CleanPercent, Feature.ExtraTime, Feature.RobotStatus, Feature.CommonStatus, Feature.SwitchStatus, Feature.ExitDock, Feature.ChargeStatus, Feature.MapFlag, Feature.CleaningInfo, Feature.TaskId, Feature.DockStatus, Feature.LastCleanTime, Feature.AutoEmptyDock, Feature.MopWash, Feature.MopDry, Feature.LiveVideo, Feature.Camera, Feature.MopForbidden, Feature.AvoidCarpet, Feature.WaterBox, Feature.SmartPlan, Feature.FanMaxPlus, Feature.SmartModeCommand, Feature.CleanRepeat, Feature.CleanedArea, Feature.GetPhoto ] }; const Z70_ARM_DIRECTION_STATES: Record<number, string> = { 1: "Up", 2: "Down", 3: "Go", 4: "Back" }; const Z70_ARM_MOVE_PRESET_STATES: Record<string, string> = { "[2,0,0]": "M3 Left", "[1,0,0]": "M3 Right", "[0,1,0]": "M4 Left", "[0,2,0]": "M4 Right", "[0,0,2]": "M5 Left", "[0,0,1]": "M5 Right" }; const Z70_GRAB_MODE_STATES: Record<number, string> = { 0: "Exit / Off", 1: "Manual Mode", 2: "Auto Mode" }; const Z70_PICK_UP_STATES: Record<number, string> = { 0: "Auto Grab", 1: "Manual Grab" }; const Z70_PUT_DOWN_STATES: Record<number, string> = { 0: "Put Down" }; const Z70_CAMERA_STATES: Record<number, string> = { 0: "Disable Mechanical Camera", 1: "Enable Mechanical Camera" }; const Z70_VIDEO_QUALITY_STATES: Record<string, string> = { SD: "SD", HD: "HD", FHD: "FHD", AUTO: "AUTO" }; const Z70_ROLLER_MOP_STATES: Record<number, string> = { 0: "In", 1: "Out" }; const Z70_ROLLER_MOP_COVER_STATES: Record<number, string> = { 0: "Stretch Out", 1: "Retract" }; const Z70_LDS_LIFTING_STATES: Record<number, string> = { 0: "Lower", 1: "Lift Up" }; const Z70_EXHIBITION_MODE_STATES: Record<number, string> = { 0: "Exit", 1: "Enter" }; const Z70_SMART_WASH_STATES: Record<number, string> = { 0: "Custom / Timed", 1: "Smart", 2: "New Smart" }; const Z70_BACK_WASH_MODE_STATES: Record<number, string> = { 0: "Smart", 1: "Custom", 2: "New Smart" }; const Z70_WASH_TOWEL_MODE_STATES: Record<number, string> = { 0: "Quick / Water Saving", 1: "Daily", 2: "Deep", 8: "Super Deep / Soak", 10: "Smart" }; const Z70_WASH_TEMPERATURE_STATES: Record<number, string> = { 0: "Normal", 1: "Warm", 2: "Hot / High Temperature" }; const Z70_BACK_TYPE_LABELS: Record<number, string> = { 1: "Washing Mop", 2: "Setting Up Mop", 3: "Removing Mop", 4: "Collecting Dust" }; const Z70_WASH_PHASE_LABELS: Record<number, string> = { 11: "Running", 17: "Pumping" }; const Z70_WASHING_MODE_LABELS: Record<number, string> = { 6: "Dock Self-Cleaning", 7: "Water Draining", 11: "Pumping Water" }; const Z70_BINARY_STATUS_STATES: Record<number, string> = { 0: "Off", 1: "On" }; const Z70_PROGRAM_RUNTIME_RESULT_STATES: Record<number, string> = { "-2": "Execution Failure 2", "-1": "Execution Failure", 0: "Successful Execution", 1: "Waiting For Execution", 2: "Executing" }; const Z70_PROGRAM_STATE_STATES: Record<number, string> = { 0: "Without Tasks", 1: "Starting", 2: "Executing", 3: "Error" }; const Z70_PROGRAM_TYPE_STATES: Record<number, string> = { 1: "My Program", 2: "Official Recommendation" }; const Z70_PROGRAM_ARM_DIRECTION_LABELS: Record<number, string> = { 1: "Arm Position Up", 2: "Arm Position Down", 3: "Arm Position Head", 4: "Arm Position Back" }; const Z70_PROGRAM_COMMAND_LABELS: Record<string, string> = { arm_out: "Arm Out", arm_grasp: "Auto Grab", arm_putdown: "Auto Put Down", arm_in: "Arm In", delay: "Delay", sound: "Play Voice", move_forward: "Go Forward", move_backward: "Go Back", turn_right: "Turn Right", turn_left: "Turn Left", arm_joints: "Arm Joints", arm_move: "Arm Move" }; const Z70_PROGRAM_ARM_MOVE_AXES = ["M3", "M4", "M5", "M6"] as const; const Z70_EASTER_EGG_TYPE_STATES: Record<number, string> = { 0: "Dance" }; const Z70_FEATURE_BACK_WASH_NEW_SMART = 109; const Z70_FEATURE_HOT_WASH_TOWEL = 41; const Z70_FEATURE_SOAK_AND_WASH = 107; const Z70_MECHANICAL_ARM_EMERGENCY_ERROR_CODES = new Set([64, 65, 67, 69, 70, 71]); type ExperimentalPayloadOptions = { unwrapSingleItemArray?: boolean; flattenObject?: boolean; writeArrayCount?: boolean; writePrimitiveValue?: boolean; pruneLegacyTopLevelStates?: boolean; }; @RegisterModel("roborock.vacuum.a179") export class A179Features extends V1VacuumFeatures { private z70FirmwareFeatures?: Set<number>; private z70HomeSecStatus: number | null = null; private z70HomeSecClientId: string | null = null; private z70RobotState: number | null = null; private z70LockStatus: number | null = null; private z70IsLocating = false; private z70VoiceChatActive = false; private z70DryStatus: number | null = null; private z70ExitDock: number | null = null; private z70WashPhase: number | null = null; private z70SwitchStatus: number | null = null; private z70CleanFluidStatus: number | null = null; private readonly z70QueryOnlyCommandIds = new Set([ "get_camera_status", "app_get_arm_joints_data", "app_get_segment_clean_subdivision", "app_get_zoned_clean_subdivision", "app_tidy_up_record_summary", "app_get_tidy_up_zones", "app_tidy_up_record_detail", "app_get_tidy_up_map", "get_wash_debug_params", "get_clean_roller_debug_info", "get_smart_wash_params", "get_wash_towel_params", "get_wash_towel_mode", "get_wash_water_temperature", "app_get_program", "app_get_robot_setting", "app_get_program_runtime", "app_get_program_soundlist", "app_get_programs_summary", "app_get_clean_estimate_info", "app_get_carpet_deep_clean_status", "app_get_dryer_setting", "app_get_wifi_list", "get_dock_info", "get_child_lock_status", "get_collision_avoid_status", "get_flow_led_status", "get_map_beautification_status", "test_get_enable_wakeup", "test_get_voice_keep_seconds", "get_voice_history_summary", "get_voice_history", "test_get_voice_list", "get_auto_delivery_cleaning_fluid", "get_ap_mic_led_status", "get_voice_service_switch", "get_handle_leak_water_status", "check_homesec_password", "get_homesec_connect_status" ]); private readonly z70SettingsOnlyCommandIds = new Set([ "set_camera_status", "switch_video_quality", "app_set_door_sill_blocks", "app_set_beautify_blocks", "app_set_smart_door_sill", "app_set_tidy_up_zones", "set_wash_debug_params", "set_roller_speed", "set_drying_time", "set_mopping_speed", "set_wash_interval", "set_smart_wash_params", "set_back_wash_mode", "set_back_wash_interval", "set_wash_towel_params", "set_wash_towel_interval", "set_wash_towel_mode", "set_wash_towel_status", "set_wash_water_temperature", "app_set_robot_setting", "app_set_carpet_deep_clean_status", "app_set_cross_carpet_cleaning_status", "app_set_priority_carpet_cleaning_status", "app_set_dryer_setting", "app_set_dryer_status", "set_child_lock_status", "set_collision_avoid_status", "set_flow_led_status", "set_map_beautification_status", "set_ignore_carpet_zone", "set_ignore_identify_area", "test_set_enable_wakeup", "test_set_voice_keep_seconds", "app_update_unsave_map", "set_auto_delivery_cleaning_fluid", "set_ap_mic_led_status", "set_voice_service_switch", "set_handle_leak_water_status", "set_homesec_password", "reset_homesec_password", "enable_homesec_voice" ]); private readonly z70NoParamCommandIds = new Set([ "app_empty_inbuilt_water_tank", "app_amethyst_drain_all_water", "app_amethyst_self_check", "app_keep_easter_egg", "app_arm_out_compartment", "app_arm_in_compartment", "app_open_gripper", "app_grip", "app_tidy_up_record_summary", "app_get_tidy_up_zones", "app_arm_recover", "app_get_arm_joints_data", "app_get_program_runtime", "app_get_program_soundlist", "app_get_programs_summary", "get_auto_delivery_cleaning_fluid", "get_ap_mic_led_status", "get_handle_leak_water_status", "app_get_clean_estimate_info", "app_get_carpet_deep_clean_status", "app_get_wifi_list", "app_resume_patrol", "app_start_easter_egg", "app_start_pet_patrol", "app_empty_rinse_tank_water", "app_save_beautification_pic", "stop_voice_chat", "get_smart_wash_params", "get_wash_towel_mode", "get_wash_water_temperature", "get_dock_info" ]); private readonly z70EmptyArrayCommandIds = new Set([ "app_stop_grasp", "start_wash_then_charge", "reset_homesec_password", "app_wakeup_robot", "app_start_build_map", "app_resume_build_map", "app_start_collect_dust", "app_stop_collect_dust" ]); private readonly z70NoParamArrayCommandIds = new Set([ "get_camera_status", "get_wash_debug_params", "get_clean_roller_debug_info", "app_get_dryer_setting", "get_wash_towel_params", "get_voice_service_switch", "get_homesec_connect_status", "get_child_lock_status", "get_collision_avoid_status", "get_flow_led_status", "get_map_beautification_status", "get_voice_history_summary", "test_get_enable_wakeup", "test_get_voice_keep_seconds", "test_get_voice_list" ]); private readonly z70CmdCommandIds = new Set([ "app_rc_roller_mop_cover", "app_rc_roller_mop" ]); private readonly z70FlagCommandIds = new Set([ "app_pick_up_enter_exit", "app_pick_up", "app_put_down", "app_change_camera", "app_exhibition_enter_exit", "app_program_enter_exit" ]); private readonly z70StartTimeCommandIds = new Set([ "app_tidy_up_record_detail", "app_delete_tidy_up_record", "app_get_tidy_up_map" ]); constructor(dependencies: FeatureDependencies, duid: string) { super(dependencies, duid, "roborock.vacuum.a179", a179Config, PROFILE_A179); } public override async initializeDeviceData(): Promise<void> { await super.initializeDeviceData(); await this.updateExtraStatus(); } public override async updateMap(): Promise<void> { await super.updateMap(); await this.refreshZ70Zones(); } public override async setupProtocolFeatures(): Promise<void> { await super.setupProtocolFeatures(); // Source-verified Z70 robotic arm / tidy-up endpoints from the Roborock app bundle. this.addCommand("app_empty_inbuilt_water_tank", { type: "boolean", role: "button", name: "Drain Built-In Water Tank", def: false }); this.addCommand("app_amethyst_drain_all_water", { type: "boolean", role: "button", name: "Drain All Water", def: false }); this.addCommand("app_amethyst_self_check", { type: "boolean", role: "button", name: "Run Self Check", def: false }); this.addCommand("app_keep_easter_egg", { type: "boolean", role: "button", name: "Keep Easter Egg Mode", def: false }); this.addCommand("app_arm_out_compartment", { type: "boolean", role: "button", name: "Arm Out", def: false }); this.addCommand("app_arm_in_compartment", { type: "boolean", role: "button", name: "Arm In", def: false }); this.addCommand("app_open_gripper", { type: "boolean", role: "button", name: "Open Gripper", def: false }); this.addCommand("app_grip", { type: "boolean", role: "button", name: "Close Gripper", def: false }); this.addCommand("app_arm_direction_move", { type: "number", role: "value", name: "Arm Direction Move", states: Z70_ARM_DIRECTION_STATES, def: 1 }); this.addCommand("app_arm_move", { type: "json", role: "json", name: "Arm Move" }); this.addCommand("app_arm_move_preset", { type: "string", role: "value", name: "Arm Move Preset", states: Z70_ARM_MOVE_PRESET_STATES, def: "[2,0,0]" }); this.addCommand("app_arm_recover", { type: "boolean", role: "button", name: "Recover Arm", def: false }); this.addCommand("app_arm_recover_payload", { type: "json", role: "json", name: "Recover Arm Payload" }); this.addCommand("app_get_arm_joints_data", { type: "boolean", role: "button", name: "Get Arm Joints Data", def: false }); this.addCommand("app_stop_grasp", { type: "boolean", role: "button", name: "Stop Grasp", def: false }); this.addCommand("app_rc_roller_mop_cover", { type: "number", role: "value", name: "Roller Mop Cover Command", states: Z70_ROLLER_MOP_COVER_STATES, def: 0 }); this.addCommand("app_rc_roller_mop", { type: "number", role: "value", name: "Roller Mop Command", states: Z70_ROLLER_MOP_STATES, def: 0 }); this.addCommand("app_rc_lds_lifting", { type: "number", role: "value", name: "LDS Lifting", states: Z70_LDS_LIFTING_STATES, def: 0 }); this.addCommand("app_wakeup_robot", { type: "boolean", role: "button", name: "Wake Up Robot", def: false }); this.addCommand("app_set_door_sill_blocks", { type: "json", role: "json", name: "Set Door Sill Blocks" }); this.addCommand("app_set_beautify_blocks", { type: "json", role: "json", name: "Set Beautify Blocks" }); this.addCommand("app_set_smart_door_sill", { type: "json", role: "json", name: "Set Smart Door Sill" }); this.addCommand("app_get_segment_clean_subdivision", { type: "json", role: "json", name: "Get Segment Clean Subdivision" }); this.addCommand("app_segment_clean_subdivision", { type: "json", role: "json", name: "Segment Clean Subdivision" }); this.addCommand("app_get_zoned_clean_subdivision", { type: "json", role: "json", name: "Get Zoned Clean Subdivision" }); this.addCommand("app_zoned_clean_subdivision", { type: "json", role: "json", name: "Zoned Clean Subdivision" }); this.addCommand("app_set_dirty_replenish_clean_status", { type: "json", role: "json", name: "Set Dirty Replenish Clean Status" }); this.addCommand("app_set_dynamic_config", { type: "json", role: "json", name: "Set Dynamic Config" }); this.addCommand("app_set_ignore_stuck_point", { type: "json", role: "json", name: "Set Ignore Stuck Point" }); this.addCommand("app_set_low_space_zones", { type: "json", role: "json", name: "Set Low Space Zones" }); this.addCommand("app_set_smart_cliff_forbidden", { type: "json", role: "json", name: "Set Smart Cliff Forbidden" }); this.addCommand("app_ignore_dirty_objects", { type: "json", role: "json", name: "Ignore Dirty Objects" }); this.addCommand("app_save_beautification_pic", { type: "boolean", role: "button", name: "Save Beautification Picture", def: false }); this.addCommand("app_start_build_map", { type: "boolean", role: "button", name: "Start Quick Build Map", def: false }); this.addCommand("app_resume_build_map", { type: "boolean", role: "button", name: "Resume Quick Build Map", def: false }); this.addCommand("app_start_collect_dust", { type: "boolean", role: "button", name: "Start Collect Dust", def: false }); this.addCommand("app_stop_collect_dust", { type: "boolean", role: "button", name: "Stop Collect Dust", def: false }); this.addCommand("app_switch_dock_cool_fan", { type: "boolean", role: "switch.enable", name: "Dock Cool Fan", def: false }); this.addCommand("app_delete_wifi", { type: "number", role: "value", name: "Delete Saved Wi-Fi", def: 0 }); this.addCommand("app_pick_up_enter_exit", { type: "number", role: "value", name: "Arm Grab Mode", states: Z70_GRAB_MODE_STATES, def: 0 }); this.addCommand("app_pick_up", { type: "number", role: "value", name: "Arm Pick-Up Action", states: Z70_PICK_UP_STATES, def: 0 }); this.addCommand("app_put_down", { type: "number", role: "value", name: "Arm Put-Down Action", states: Z70_PUT_DOWN_STATES, def: 0 }); this.addCommand("app_change_camera", { type: "number", role: "value", name: "Mechanical Camera", states: Z70_CAMERA_STATES, def: 0 }); this.addCommand("get_camera_status", { type: "boolean", role: "button", name: "Get Camera Status", def: false }); this.addCommand("set_camera_status", { type: "number", role: "value", name: "Set Camera Status Bitfield", def: 0 }); this.addCommand("start_camera_preview", { type: "json", role: "json", name: "Start Camera Preview" }); this.addCommand("stop_camera_preview", { type: "json", role: "json", name: "Stop Camera Preview" }); this.addCommand("switch_video_quality", { type: "string", role: "value", name: "Switch Video Quality", states: Z70_VIDEO_QUALITY_STATES, def: "SD" }); this.addCommand("app_exhibition_enter_exit", { type: "number", role: "value", name: "Exhibition Mode", states: Z70_EXHIBITION_MODE_STATES, def: 0 }); this.addCommand("app_exhibition_action", { type: "json", role: "json", name: "Exhibition Action" }); this.addCommand("app_set_tidy_up_zones", { type: "json", role: "json", name: "Set Tidy-Up Zones" }); this.addCommand("app_start_tidy_up", { type: "json", role: "json", name: "Start Tidy-Up" }); this.addCommand("app_tidy_up_record_summary", { type: "boolean", role: "button", name: "Refresh Tidy-Up Summary", def: false }); this.addCommand("app_get_tidy_up_zones", { type: "boolean", role: "button", name: "Refresh Tidy-Up Zones", def: false }); this.addCommand("app_tidy_up_record_detail", { type: "number", role: "value", name: "Get Tidy-Up Record", def: 0 }); this.addCommand("app_delete_tidy_up_record", { type: "number", role: "value", name: "Delete Tidy-Up Record", def: 0 }); this.addCommand("app_get_tidy_up_map", { type: "number", role: "value", name: "Get Tidy-Up Record Map", def: 0 }); this.addCommand("get_wash_debug_params", { type: "boolean", role: "button", name: "Get Wash Debug Params", def: false }); this.addCommand("get_clean_roller_debug_info", { type: "boolean", role: "button", name: "Get Clean Roller Debug Info", def: false }); this.addCommand("set_wash_debug_params", { type: "json", role: "json", name: "Set Wash Debug Params" }); this.addCommand("set_roller_speed", { type: "number", role: "value", name: "Set Roller Speed", def: 0 }); this.addCommand("set_drying_time", { type: "number", role: "value", name: "Set Drying Time", def: 0 }); this.addCommand("set_mopping_speed", { type: "number", role: "value", name: "Set Mopping Speed", def: 0 }); this.addCommand("set_wash_interval", { type: "number", role: "value", name: "Set Wash Interval", def: 0 }); this.addCommand("get_smart_wash_params", { type: "boolean", role: "button", name: "Get Smart Wash Params", def: false }); this.addCommand("set_smart_wash_params", { type: "json", role: "json", name: "Set Smart Wash Params" }); this.addCommand("set_back_wash_mode", { type: "number", role: "value", name: "Set Back Wash Mode", states: Z70_BACK_WASH_MODE_STATES, def: 0 }); this.addCommand("set_back_wash_interval", { type: "number", role: "value", name: "Set Back Wash Interval", min: 10, max: 50, unit: "min", def: 20 }); this.addCommand("get_wash_towel_params", { type: "boolean", role: "button", name: "Get Wash Towel Params", def: false }); this.addCommand("get_wash_towel_mode", { type: "boolean", role: "button", name: "Get Wash Towel Mode", def: false }); this.addCommand("get_wash_water_temperature", { type: "boolean", role: "button", name: "Get Wash Water Temperature", def: false }); this.addCommand("set_wash_towel_params", { type: "json", role: "json", name: "Set Wash Towel Params" }); this.addCommand("set_wash_towel_interval", { type: "number", role: "value", name: "Set Wash Towel Interval", def: 0 }); this.addCommand("set_wash_towel_mode", { type: "number", role: "value", name: "Set Wash Towel Mode", states: Z70_WASH_TOWEL_MODE_STATES, def: 1 }); this.addCommand("set_wash_towel_status", { type: "number", role: "value", name: "Set Wash Towel Status", def: 0 }); this.addCommand("set_wash_water_temperature", { type: "number", role: "value", name: "Set Wash Water Temperature", states: Z70_WASH_TEMPERATURE_STATES, def: 0 }); this.addCommand("start_wash_then_charge", { type: "boolean", role: "button", name: "Start Wash Then Charge", def: false }); this.addCommand("app_get_program", { type: "number", role: "value", name: "Get Program", min: 1, def: 1 }); this.addCommand("app_get_robot_setting", { type: "json", role: "json", name: "Get Robot Setting" }); this.addCommand("app_set_robot_setting", { type: "json", role: "json", name: "Set Robot Setting" }); this.addCommand("app_get_program_runtime", { type: "boolean", role: "button", name: "Get Program Runtime", def: false }); this.addCommand("app_get_program_soundlist", { type: "boolean", role: "button", name: "Get Program Sound List", def: false }); this.addCommand("app_get_programs_summary", { type: "boolean", role: "button", name: "Get Program Summary", def: false }); this.addCommand("app_program_enter_exit", { type: "number", role: "value", name: "Program Enter / Exit", states: Z70_EXHIBITION_MODE_STATES, def: 0 }); this.addCommand("app_copy_program", { type: "json", role: "json", name: "Copy Program" }); this.addCommand("app_delete_program", { type: "number", role: "value", name: "Delete Program", min: 1, def: 1 }); this.addCommand("app_modify_program", { type: "json", role: "json", name: "Modify Program" }); this.addCommand("app_save_program", { type: "json", role: "json", name: "Save Program" }); this.addCommand("app_start_program", { type: "json", role: "json", name: "Start Program" }); this.addCommand("app_start_patrol", { type: "json", role: "json", name: "Start Patrol" }); this.addCommand("app_resume_patrol", { type: "boolean", role: "button", name: "Resume Patrol", def: false }); this.addCommand("app_start_pet_patrol", { type: "boolean", role: "button", name: "Start Pet Search", def: false }); this.addCommand("app_empty_rinse_tank_water", { type: "boolean", role: "button", name: "Empty Rinse Tank Water", def: false }); this.addCommand("app_start_easter_egg", { type: "boolean", role: "button", name: "Start Easter Egg Attack", def: false }); this.addCommand("start_new_easter_egg", { type: "number", role: "value", name: "Start New Easter Egg", states: Z70_EASTER_EGG_TYPE_STATES, def: 0 }); this.addCommand("start_voice_chat", { type: "json", role: "json", name: "Start Voice Chat" }); this.addCommand("stop_voice_chat", { type: "boolean", role: "button", name: "Stop Voice Chat", def: false }); this.addCommand("set_voice_chat_volume", { type: "number", role: "value", name: "Set Voice Chat Volume" }); this.addCommand("app_get_clean_estimate_info", { type: "boolean", role: "button", name: "Get Clean Estimate Info", def: false }); this.addCommand("app_get_carpet_deep_clean_status", { type: "boolean", role: "button", name: "Get Carpet Deep Clean Status", def: false }); this.addCommand("app_set_carpet_deep_clean_status", { type: "json", role: "json", name: "Set Carpet Deep Clean Status" }); this.addCommand("app_set_cross_carpet_cleaning_status", { type: "boolean", role: "switch.enable", name: "Cross Carpet Cleaning", def: false }); this.addCommand("app_set_priority_carpet_cleaning_status", { type: "boolean", role: "switch.enable", name: "Priority Carpet Cleaning", def: false }); this.addCommand("app_get_dryer_setting", { type: "boolean", role: "button", name: "Get Dryer Setting", def: false }); this.addCommand("app_set_dryer_setting", { type: "json", role: "json", name: "Set Dryer Setting" }); this.addCommand("app_set_dryer_status", { type: "boolean", role: "switch.enable", name: "Dryer Status", def: false }); this.addCommand("app_get_wifi_list", { type: "boolean", role: "button", name: "Get Wi-Fi List", def: false }); this.addCommand("get_dock_info", { type: "boolean", role: "button", name: "Get Dock Info", def: false }); this.addCommand("get_child_lock_status", { type: "boolean", role: "button", name: "Get Child Lock Status", def: false }); this.addCommand("set_child_lock_status", { type: "boolean", role: "switch.enable", name: "Child Lock", def: false }); this.addCommand("get_collision_avoid_status", { type: "boolean", role: "button", name: "Get Collision Avoid Status", def: false }); this.addCommand("set_collision_avoid_status", { type: "boolean", role: "switch.enable", name: "Collision Avoid Status", def: false }); this.addCommand("get_flow_led_status", { type: "boolean", role: "button", name: "Get Flow LED Status", def: false }); this.addCommand("set_flow_led_status", { type: "boolean", role: "switch.enable", name: "Flow LED Status", def: false }); this.addCommand("get_map_beautification_status", { type: "boolean", role: "button", name: "Get Map Beautification Status", def: false }); this.addCommand("set_map_beautification_status", { type: "boolean", role: "switch.enable", name: "Map Beautification Status", def: false }); this.addCommand("set_ignore_carpet_zone", { type: "json", role: "json", name: "Set Ignore Carpet Zone" }); this.addCommand("set_ignore_identify_area", { type: "json", role: "json", name: "Set Ignore Identify Area" }); this.addCommand("test_get_enable_wakeup", { type: "boolean", role: "button", name: "Get Voice Wakeup Status", def: false }); this.addCommand("test_set_enable_wakeup", { type: "boolean", role: "switch.enable", name: "Voice Wakeup", def: false }); this.addCommand("test_get_voice_keep_seconds", { type: "boolean", role: "button", name: "Get Voice Keep Seconds", def: false }); this.addCommand("test_set_voice_keep_seconds", { type: "number", role: "value", name: "Voice Keep Seconds", def: 0 }); this.addCommand("get_voice_history_summary", { type: "boolean", role: "button", name: "Get Voice History Summary", def: false }); this.addCommand("get_voice_history", { type: "number", role: "value", name: "Get Voice History", def: 0 }); this.addCommand("test_get_voice_list", { type: "boolean", role: "button", name: "Get Voice List", def: false }); this.addCommand("app_start_replenish_clean_area", { type: "json", role: "json", name: "Start Replenish Clean Area" }); this.addCommand("app_skip_current_cleaning_area", { type: "json", role: "json", name: "Skip Current Cleaning Area" }); this.addCommand("app_update_unsave_map", { type: "boolean", role: "switch.enable", name: "Update Unsave Map", def: false }); this.addCommand("get_auto_delivery_cleaning_fluid", { type: "boolean", role: "button", name: "Get Auto Delivery Clean Fluid", def: false }); this.addCommand("set_auto_delivery_cleaning_fluid", { type: "boolean", role: "switch.enable", name: "Auto Delivery Clean Fluid", def: false }); this.addCommand("get_ap_mic_led_status", { type: "boolean", role: "button", name: "Get Voice Control LED Status", def: false }); this.addCommand("set_ap_mic_led_status", { type: "boolean", role: "switch.enable", name: "Voice Control LED", def: false }); this.addCommand("get_voice_service_switch", { type: "boolean", role: "button", name: "Get Voice Service Switch", def: false }); this.addCommand("set_voice_service_switch", { type: "boolean", role: "switch.enable", name: "Voice Service Switch", def: false }); this.addCommand("get_handle_leak_water_status", { type: "boolean", role: "button", name: "Get Water Leak Check", def: false }); this.addCommand("set_handle_leak_water_status", { type: "boolean", role: "switch.enable", name: "Water Leak Check", def: false }); this.addCommand("check_homesec_password", { type: "string", role: "text", name: "Check Home Security Password", def: "" }); this.addCommand("set_homesec_password", { type: "json", role: "json", name: "Set Home Security Password" }); this.addCommand("reset_homesec_password", { type: "boolean", role: "button", name: "Reset Home Security Password", def: false }); this.addCommand("enable_homesec_voice", { type: "boolean", role: "switch.enable", name: "Enable Home Security Voice", def: false }); this.addCommand("get_homesec_connect_status", { type: "boolean", role: "button", name: "Get Home Security Connect Status", def: false }); this.reclassifyZ70WritableCommandGroups(); } public override async createCommandObjects(): Promise<void> { await super.createCommandObjects(); await this.cleanupLegacyZ70CommandStates(); } private reclassifyZ70WritableCommandGroups(): void { const registeredCommands = { ...this.commands }; this.extraCommandGroups.queries = {}; this.extraCommandGroups.settings = {}; for (const [command, spec] of Object.entries(registeredCommands)) { if (this.z70QueryOnlyCommandIds.has(command)) { delete this.commands[command]; this.addCommand(command, spec, "queries"); continue; } if (this.z70SettingsOnlyCommandIds.has(command)) { delete this.commands[command]; this.addCommand(command, spec, "settings"); } } } private async cleanupLegacyZ70CommandStates(): Promise<void> { const movedCommands = [ ...Object.keys(this.extraCommandGroups.queries ?? {}), ...Object.keys(this.extraCommandGroups.settings ?? {}) ]; await Promise.all(movedCommands.map(async (command) => { const path = `Devices.${this.duid}.commands.${command}`; const existing = await this.deps.adapter.getObjectAsync(path); if (existing) { await this.deps.adapter.delObjectAsync(path); } })); } public override async getCommandParams(method: string, params?: unknown, id?: string): Promise<unknown> { const baseParams = await super.getCommandParams(method, params, id); if (method === "app_arm_recover" || method === "app_arm_recover_payload") { return { method: "app_arm_recover", params: this.normalizeOptionalObjectParam(baseParams, method) }; } if (this.z70NoParamCommandIds.has(method)) { return { method, params: {} }; } if (this.z70EmptyArrayCommandIds.has(method)) { return { method, params: [] }; } if (this.z70NoParamArrayCommandIds.has(method)) { return { method: method === "get_clean_roller_debug_info" ? "get_wash_debug_params" : method, params: [] }; } if (this.z70FlagCommandIds.has(method)) { return { method, params: { flag: this.normalizeNumericParam(baseParams, method) } }; } if (this.z70StartTimeCommandIds.has(method)) { return { method, params: { start_time: this.normalizeNumericParam(baseParams, method) } }; } if (method === "app_arm_direction_move") { return { method, params: { direction: this.normalizeNumericParam(baseParams, method) } }; } if (this.z70CmdCommandIds.has(method)) { return { method, params: { cmd: this.normalizeNumericParam(baseParams, method) } }; } if (method === "app_rc_lds_lifting") { return { method, params: { lift_up: this.normalizeNumericParam(baseParams, method) } }; } if (method === "app_arm_move") { return { method, params: { m: this.normalizeArmMoveParam(baseParams, method) } }; } if (method === "app_arm_move_preset") { return { method: "app_arm_move", params: { m: this.normalizeArmMoveParam(baseParams, method) } }; } if (method === "app_set_tidy_up_zones") { return { method, params: this.parseJsonParam(baseParams, method) }; } if ( method === "app_set_door_sill_blocks" || method === "app_set_beautify_blocks" || method === "app_set_smart_door_sill" ) { return { method, params: this.parseJsonParam(baseParams, method) }; } if ( method === "app_get_segment_clean_subdivision" || method === "app_segment_clean_subdivision" || method === "app_get_zoned_clean_subdivision" || method === "app_zoned_clean_subdivision" || method === "app_set_dirty_replenish_clean_status" || method === "app_set_dynamic_config" || method === "app_set_ignore_stuck_point" || method === "app_set_low_space_zones" || method === "app_set_smart_cliff_forbidden" || method === "app_ignore_dirty_objects" || method === "set_ignore_carpet_zone" || method === "set_ignore_identify_area" ) { return { method, params: this.normalizeRequiredObjectParam(baseParams, method) }; } if (method === "app_exhibition_action") { return { method, params: this.normalizeExhibitionActionParam(baseParams, method) }; } if (method === "set_camera_status") { return { method, params: [this.normalizeNumericParam(baseParams, method)] }; } if (method === "set_wash_debug_params") { return { method, params: this.normalizeRequiredObjectParam(baseParams, method) }; } if (method === "start_camera_preview") { return { method, params: await this.normalizeCameraPreviewParams(baseParams, method) }; } if (method === "stop_camera_preview") { return { method, params: await this.normalizeCameraPreviewParams(baseParams, method) }; } if (method === "set_smart_wash_params" || method === "set_wash_towel_params") { return { method, params: this.normalizeRequiredObjectParam(baseParams, method) }; } if (method === "app_get_robot_setting") { return { method, params: this.normalizeRobotSettingQueryParam(baseParams, method) }; } if (method === "app_set_robot_setting" || method === "app_set_dryer_setting") { return { method, params: this.normalizeRequiredObjectParam(baseParams, method) }; } if (method === "switch_video_quality") { return { method, params: { quality: this.normalizeVideoQualityParam(baseParams, method) } }; } if (method === "set_roller_speed") { return { method: "set_wash_debug_params", params: { rollerspeed: this.normalizeNumericParam(baseParams, method) } }; } if (method === "set_drying_time") { return { method: "set_wash_debug_params", params: { dryingtime: this.normalizeNumericParam(baseParams, method) } }; } if (method === "set_mopping_speed") { return { method: "set_wash_debug_params", params: { moppingspeed: this.normalizeNumericParam(baseParams, method) } }; } if (method === "set_wash_interval") { return { method: "set_wash_debug_params", params: { washinterval: this.normalizeNumericParam(baseParams, method) } }; } if (method === "set_back_wash_mode") { const mode = this.normalizeBackWashModeParam(baseParams, method); const intervalMinutes = mode === 0 ? 20 : await this.readNumericState("dockingStationStatus.smartWash.washIntervalMinutes", 20); await this.assertBackWashModeSupported(mode); return { method: "set_smart_wash_params", params: this.buildSmartWashParams(mode, intervalMinutes) }; } if (method === "set_back_wash_interval") { const intervalMinutes = this.normalizeBackWashIntervalMinutes(baseParams, method); return { method: "set_smart_wash_params", params: this.buildSmartWashParams(1, intervalMinutes) }; } if (method === "set_wash_towel_interval") { return { method: "set_wash_towel_params", params: { interval: this.normalizeNumericParam(baseParams, method) } }; } if (method === "set_wash_towel_mode") { return { method, params: { wash_mode: this.normalizeNumericParam(baseParams, method) } }; } if (method === "set_wash_towel_status") { return { method: "set_wash_towel_params", params: { status: this.normalizeNumericParam(baseParams, method) } }; } if (method === "set_wash_water_temperature") { return { method, params: { values: this.normalizeNumericParam(baseParams, method) } }; } if (method === "app_get_program" || method === "app_delete_program") { return { method, params: { program_id: this.normalizeNumericParam(baseParams, method) } }; } if (method === "app_copy_program" || method === "app_modify_program") { return { method, params: this.normalizeProgramNameAndIdParam(baseParams, method) }; } if (method === "app_save_program" || method === "start_voice_chat") { return { method, params: this.normalizeRequiredObjectParam(baseParams, method) }; } if (method === "app_start_program") { return { method, params: await this.normalizeStartProgramParam(baseParams, method) }; } if (method === "app_start_patrol") { return { method, params: this.normalizePatrolParam(baseParams, method) }; } if ( method === "app_start_replenish_clean_area" || method === "app_skip_current_cleaning_area" || method === "app_set_carpet_deep_clean_status" ) { return { method, params: this.parseJsonParam(baseParams, method) }; } if (method === "start_new_easter_egg") { return { method, params: { type: this.normalizeNumericParam(baseParams, method) } }; } if (method === "set_auto_delivery_cleaning_fluid") { return { method, params: { status: this.normalizeBinarySwitchParam(baseParams, method) } }; } if (method === "set_ap_mic_led_status" || method === "set_handle_leak_water_status") { return { method, params: { status: this.normalizeBinarySwitchParam(baseParams, method) } }; } if (method === "set_voice_service_switch") { return { method, params: { data: this.normalizeBinarySwitchParam(baseParams, method) } }; } if (method === "set_voice_chat_volume") { return { method, params: { volume: this.normalizeNumericParam(baseParams, method) } }; } if (method === "check_homesec_password") { return { method, params: { password: this.normalizeTextParam(baseParams, method) } }; } if (method === "set_homesec_password") { return { method, params: this.normalizeHomeSecPasswordParam(baseParams, method) }; } if (method === "enable_homesec_voice") { return { method, params: { enable: this.normalizeBooleanParam(baseParams, method) } }; } if ( method === "app_set_cross_carpet_cleaning_status" || method === "app_set_priority_carpet_cleaning_status" || method === "app_set_dryer_status" || method === "app_switch_dock_cool_fan" || method === "set_child_lock_status" || method === "set_collision_avoid_status" || method === "set_flow_led_status" || method === "set_map_beautification_status" || method === "test_set_enable_wakeup" ) { const key = method === "set_child_lock_status" ? "lock_status" : method === "test_set_enable_wakeup" ? "enable_wakeup" : "status"; return { method, params: { [key]: this.normalizeBinarySwitchParam(baseParams, method) } }; } if (method === "app_delete_wifi") { return { method, params: { id: this.normalizeNumericParam(baseParams, method) } }; } if (method === "test_set_voice_keep_seconds") { return { method, params: { keep_seconds: this.normalizeNumericParam(baseParams, method) } }; } if (method === "get_voice_history") { return { method, params: { max_id: this.normalizeNumericParam(baseParams, method) } }; } if (method === "app_update_unsave_map") { return { method, params: { update: this.normalizeBooleanParam(baseParams, method) } }; } if (method === "app_start_tidy_up") { const payload = this.parseJsonParam(baseParams, method); return { method, params: { objects: typeof payload === "object" && payload !== null && "objects" in payload ? (payload as { objects: unknown }).objects : payload } }; } return baseParams; } public override async onCommandResult( requestedMethod: string, finalMethod: string, response: unknown, params?: unknown ): Promise<void> { await super.onCommandResult(requestedMethod, finalMethod, response, params); switch (finalMethod) { case "app_tidy_up_record_summary": await this.applyTidyUpSummaryStatus(response); return; case "app_get_tidy_up_zones": await this.applyTidyUpZonesStatus(response); return; case "app_get_program": await this.applyProgramDetailCommandResult(response, params); return; case "app_get_programs_summary": await this.applyProgramSummaryStatus(response); return; case "app_get_program_runtime": await this.applyProgramRuntimeStatus(response); return; case "app_get_program_soundlist": await this.applyProgramSoundListStatus(response); return; case "app_get_segment_clean_subdivision": await this.applyCompactArrayStatus(response, "cleaningInfo.segmentSubdivision", "Segment Subdivision"); return; case "app_get_zoned_clean_subdivision": await this.applyCompactArrayStatus(response, "cleaningInfo.zoneSubdivision", "Zone Subdivision"); return; case "app_get_robot_setting": await this.applyRobotSettingStatus(response); return; case "app_get_clean_estimate_info": await this.applyCleanEstimateStatus(response); return; case "app_get_carpet_deep_clean_status": await this.applyCarpetDeepCleanStatus(response); return; case "app_get_dryer_setting": await this.applyDryerSettingStatus(response); return; case "app_get_wifi_list": await this.applyWifiListStatus(response); return; case "get_dock_info": await this.applyDockInfoStatus(response); return; case "get_child_lock_status": await this.applyGroupedBinaryResultStatePayload( response, "deviceStatus", "childLock", "Child Lock", "lock_status", "childLockStatus", "Child Lock Status", "childLockEnabled", "Child Lock Enabled" ); return; case "get_collision_avoid_status": await this.applyGroupedBinaryResultStatePayload( response, "deviceStatus", "collisionAvoid", "Collision Avoid", "status", "collisionAvoidStatus", "Collision Avoid Status", "collisionAvoidEnabled", "Collision Avoid Enabled" ); return; case "get_flow_led_status": await this.applyGroupedBinaryResultStatePayload( response, "deviceStatus", "flowLed", "Flow LED", "status", "flowLedStatus", "Flow LED Status", "flowLedEnabled", "Flow LED Enabled" ); return; case "get_map_beautification_status": await this.applyGroupedBinaryResultStatePayload( response, "cleaningInfo", "mapBeautification", "Map Beautification", "status", "mapBeautificationStatus", "Map Beautification Status", "mapBeautificationEnabled", "Map Beautification Enabled" ); return; case "test_get_enable_wakeup": await this.applyGroupedBinaryResultStatePayload( response, "homeSecurity", "voiceWakeup", "Voice Wakeup", "enable_wakeup", "voiceWakeupStatus", "Voice Wakeup Status", "voiceWakeupEnabled", "Voice Wakeup Enabled" ); return; case "test_get_voice_keep_seconds": await this.applyVoiceKeepSecondsStatus(response); return; case "get_voice_history_summary": await this.applyCompactJsonStatus(response, "homeSecurity.voiceHistorySummaryJSON", "Voice History Summary JSON"); return; case "get_voice_history": await this.applyVoiceHistoryStatus(response); return; case "test_get_voice_list": await this.applyCompactArrayStatus(response, "homeSecurity.voiceList", "Voice List"); return; case "get_homesec_connect_status": await this.applyHomeSecConnectStatus(response); return; case "get_auto_delivery_cleaning_fluid": await this.applyGroupedBinaryResultStatePayload( response, "dockingStationStatus", "autoDeliveryCleanFluid", "Auto Delivery Clean Fluid", "status", "autoDeliveryCleanFluidStatus", "Auto Delivery Clean Fluid Status", "autoDeliveryCleanFluidEnabled", "Auto Delivery Clean Fluid Enabled" ); return; case "get_ap_mic_led_status": await this.applyGroupedBinaryResultStatePayload( response, "homeSecurity", "voiceControlLed", "Voice Control LED", "status", "voiceControlLedStatus", "Voice Control LED Status", "voiceControlLedEnabled", "Voice Control LED Enabled" ); return; case "get_voice_service_switch": await this.applyGroupedBinaryResultStatePayload( response, "homeSecurity", "voiceService", "Voice Service", "data", "voiceServiceData", "Voice Service Data", "voiceServiceEnabled", "Voice Service Enabled" ); return; case "get_handle_leak_water_status": await this.applyGroupedBinaryResultStatePayload( response, "dockingStationStatus", "waterLeak", "Water Leak", "status", "waterLeakStatus", "Water Leak Status", "waterLeakEnabled", "Water Leak Enabled" ); return; case "get_smart_wash_params": await this.applySmartWashStatus(response, await this.getZ70FirmwareFeatures()); return; case "get_wash_towel_params": { const firmwareFeatures = await this.getZ70FirmwareFeatures(); await this.applyWashTowelSupportStates(firmwareFeatures); await this.applyWashTowelParamsStatus(response); return; } case "get_wash_towel_mode": { const firmwareFeatures = await this.getZ70FirmwareFeatures(); await this.applyWashTowelSupportStates(firmwareFeatures); await this.applyWashTowelModeStatus(response, firmwareFeatures.has(Z70_FEATURE_SOAK_AND_WASH)); return; } case "get_wash_water_temperature": { const firmwareFeatures = await this.getZ70FirmwareFeatures(); await this.applyWashTowelSupportStates(firmwareFeatures); if (firmwareFeatures.has(Z70_FEATURE_HOT_WASH_TOWEL)) { await this.applyWashTowelTemperatureStatus(response); } return; } } } protected override async processResultKey(folder: string, key: string, val: unknown): Promise<void> { await super.processResultKey(folder, key, val); if (folder !== "deviceStatus") { return; } if (key === "common_status") { await this.updateDerivedCommonStatus(val); return; } if (key === "camera_status") { await this.updateDerivedCameraStatus(val); return; } if (key === "dock_error_status") { await this.updateDerivedDockErrorStatus(val); return; } if (key === "home_sec_status") { await this.updateDerivedHomeSecStatus(val); return; } if (key === "home_sec_enable_password") { await super.processResultKey("deviceStatus", "homeSecPasswordEnabled", Number(val) === 1); return; } if (key === "lock_status") { this.z70LockStatus = Number(val); await this.refreshDerivedRobotControlStates(); return; } if (key === "switch_status") { this.z70SwitchStatus = Number(val); await this.refreshDerivedSwitchStatus(); return; } if (key === "clean_fluid") { this.z70CleanFluidStatus = Number(val); await this.refreshDerivedSwitchStatus(); return; } if (key === "is_locating") { this.z70IsLocating = Number(val) === 1; await this.refreshDerivedRobotControlStates(); return; } if (key === "voice_chat_status") { this.z70VoiceChatActive = Number(val) === 1; await super.processResultKey("deviceStatus", "voiceChatActive", this.z70VoiceChatActive); await this.refreshDerivedRobotControlStates(); return; } if (key === "monitor_status") { await super.processResultKey("deviceStatus", "monitorActive", Number(val) === 1); return; } if (key === "dry_status") { this.z70DryStatus = Number(val); await this.refreshDerivedRobotControlStates(); return; } if (key === "back_type") { await this.updateDerivedBackType(val); return; } if (ke