|
| 1 | +const capabilities = require("./capabilities"); |
| 2 | +const DreameGen2ValetudoRobot = require("./DreameGen2ValetudoRobot"); |
| 3 | +const DreameGen4ValetudoRobot = require("./DreameGen4ValetudoRobot"); |
| 4 | + |
| 5 | +const DreameQuirkFactory = require("./DreameQuirkFactory"); |
| 6 | +const DreameValetudoRobot = require("./DreameValetudoRobot"); |
| 7 | +const entities = require("../../entities"); |
| 8 | +const Logger = require("../../Logger"); |
| 9 | +const MiioValetudoRobot = require("../MiioValetudoRobot"); |
| 10 | +const QuirksCapability = require("../../core/capabilities/QuirksCapability"); |
| 11 | +const ValetudoSelectionPreset = require("../../entities/core/ValetudoSelectionPreset"); |
| 12 | +const {IMAGE_FILE_FORMAT} = require("../../utils/const"); |
| 13 | + |
| 14 | +const stateAttrs = entities.state.attributes; |
| 15 | + |
| 16 | +class DreameL20UltraValetudoRobot extends DreameGen4ValetudoRobot { |
| 17 | + |
| 18 | + /** |
| 19 | + * |
| 20 | + * @param {object} options |
| 21 | + * @param {import("../../Configuration")} options.config |
| 22 | + * @param {import("../../ValetudoEventStore")} options.valetudoEventStore |
| 23 | + */ |
| 24 | + constructor(options) { |
| 25 | + super( |
| 26 | + Object.assign( |
| 27 | + {}, |
| 28 | + { |
| 29 | + operationModes: Object.freeze({ |
| 30 | + [stateAttrs.PresetSelectionStateAttribute.MODE.VACUUM_AND_MOP]: 0, |
| 31 | + [stateAttrs.PresetSelectionStateAttribute.MODE.MOP]: 1, |
| 32 | + [stateAttrs.PresetSelectionStateAttribute.MODE.VACUUM]: 2, |
| 33 | + [stateAttrs.PresetSelectionStateAttribute.MODE.VACUUM_THEN_MOP]: 3, |
| 34 | + }), |
| 35 | + highResolutionWaterGrades: true |
| 36 | + }, |
| 37 | + options, |
| 38 | + ) |
| 39 | + ); |
| 40 | + |
| 41 | + this.registerCapability(new capabilities.DreameMapSegmentationCapability({ |
| 42 | + robot: this, |
| 43 | + miot_actions: { |
| 44 | + start: { |
| 45 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, |
| 46 | + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.ACTIONS.START.AIID |
| 47 | + } |
| 48 | + }, |
| 49 | + miot_properties: { |
| 50 | + mode: { |
| 51 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MODE.PIID |
| 52 | + }, |
| 53 | + additionalCleanupParameters: { |
| 54 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.ADDITIONAL_CLEANUP_PROPERTIES.PIID |
| 55 | + } |
| 56 | + }, |
| 57 | + segmentCleaningModeId: 18, |
| 58 | + iterationsSupported: 4, |
| 59 | + customOrderSupported: true, |
| 60 | + newOrder: true |
| 61 | + })); |
| 62 | + |
| 63 | + |
| 64 | + const quirkFactory = new DreameQuirkFactory({ |
| 65 | + robot: this |
| 66 | + }); |
| 67 | + |
| 68 | + this.registerCapability(new capabilities.DreameWaterUsageControlCapability({ |
| 69 | + robot: this, |
| 70 | + presets: Object.keys(this.waterGrades).map(k => { |
| 71 | + return new ValetudoSelectionPreset({name: k, value: this.waterGrades[k]}); |
| 72 | + }), |
| 73 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.MOP_EXPANSION.SIID, |
| 74 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.MOP_EXPANSION.PROPERTIES.HIGH_RES_WATER_USAGE.PIID |
| 75 | + })); |
| 76 | + |
| 77 | + this.registerCapability(new capabilities.DreameZoneCleaningCapability({ |
| 78 | + robot: this, |
| 79 | + miot_actions: { |
| 80 | + start: { |
| 81 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, |
| 82 | + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.ACTIONS.START.AIID |
| 83 | + } |
| 84 | + }, |
| 85 | + miot_properties: { |
| 86 | + mode: { |
| 87 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MODE.PIID |
| 88 | + }, |
| 89 | + additionalCleanupParameters: { |
| 90 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.ADDITIONAL_CLEANUP_PROPERTIES.PIID |
| 91 | + } |
| 92 | + }, |
| 93 | + zoneCleaningModeId: 19, |
| 94 | + maxZoneCount: 4 |
| 95 | + })); |
| 96 | + |
| 97 | + this.registerCapability(new capabilities.DreameConsumableMonitoringCapability({ |
| 98 | + robot: this, |
| 99 | + miot_properties: { |
| 100 | + main_brush: { |
| 101 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAIN_BRUSH.SIID, |
| 102 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAIN_BRUSH.PROPERTIES.TIME_LEFT.PIID |
| 103 | + }, |
| 104 | + side_brush: { |
| 105 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.SIDE_BRUSH.SIID, |
| 106 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.SIDE_BRUSH.PROPERTIES.TIME_LEFT.PIID |
| 107 | + }, |
| 108 | + filter: { |
| 109 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.FILTER.SIID, |
| 110 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.FILTER.PROPERTIES.TIME_LEFT.PIID |
| 111 | + }, |
| 112 | + sensor: { |
| 113 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.SENSOR.SIID, |
| 114 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.SENSOR.PROPERTIES.TIME_LEFT.PIID |
| 115 | + }, |
| 116 | + wheel: { |
| 117 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.WHEEL.SIID, |
| 118 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.WHEEL.PROPERTIES.TIME_LEFT.PIID |
| 119 | + } |
| 120 | + }, |
| 121 | + miot_actions: { |
| 122 | + reset_main_brush: { |
| 123 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAIN_BRUSH.SIID, |
| 124 | + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAIN_BRUSH.ACTIONS.RESET.AIID |
| 125 | + }, |
| 126 | + reset_side_brush: { |
| 127 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.SIDE_BRUSH.SIID, |
| 128 | + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.SIDE_BRUSH.ACTIONS.RESET.AIID |
| 129 | + }, |
| 130 | + reset_filter: { |
| 131 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.FILTER.SIID, |
| 132 | + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.FILTER.ACTIONS.RESET.AIID |
| 133 | + }, |
| 134 | + reset_sensor: { |
| 135 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.SENSOR.SIID, |
| 136 | + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.SENSOR.ACTIONS.RESET.AIID |
| 137 | + }, |
| 138 | + reset_wheel: { |
| 139 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.WHEEL.SIID, |
| 140 | + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.WHEEL.ACTIONS.RESET.AIID |
| 141 | + } |
| 142 | + }, |
| 143 | + })); |
| 144 | + |
| 145 | + this.registerCapability(new capabilities.DreameOperationModeControlCapability({ |
| 146 | + robot: this, |
| 147 | + presets: Object.keys(this.operationModes).map(k => { |
| 148 | + return new ValetudoSelectionPreset({name: k, value: this.operationModes[k]}); |
| 149 | + }), |
| 150 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, |
| 151 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID |
| 152 | + })); |
| 153 | + |
| 154 | + this.registerCapability(new capabilities.DreameCarpetSensorModeControlCapability({ |
| 155 | + robot: this, |
| 156 | + liftSupported: true, |
| 157 | + detachSupported: true |
| 158 | + })); |
| 159 | + |
| 160 | + this.registerCapability(new capabilities.DreameObstacleImagesCapability({ |
| 161 | + robot: this, |
| 162 | + fileFormat: IMAGE_FILE_FORMAT.JPG, |
| 163 | + dimensions: { |
| 164 | + width: 672, |
| 165 | + height: 504 |
| 166 | + } |
| 167 | + })); |
| 168 | + |
| 169 | + this.registerCapability(new capabilities.DreameMapSegmentMaterialControlCapability({ |
| 170 | + robot: this, |
| 171 | + miot_actions: { |
| 172 | + map_edit: { |
| 173 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAP.SIID, |
| 174 | + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAP.ACTIONS.EDIT.AIID |
| 175 | + } |
| 176 | + }, |
| 177 | + miot_properties: { |
| 178 | + mapDetails: { |
| 179 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAP.PROPERTIES.MAP_DETAILS.PIID |
| 180 | + }, |
| 181 | + actionResult: { |
| 182 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAP.PROPERTIES.ACTION_RESULT.PIID |
| 183 | + } |
| 184 | + }, |
| 185 | + supportedMaterials: [ |
| 186 | + capabilities.DreameMapSegmentMaterialControlCapability.MATERIAL.GENERIC, |
| 187 | + capabilities.DreameMapSegmentMaterialControlCapability.MATERIAL.TILE, |
| 188 | + capabilities.DreameMapSegmentMaterialControlCapability.MATERIAL.WOOD_VERTICAL, |
| 189 | + capabilities.DreameMapSegmentMaterialControlCapability.MATERIAL.WOOD_HORIZONTAL, |
| 190 | + ] |
| 191 | + })); |
| 192 | + |
| 193 | + |
| 194 | + [ |
| 195 | + capabilities.DreameCarpetModeControlCapability, |
| 196 | + capabilities.DreameKeyLockCapability, |
| 197 | + capabilities.DreameAutoEmptyDockManualTriggerCapability, |
| 198 | + capabilities.DreameMopDockCleanManualTriggerCapability, |
| 199 | + capabilities.DreameMopDockDryManualTriggerCapability, |
| 200 | + capabilities.DreameAICameraGoToLocationCapability, |
| 201 | + capabilities.DreameAICameraLineLaserObstacleAvoidanceControlCapability, |
| 202 | + capabilities.DreamePetObstacleAvoidanceControlCapability, |
| 203 | + capabilities.DreameCollisionAvoidantNavigationControlCapability, |
| 204 | + capabilities.DreameAutoEmptyDockAutoEmptyIntervalControlCapabilityV2, |
| 205 | + capabilities.DreameMopExtensionControlCapabilityV1, |
| 206 | + capabilities.DreameCameraLightControlCapability, |
| 207 | + capabilities.DreameMopTwistControlCapabilityV2, |
| 208 | + capabilities.DreameMopExtensionFurnitureLegHandlingControlCapability, |
| 209 | + capabilities.DreameMopDockMopAutoDryingControlCapability, |
| 210 | + capabilities.DreameFloorMaterialDirectionAwareNavigationControlCapability, |
| 211 | + capabilities.DreameCleanRouteControlCapabilityV2, |
| 212 | + capabilities.DreameMopDockMopDryingTimeControlCapability, |
| 213 | + ].forEach(capability => { |
| 214 | + this.registerCapability(new capability({robot: this})); |
| 215 | + }); |
| 216 | + |
| 217 | + this.registerCapability(new QuirksCapability({ |
| 218 | + robot: this, |
| 219 | + quirks: [ |
| 220 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.CARPET_MODE_SENSITIVITY), |
| 221 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.MOP_DOCK_MOP_CLEANING_FREQUENCY), |
| 222 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.MOP_DRYING_TIME), |
| 223 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.MOP_DOCK_DETERGENT), |
| 224 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.MOP_DOCK_WET_DRY_SWITCH), |
| 225 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.MOP_DOCK_AUTO_REPAIR_TRIGGER), |
| 226 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.DRAIN_INTERNAL_WATER_TANK), |
| 227 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.CARPET_DETECTION_AUTO_DEEP_CLEANING), |
| 228 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.MOP_DOCK_WATER_USAGE), |
| 229 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.DETACH_MOPS), |
| 230 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.MOP_DOCK_CLEANING_PROCESS_TRIGGER), |
| 231 | + quirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.WATER_HOOKUP_TEST_TRIGGER), |
| 232 | + ] |
| 233 | + })); |
| 234 | + |
| 235 | + this.state.upsertFirstMatchingAttribute(new entities.state.attributes.DockStatusStateAttribute({ |
| 236 | + value: entities.state.attributes.DockStatusStateAttribute.VALUE.IDLE |
| 237 | + })); |
| 238 | + |
| 239 | + this.state.upsertFirstMatchingAttribute(new entities.state.attributes.AttachmentStateAttribute({ |
| 240 | + type: entities.state.attributes.AttachmentStateAttribute.TYPE.MOP, |
| 241 | + attached: false |
| 242 | + })); |
| 243 | + } |
| 244 | + |
| 245 | + parseAndUpdateState(data) { |
| 246 | + if (!Array.isArray(data)) { |
| 247 | + Logger.error("Received non-array state", data); |
| 248 | + return; |
| 249 | + } |
| 250 | + |
| 251 | + // Filter out everything that might confuse the regular state parsing |
| 252 | + return super.parseAndUpdateState(data.filter(e => { |
| 253 | + return ( |
| 254 | + !( |
| 255 | + e.siid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID && |
| 256 | + e.piid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.WATER_USAGE.PIID |
| 257 | + ) |
| 258 | + ); |
| 259 | + })); |
| 260 | + } |
| 261 | + |
| 262 | + getStatePropertiesToPoll() { |
| 263 | + const superProps = super.getStatePropertiesToPoll(); |
| 264 | + |
| 265 | + return [ |
| 266 | + ...superProps.filter(e => { |
| 267 | + return !( |
| 268 | + e.siid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID && |
| 269 | + e.piid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.WATER_USAGE.PIID |
| 270 | + ); |
| 271 | + }), |
| 272 | + |
| 273 | + { |
| 274 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.AUTO_EMPTY_DOCK.SIID, |
| 275 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.AUTO_EMPTY_DOCK.PROPERTIES.STATE.PIID |
| 276 | + }, |
| 277 | + { |
| 278 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, |
| 279 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_STATUS.PIID |
| 280 | + }, |
| 281 | + { |
| 282 | + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, |
| 283 | + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID |
| 284 | + } |
| 285 | + ]; |
| 286 | + } |
| 287 | + |
| 288 | + getModelName() { |
| 289 | + return "L20 Ultra"; |
| 290 | + } |
| 291 | + |
| 292 | + getModelDetails() { |
| 293 | + return Object.assign( |
| 294 | + {}, |
| 295 | + super.getModelDetails(), |
| 296 | + { |
| 297 | + supportedAttachments: [ |
| 298 | + stateAttrs.AttachmentStateAttribute.TYPE.MOP, |
| 299 | + ] |
| 300 | + } |
| 301 | + ); |
| 302 | + } |
| 303 | + |
| 304 | + |
| 305 | + static IMPLEMENTATION_AUTO_DETECTION_HANDLER() { |
| 306 | + const deviceConf = MiioValetudoRobot.READ_DEVICE_CONF(DreameValetudoRobot.DEVICE_CONF_PATH); |
| 307 | + |
| 308 | + // R2253 is a different bot entirely and not supportable |
| 309 | + return [ |
| 310 | + "dreame.vacuum.r2394j", |
| 311 | + "dreame.vacuum.r2394k", |
| 312 | + "dreame.vacuum.r2394s", |
| 313 | + ].includes(deviceConf?.model); |
| 314 | + } |
| 315 | +} |
| 316 | + |
| 317 | + |
| 318 | +module.exports = DreameL20UltraValetudoRobot; |
0 commit comments