UNPKG

iobroker.roborock

Version:
636 lines (624 loc) 22.9 kB
import { ADAPTER_ERRORS_EN } from "./adapterErrorMapping"; const Z70_TIDY_UP_TASK_STATES: Record<number, string> = { 0: "No Need", 1: "Need", 2: "To Tidy", 3: "Success", 4: "Not Found", 5: "User Handled", 6: "Shoes Unsupported", 7: "Object Unreachable", 8: "Object On Carpet", 9: "Object In Forbidden Zone", 10: "Object In Low Area", 11: "Object In Unsafe Area", 12: "Object Overweight", 13: "Put Point Unreachable", 14: "Put Point Not Found", 15: "Put Down Failed", 16: "Failed To Grasp", 17: "Failed To Compute Joints", 18: "Out Compartment Failed", 19: "Out Compartment Invalid Area", 20: "Grasp Position Unreachable", 21: "Already In Storage Zone", }; const Z70_BACK_TYPE_STATES: Record<number, string> = { 1: "Washing Mop", 2: "Setting Up Mop", 3: "Removing Mop", 4: "Collecting Dust", }; const Z70_WASH_PHASE_STATES: Record<number, string> = { 11: "Running", 17: "Pumping", }; const Z70_WASHING_MODE_STATES: Record<number, string> = { 6: "Dock Self-Cleaning", 7: "Water Draining", 11: "Pumping Water", }; const Z70_WATER_SHORTAGE_STATES: Record<number, string> = { 0: "Normal", 1: "Water Shortage", }; export const VACUUM_CONSTANTS = { errorCodes: { 0: "No error", // Use S7 MaxV English defaults as the standardized error definition for the entire adapter // This supersedes legacy hardcoded lists and serves as the baseline for V1 and B01 ...ADAPTER_ERRORS_EN, // Add legacy/missing codes 254: "Bin full", 255: "Internal error", "-1": "Unknown Error", }, stateCodes: { 0: "Unknown", 1: "Initiating", 2: "Sleeping", 3: "Idle", 4: "Remote Control", 5: "Cleaning", 6: "Returning Dock", 7: "Manual Mode", 8: "Charging", 9: "Charging Error", 10: "Paused", 11: "Spot Cleaning", 12: "In Error", 13: "Shutting Down", 14: "Updating", 15: "Docking", 16: "Go To", 17: "Zone Clean", 18: "Room Clean", 22: "Emptying dust container", 23: "Washing the mop", 25: "Washing duster", 26: "Going to wash the mop", 28: "In call", 29: "Mapping", 30: "Egg attack", 32: "Patrol", 33: "Setting up the mop", 34: "Removing the mop", 36: "Exhibition mode", 37: "Dance", 38: "Tidy-up housework", 39: "Remote pick-up", 40: "Emergency stop", 41: "Arm resetting", 42: "Program mode", 100: "Fully Charged", 101: "Offline", 102: "Unknown", }, dockTypes: { 0: "Charging dock", 1: "Auto-Empty Dock", 2: "Empty Wash Fill Dock", 3: "Empty Wash Fill (Dry) Dock", 5: "Auto-Empty Dock (Q8 Max+)", 6: "Empty Wash Fill Dry Dock (S8 Pro Ultra)", 7: "Empty Wash Fill Dry Dock (S8 Pro Ultra)", 8: "Empty Wash Fill Dry Dock (Q Revo)", 9: "Empty Wash Fill Dry Dock (Q Revo Pro)", 10: "Empty Wash Fill Dock (S7 MaxV Ultra)", 14: "Empty Wash Fill Dry Dock (Qrevo Master)", 15: "Empty Wash Fill Dry Dock (Qrevo S)", 16: "Empty Wash Fill Dry Dock (Saros 10R / Saros Z70)", 17: "Empty Wash Fill Dry Dock (Qrevo Curv)", 18: "Empty Wash Fill Dry Dock (S8 Pro)", }, // B01 Devices: Property lists (Protocol 101/102 via prop.get) b01StatusProps: [ "status", "fault", "wind", "water", "mode", "quantity", "repeat_state", "tank_state", "sweep_type", "clean_path_preference", "cloth_state", "time_zone", "time_zone_info", "language", "cleaning_time", "real_clean_time", "cleaning_area", "custom_type", "work_mode", "charge_state", "current_map_id", "map_num", "dust_action", "quiet_is_open", "clean_finish", "build_map", "dust_frequency", "multi_floor", "pv_charging", "recommend", "add_sweep_status", "clean_fluid" ], b01SettingsProps: [ "alarm", "volume", "hypa", "main_brush", "side_brush", "mop_life", "main_sensor", "net_status", "sound", "station_act", "quiet_begin_time", "quiet_end_time", "voice_type", "voice_type_version", "order_total", "privacy", "dust_auto_state", "light_mode", "order_save_mode", "manufacturer", "child_lock", "charge_station_type", "carpet_turbo", "green_laser" ], baseCommands: { app_start: { type: "boolean", def: false }, app_segment_clean: { type: "boolean", def: false }, app_stop: { type: "boolean", def: false }, app_pause: { type: "boolean", def: false }, app_charge: { type: "boolean", def: false }, app_spot: { type: "boolean", def: false }, app_zoned_clean: { type: "json" }, resume_zoned_clean: { type: "boolean", def: false }, stop_zoned_clean: { type: "boolean", def: false }, resume_segment_clean: { type: "boolean", def: false }, stop_segment_clean: { type: "boolean", def: false }, set_custom_mode: { type: "number", def: 102, states: { 101: "Quiet", 102: "Balanced", 103: "Turbo", 104: "Max", 105: "Off" } }, find_me: { type: "boolean", def: false }, app_goto_target: { type: "json" }, set_clean_motor_mode: { type: "json", def: '{"fan_power":102,"mop_mode":300,"water_box_mode":201}' }, }, deviceStates: { dock_type: { name: "Dock Type", type: "number", states: { 0: "Charging dock", 1: "Auto-Empty Dock", 2: "Empty Wash Fill Dock", 3: "Empty Wash Fill (Dry) Dock", 5: "Auto-Empty Dock (Q8 Max+)", 6: "Empty Wash Fill Dry Dock (S8 Pro Ultra)", 7: "Empty Wash Fill Dry Dock (S8 Pro Ultra)", 8: "Empty Wash Fill Dry Dock (Q Revo)", 9: "Empty Wash Fill Dry Dock (Q Revo Pro)", 10: "Empty Wash Fill Dock (S7 MaxV Ultra)", 14: "Empty Wash Fill Dry Dock (Qrevo Master)", 15: "Empty Wash Fill Dry Dock (Qrevo S)", 16: "Empty Wash Fill Dry Dock (Saros 10R / Saros Z70)", 17: "Empty Wash Fill Dry Dock (Qrevo Curv)", 18: "Empty Wash Fill Dry Dock (S8 Pro)", } }, error_code: { type: "number", states: {} }, clean_area: { type: "number", unit: "m²" }, clean_time: { type: "number", unit: "min" }, battery: { type: "number", unit: "%" }, state: { type: "number", states: {} }, fan_power: { type: "number", states: { 101: "Quiet", 102: "Balanced", 103: "Turbo", 104: "Max", 105: "Off" } }, clean_percent: { type: "number", unit: "%" }, water_box_mode: { type: "number", states: { 200: "Off", 201: "Mild", 202: "Moderate", 203: "Intense", 204: "Custom", 205: "Custom", 206: "Custom", 207: "Custom", 208: "Custom", 209: "Custom" } }, mop_mode: { type: "number", states: { 300: "Standard", 301: "Deep", 303: "Deep+", 304: "Fast" } }, carpet_mode: { type: "string", states: { '[{"enable":0,"stall_time":10,"current_low":400,"current_high":500,"current_integral":450}]': "off", '[{"enable":1,"stall_time":10,"current_low":400,"current_high":500,"current_integral":450}]': "on", }, }, carpet_clean_mode: { type: "number", states: { 0: "Avoid", 1: "Rise", 2: "Ignore", }, }, unsave_map_flag: { type: "number" }, unsave_map_reason: { type: "number" }, dock_error_status: { type: "number" }, debug_mode: { type: "number" }, auto_dust_collection: { type: "number" }, dust_collection_status: { type: "number" }, adbumper_status: { type: "string" }, lock_status: { type: "number" }, is_locating: { type: "number" }, map_status: { type: "number" }, dnd_enabled: { type: "number" }, lab_status: { type: "number" }, in_fresh_state: { type: "number" }, in_returning: { type: "number" }, in_cleaning: { type: "number" }, in_warmup: { type: "number" }, map_present: { type: "number" }, is_exploring: { type: "number" }, events: { type: "string" }, subdivision_sets: { type: "number" }, repeat: { type: "number" }, replenish_mode: { type: "number" }, rdt: { type: "number" }, camera_status: { type: "number" }, distance_off: { name: "Distance Off", type: "number" }, wash_phase: { type: "number", states: Z70_WASH_PHASE_STATES }, wash_ready: { type: "number" }, wash_status: { type: "number" }, back_type: { type: "number", states: Z70_BACK_TYPE_STATES }, backTypeLabel: { name: "Back Dock Substate", type: "string" }, collision_avoid_status: { type: "number" }, avoid_count: { type: "number" }, switch_map_mode: { type: "number" }, charge_status: { type: "number" }, dry_status: { type: "number" }, extra_time: { type: "number" }, rss: { type: "number" }, dss: { type: "number" }, common_status: { type: "number" }, hasDockError: { name: "Dock Error Active", type: "boolean" }, isAutoDeliveryOn: { name: "Auto Delivery Active", type: "boolean" }, isVocieControlActive: { name: "Voice Control Active", type: "boolean" }, patrolStatus: { name: "Patrol Status", type: "number" }, patrolActive: { name: "Patrol Active", type: "boolean" }, mechanicalTidyUpHouseworkState: { name: "Mechanical Tidy-Up Housework State", type: "number", states: { 0: "Idle", 1: "Active", }, }, mechanicalArmGrabStatus: { name: "Mechanical Arm Grab Status", type: "number", states: { 0: "Not Started", 1: "Exiting Door", 2: "Entering Door", 3: "Waiting", 4: "Grabbing", 5: "Putting Down", 7: "Continue", 8: "Mode Changing", 9: "Continue to Grab", 10: "Continue to Put Down", }, }, mechanicalArmGrabMode: { name: "Mechanical Arm Grab Mode", type: "number", states: { 0: "Off", 1: "Manual", 2: "Auto", }, }, mechanicalArmGrabResult: { name: "Mechanical Arm Grab Result", type: "number", states: { 0: "No Success", 1: "Success", }, }, assistedTidyUp: { name: "Assisted Tidy-Up", type: "number", states: { 0: "Off", 1: "On", }, }, mechanicalArmActiveStatus: { name: "Mechanical Arm Active Status", type: "number", states: { 0: "Inactive", 1: "Active", }, }, canChangeCameraStatus: { name: "Can Change Camera Status", type: "number", states: { 0: "No", 1: "Yes", }, }, notInGrabMode: { name: "Not In Grab Mode", type: "boolean" }, manualGrabMode: { name: "Manual Grab Mode", type: "boolean" }, autoGrabMode: { name: "Auto Grab Mode", type: "boolean" }, notStart: { name: "Grab Not Started", type: "boolean" }, isExitingDoor: { name: "Arm Exiting Door", type: "boolean" }, isEnteringDoor: { name: "Arm Entering Door", type: "boolean" }, isWaiting: { name: "Arm Waiting", type: "boolean" }, isGrabing: { name: "Arm Grabbing", type: "boolean" }, isPuttingDown: { name: "Arm Putting Down", type: "boolean" }, isContinue: { name: "Arm Continue", type: "boolean" }, isContinueToGrab: { name: "Arm Continue To Grab", type: "boolean" }, isContinueToPutDown: { name: "Arm Continue To Put Down", type: "boolean" }, isMechanicalModeChanging: { name: "Mechanical Mode Changing", type: "boolean" }, isGrabSucessful: { name: "Grab Successful", type: "boolean" }, isEmergencyStopStatus: { name: "Emergency Stop Active", type: "boolean" }, isArmResetting: { name: "Arm Resetting", type: "boolean" }, isProgramMode: { name: "Program Mode Active", type: "boolean" }, isLocked: { name: "Locked", type: "boolean" }, isDrying: { name: "Drying", type: "boolean" }, isExitingDock: { name: "Exiting Dock", type: "boolean" }, isBackDockWashingDusterMode: { name: "Back Dock Washing Duster Mode", type: "boolean" }, isWashing: { name: "Washing", type: "boolean" }, isSpotCleaning: { name: "Spot Cleaning", type: "boolean" }, isZonedCleaning: { name: "Zoned Cleaning", type: "boolean" }, isSegmentCleaning: { name: "Segment Cleaning", type: "boolean" }, dockCanStopCollectDust: { name: "Dock Can Stop Collect Dust", type: "boolean" }, dockCanStopWash: { name: "Dock Can Stop Wash", type: "boolean" }, isInBackDockTask: { name: "In Back Dock Task", type: "boolean" }, isBackDockTaskResumeable: { name: "Back Dock Task Resumeable", type: "boolean" }, isReadyToCmd: { name: "Ready To Command", type: "boolean" }, canPauseByToast: { name: "Can Pause By Toast", type: "boolean" }, isTidyUpHouseWork: { name: "Tidy-Up Housework", type: "boolean" }, offlineMapEnabled: { name: "Offline Map Enabled", type: "boolean" }, hasCleanFluidModule: { name: "Clean Fluid Module Installed", type: "boolean" }, isSettingCarpetFirstOn: { name: "Carpet-First Cleaning Enabled", type: "boolean" }, isSettingCarpetCrossOn: { name: "Cross-Carpet Cleaning Enabled", type: "boolean" }, isSettingDirtyReplenishOn: { name: "Dirty-Replenish Cleaning Enabled", type: "boolean" }, washPhaseLabel: { name: "Wash Phase", type: "string" }, isHomeButtonsEnabled: { name: "Home Buttons Enabled", type: "boolean" }, isHomeModeControlButtonsEnabled: { name: "Home Mode Control Buttons Enabled", type: "boolean" }, isHomeMapEditButtonsEnabled: { name: "Home Map Edit Buttons Enabled", type: "boolean" }, isHomeSettingButtonEnabled: { name: "Home Setting Button Enabled", type: "boolean" }, hasMechanicalArmEmergencyError: { name: "Mechanical Arm Emergency Error", type: "boolean" }, mechArmTidyupTaskState: { name: "Mechanical Tidy-Up Task State", type: "number", states: Z70_TIDY_UP_TASK_STATES, }, mechArmTidyupObjectType: { name: "Mechanical Tidy-Up Object Type", type: "number", states: { 0: "None", 2: "Shoes", 34: "Fabrics / Sock", 51: "Clumps / Curled Fabric", }, }, mechArmTidyupObjectLabel: { name: "Mechanical Tidy-Up Object Label", type: "string" }, mechArmMoveTaskState: { name: "Mechanical Move Task State", type: "number", states: Z70_TIDY_UP_TASK_STATES, }, mechArmMoveObjectType: { name: "Mechanical Move Object Type", type: "number", states: { 0: "None", 2: "Shoes", 34: "Fabrics / Sock", 51: "Clumps / Curled Fabric", }, }, mechArmMoveObjectLabel: { name: "Mechanical Move Object Label", type: "string" }, isMechArmDoingTidyupTask: { name: "Mechanical Tidy-Up Task Active", type: "boolean" }, isMechArmDoingMoveTask: { name: "Mechanical Move Task Active", type: "boolean" }, cameraEnabled: { name: "Camera Enabled", type: "boolean" }, petModeEnabled: { name: "Pet Mode Enabled", type: "boolean" }, realTimeMonitorEnabled: { name: "Real-Time Monitor Enabled", type: "boolean" }, ledSetting: { name: "Camera LED Setting", type: "number" }, monitorPrivacyPolicyAgreed: { name: "Monitor Privacy Policy Agreed", type: "boolean" }, explorationEnabled: { name: "Exploration Enabled", type: "boolean" }, hasShownPetModeAlert: { name: "Has Shown Pet Mode Alert", type: "boolean" }, realVideoSetting: { name: "Real Video Setting", type: "number", states: { 0: "Lightly Disturb", 1: "Strong Reminder", 2: "Do Not Disturb", }, }, mapObjectPhotoEnabled: { name: "Map Object Photo Enabled", type: "boolean" }, mapObjectPhotoPrivacyPolicyAgreed: { name: "Map Object Photo Privacy Policy Agreed", type: "boolean" }, realTimeVideoWithTwoKeysStatus: { name: "Real-Time Video Two-Key Status", type: "number", states: { 0: "Off", 1: "Waiting Activation", 2: "Active", }, }, petSnapshotEnabled: { name: "Pet Snapshot Enabled", type: "boolean" }, mechanicalCameraEnabled: { name: "Mechanical Camera Enabled", type: "boolean" }, kct: { type: "number" }, sterilize_status: { type: "number" }, rst: { type: "number" }, switch_status: { type: "number" }, last_clean_t: { type: "string" }, cleaning_info: { type: "string" }, exit_dock: { type: "number" }, clean_tidyup_status: { name: "Tidy-Up Status", type: "number" }, assist_clean_status: { name: "Assist Clean Status", type: "number" }, sub_error_code: { name: "Sub Error Code", type: "number" }, dtof_status: { type: "number" }, seq_type: { type: "number" }, mop_forbidden_enable: { type: "number" }, voice_chat_status: { type: "number", states: { 0: "Inactive", 1: "Active", }, }, corner_clean_mode: { type: "number" }, home_sec_status: { type: "number", states: { 0: "Disconnected", 1: "Connected", 2: "Disconnecting", }, }, home_sec_enable_password: { type: "number", states: { 0: "Disabled", 1: "Enabled", }, }, monitor_status: { type: "number", states: { 0: "Inactive", 1: "Active", }, }, homeSecClientId: { name: "Home Security Client ID", type: "string" }, isHomeSecControlledByCurrentClient: { name: "Home Security Controlled By Current Client", type: "boolean" }, isHomeSecFreeControl: { name: "Home Security Free Control", type: "boolean" }, isHomeSecRunning: { name: "Home Security Running", type: "boolean" }, isHomeSecDisconnected: { name: "Home Security Disconnected", type: "boolean" }, isHomeSecDisconnecting: { name: "Home Security Disconnecting", type: "boolean" }, isHomeSecPreviewStartReady: { name: "Home Security Preview Start Ready", type: "boolean" }, isHomeSecPreviewRetryPending: { name: "Home Security Preview Retry Pending", type: "boolean" }, isHomeSecPreviewOwnedByCurrentClient: { name: "Home Security Preview Owned By Current Client", type: "boolean" }, isHomeSecPreviewBlockedByOtherClient: { name: "Home Security Preview Blocked By Other Client", type: "boolean" }, homeSecPasswordEnabled: { name: "Home Security Password Enabled", type: "boolean" }, monitorActive: { name: "Monitor Active", type: "boolean" }, voiceChatActive: { name: "Voice Chat Active", type: "boolean" }, clean_fluid: { type: "number" }, water_box_carriage_status: { type: "number" }, water_box_status: { type: "number" }, water_shortage_status: { type: "number", states: Z70_WATER_SHORTAGE_STATES }, waterShortageActive: { name: "Water Shortage Active", type: "boolean" }, cleaned_area: { type: "number", unit: "m²" }, clean_times: { type: "number" }, along_floor: { type: "number", def: 0, states: { 0: "Off", 1: "On" }, write: true }, green_laser: { type: "number", def: 0, states: { 0: "Off", 1: "On" }, write: true }, dust_bag_used: { type: "number", def: 0 }, add_sweep_status: { type: "number", def: 0, states: { 0: "None", 1: "Active" } }, clean_finish: { type: "string" }, status: { type: "number", def: 3, states: { 1: "Start", 2: "Stop", 3: "Idle", 5: "Cleaning", 6: "Home", 7: "Manual", 8: "Charging", 9: "Charge Error", 10: "Pause", 11: "Spot", 12: "Error", 14: "Updating", 15: "Docking", 16: "Go To", 17: "Zone Clean", 18: "Room Clean", 22: "Emptying", 23: "Washing", 26: "Going to Wash", 28: "In Call", 29: "Mapping", 100: "Fully Charged", }, write: true, }, washingTaskStatus: { name: "Washing Task Status", type: "number", def: 0, states: {} }, washingMode: { name: "Washing Mode", type: "number", def: 0, states: Z70_WASHING_MODE_STATES }, washingModeLabel: { name: "Washing Mode Label", type: "string" }, isCleanCarouselSelfCleaning: { name: "Dock Self-Cleaning Active", type: "boolean" }, isWaterDraining: { name: "Water Draining Active", type: "boolean" }, isPumpingWater: { name: "Water Pumping Active", type: "boolean" }, wind: { type: "number", def: 102, states: { 101: "Quiet", 102: "Balanced", 103: "Turbo", 104: "Max", 105: "Off", 108: "Max+" }, write: true, }, water: { type: "number", def: 201, states: { 200: "Off", 201: "Mild", 202: "Moderate", 203: "Intense", 204: "Custom" }, write: true, }, }, consumables: { // Raw keys from robot (converted to hours/cycles where applicable) main_brush_work_time: { type: "number", unit: "h" }, side_brush_work_time: { type: "number", unit: "h" }, filter_work_time: { type: "number", unit: "h" }, filter_element_work_time: { type: "number", unit: "h" }, sensor_dirty_time: { type: "number", unit: "h" }, main_brush_life: { type: "number", unit: "%" }, side_brush_life: { type: "number", unit: "%" }, filter_life: { type: "number", unit: "%" }, dust_collection_work_times: { type: "number", unit: "cycles" }, strainer_work_times: { type: "number", unit: "cycles" }, cleaning_brush_work_times: { type: "number", unit: "cycles" }, } as const, consumableTranslationKeys: { main_brush: "localization_strings_Setting_Supplies_Common_4", side_brush: "localization_strings_Setting_Supplies_Common_2", filter: "localization_strings_Setting_Supplies_Common_0", filter_element: "supplies_waterbox_chip_name", sensor: "supplies_sensors_name", mop: "custom_mode_panel_mop_gear_title", strainer: "supplies_strainer_name", dust_collection: "dust_collection_life5", cleaning_brush: "home_page_supplies_cleaning_brush1" } as const, dockingStationTranslationKeys: { cleanFluidStatus: "dock_info_clean_fluid_title", waterBoxFilterStatus: "dock_info_water_box_filter_title", dustBagStatus: "dust_collection_life5", dirtyWaterBoxStatus: "dock_info_dirty_water_box_title", clearWaterBoxStatus: "dock_info_clear_water_box_title", isUpdownWaterReady: "inner_error_name_152" } as const, resetConsumables: new Set([ "main_brush_work_time", "side_brush_work_time", "filter_work_time", "filter_element_work_time", "sensor_dirty_time", "dust_collection_work_times", "strainer_work_times", "cleaning_brush_work_times", ]), cleaningRecords: { 0: { type: "string" }, // begin 1: { type: "string" }, // end 2: { type: "number", unit: "min" }, // duration 3: { type: "number", unit: "m²" }, // area 4: { type: "number" }, // error 5: { type: "number" }, // complete 6: { type: "number" }, // start_type 7: { type: "number" }, // clean_type 8: { type: "number" }, // finish_reason 9: { type: "number" }, // dust_collection_status // Mapped from name begin: { type: "string" }, end: { type: "string" }, duration: { type: "number", unit: "min" }, area: { type: "number", unit: "m²" }, error: { type: "number" }, complete: { type: "number" }, start_type: { type: "number" }, clean_type: { type: "number" }, finish_reason: { type: "number" }, dust_collection_status: { type: "number" }, cleaned_area: { type: "number", unit: "m²" }, task_id: { type: "number" }, clean_times: { type: "number" }, dirty_replenish: { type: "number" }, manual_replenish: { type: "number" }, map_flag: { type: "number" }, wash_count: { type: "number" }, avoid_count: { type: "number" }, sub_source: { type: "number" }, extra_time: { type: "number" }, }, cleaningInfo: { 0: { type: "number", unit: "h" }, 1: { type: "number", unit: "m²" }, clean_time: { type: "number", unit: "h" }, clean_area: { type: "number", unit: "m²" }, clean_count: { type: "number" }, dust_collection_count: { type: "number" }, }, firmwareFeatures: { 41: "isHotWashTowelSupported", 111: "isSupportFDSEndPoint", 112: "isSupportAutoSplitSegments", 114: "isSupportOrderSegmentClean", 107: "isSoakAndWashSupported", 109: "isBackWashNewSmartSupported", 116: "isMapSegmentSupported", 119: "isSupportLedStatusSwitch", 120: "isMultiFloorSupported", 122: "isSupportFetchTimerSummary", 123: "isOrderCleanSupported", 125: "isRemoteSupported", } as const, }; export type FirmwareFeatures = typeof VACUUM_CONSTANTS.firmwareFeatures; export type FirmwareFeatureId = keyof FirmwareFeatures;