From 9b0182968e277c3a7dbc991650704da4eb45c4ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Beye?= Date: Thu, 11 Jan 2024 23:01:28 +0100 Subject: [PATCH] feat(vendor.dreame): Add implementation for the R2211 --- .../dreame/DreameS10PlusValetudoRobot.js | 187 ++++++++++++++++++ backend/lib/robots/dreame/index.js | 1 + util/generate_robot_docs.js | 1 + 3 files changed, 189 insertions(+) create mode 100644 backend/lib/robots/dreame/DreameS10PlusValetudoRobot.js diff --git a/backend/lib/robots/dreame/DreameS10PlusValetudoRobot.js b/backend/lib/robots/dreame/DreameS10PlusValetudoRobot.js new file mode 100644 index 00000000000..734f3f15655 --- /dev/null +++ b/backend/lib/robots/dreame/DreameS10PlusValetudoRobot.js @@ -0,0 +1,187 @@ +const capabilities = require("./capabilities"); +const DreameGen2LidarValetudoRobot = require("./DreameGen2LidarValetudoRobot"); +const DreameGen2ValetudoRobot = require("./DreameGen2ValetudoRobot"); +const DreameQuirkFactory = require("./DreameQuirkFactory"); +const DreameValetudoRobot = require("./DreameValetudoRobot"); +const entities = require("../../entities"); +const fs = require("fs"); +const MiioValetudoRobot = require("../MiioValetudoRobot"); +const QuirksCapability = require("../../core/capabilities/QuirksCapability"); +const ValetudoSelectionPreset = require("../../entities/core/ValetudoSelectionPreset"); + +class DreameS10PlusValetudoRobot extends DreameGen2LidarValetudoRobot { + + /** + * + * @param {object} options + * @param {import("../../Configuration")} options.config + * @param {import("../../ValetudoEventStore")} options.valetudoEventStore + */ + constructor(options) { + super( + Object.assign( + {}, + { + detailedAttachmentReport: true, + }, + options, + ) + ); + + const QuirkFactory = new DreameQuirkFactory({ + robot: this + }); + + this.registerCapability(new capabilities.DreameWaterUsageControlCapability({ + robot: this, + presets: Object.keys(DreameValetudoRobot.WATER_GRADES).map(k => { + return new ValetudoSelectionPreset({name: k, value: DreameValetudoRobot.WATER_GRADES[k]}); + }), + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.WATER_USAGE.PIID + })); + + this.registerCapability(new capabilities.DreameZoneCleaningCapability({ + robot: this, + miot_actions: { + start: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.ACTIONS.START.AIID + } + }, + miot_properties: { + mode: { + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MODE.PIID + }, + additionalCleanupParameters: { + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.ADDITIONAL_CLEANUP_PROPERTIES.PIID + } + }, + zoneCleaningModeId: 19, + maxZoneCount: 4 + })); + + this.registerCapability(new capabilities.DreameConsumableMonitoringCapability({ + robot: this, + miot_properties: { + main_brush: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAIN_BRUSH.SIID, + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAIN_BRUSH.PROPERTIES.TIME_LEFT.PIID + }, + side_brush: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.SIDE_BRUSH.SIID, + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.SIDE_BRUSH.PROPERTIES.TIME_LEFT.PIID + }, + filter: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.FILTER.SIID, + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.FILTER.PROPERTIES.TIME_LEFT.PIID + }, + sensor: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.SENSOR.SIID, + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.SENSOR.PROPERTIES.TIME_LEFT.PIID + }, + mop: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.MOP.SIID, + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.MOP.PROPERTIES.TIME_LEFT.PIID + } + }, + miot_actions: { + reset_main_brush: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAIN_BRUSH.SIID, + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.MAIN_BRUSH.ACTIONS.RESET.AIID + }, + reset_side_brush: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.SIDE_BRUSH.SIID, + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.SIDE_BRUSH.ACTIONS.RESET.AIID + }, + reset_filter: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.FILTER.SIID, + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.FILTER.ACTIONS.RESET.AIID + }, + reset_sensor: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.SENSOR.SIID, + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.SENSOR.ACTIONS.RESET.AIID + }, + reset_mop: { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.MOP.SIID, + aiid: DreameGen2ValetudoRobot.MIOT_SERVICES.MOP.ACTIONS.RESET.AIID + } + }, + })); + + this.registerCapability(new capabilities.DreameOperationModeControlCapability({ + robot: this, + presets: Object.keys(this.operationModes).map(k => { + return new ValetudoSelectionPreset({name: k, value: this.operationModes[k]}); + }), + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID + })); + + this.registerCapability(new capabilities.DreameCarpetSensorModeControlCapability({ + robot: this, + liftSupported: false + })); + + + [ + capabilities.DreameCarpetModeControlCapability, + capabilities.DreameKeyLockCapability, + capabilities.DreameLineLaserObstacleAvoidanceControlCapability + ].forEach(capability => { + this.registerCapability(new capability({robot: this})); + }); + + this.registerCapability(new QuirksCapability({ + robot: this, + quirks: [ + QuirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.CARPET_MODE_SENSITIVITY), + QuirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.TIGHT_MOP_PATTERN), + ] + })); + + this.state.upsertFirstMatchingAttribute(new entities.state.attributes.DockStatusStateAttribute({ + value: entities.state.attributes.DockStatusStateAttribute.VALUE.IDLE + })); + + this.state.upsertFirstMatchingAttribute(new entities.state.attributes.AttachmentStateAttribute({ + type: entities.state.attributes.AttachmentStateAttribute.TYPE.MOP, + attached: false + })); + } + + getStatePropertiesToPoll() { + const superProps = super.getStatePropertiesToPoll(); + + return [ + ...superProps, + { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_STATUS.PIID + }, + { + siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID, + piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID + } + ]; + } + + + getModelName() { + return "S10+"; + } + + getCloudSecretFromFS() { + return fs.readFileSync("/mnt/private/ULI/factory/key.txt"); + } + + + static IMPLEMENTATION_AUTO_DETECTION_HANDLER() { + const deviceConf = MiioValetudoRobot.READ_DEVICE_CONF(DreameValetudoRobot.DEVICE_CONF_PATH); + + return !!(deviceConf && deviceConf.model === "dreame.vacuum.r2211o"); + } +} + + +module.exports = DreameS10PlusValetudoRobot; diff --git a/backend/lib/robots/dreame/index.js b/backend/lib/robots/dreame/index.js index 0ecb743d784..5992aefd07a 100644 --- a/backend/lib/robots/dreame/index.js +++ b/backend/lib/robots/dreame/index.js @@ -15,6 +15,7 @@ module.exports = { "DreameP2148ValetudoRobot": require("./DreameP2148ValetudoRobot"), "DreameP2149ValetudoRobot": require("./DreameP2149ValetudoRobot"), "DreameP2150ValetudoRobot": require("./DreameP2150ValetudoRobot"), + "DreameS10PlusValetudoRobot": require("./DreameS10PlusValetudoRobot"), "DreameW10ProValetudoRobot": require("./DreameW10ProValetudoRobot"), "DreameW10ValetudoRobot": require("./DreameW10ValetudoRobot"), "DreameX10PlusValetudoRobot": require("./DreameX10PlusValetudoRobot"), diff --git a/util/generate_robot_docs.js b/util/generate_robot_docs.js index db2717ffcdc..f21800587e6 100644 --- a/util/generate_robot_docs.js +++ b/util/generate_robot_docs.js @@ -62,6 +62,7 @@ const HIDDEN_IMPLEMENTATIONS = [ "RoborockS6MaxVValetudoRobot", "DreameP2149ValetudoRobot", "DreameL10SProValetudoRobot", + "DreameS10PlusValetudoRobot", "DreameL10UltraValetudoRobot", "DreameD9ProPlusValetudoRobot", ];