diff --git a/backend/lib/robots/midea/MideaQuirkFactory.js b/backend/lib/robots/midea/MideaQuirkFactory.js index b076d1ba..1ca6154b 100644 --- a/backend/lib/robots/midea/MideaQuirkFactory.js +++ b/backend/lib/robots/midea/MideaQuirkFactory.js @@ -424,6 +424,51 @@ class MideaQuirkFactory { }).toHexString()); } }); + case MideaQuirkFactory.KNOWN_QUIRKS.STAIN_CLEANING: + return new Quirk({ + id: id, + title: "Stain Cleaning", + description: "When enabled, during a clean the robot will detect stains and spills and will exert special care. Note that due to optical similarities, this feature is mutually exclusive to the PetObstacleAvoidance.", + options: ["off", "on"], + getter: async () => { + const response = await this.robot.sendCommand(new MSmartPacket({ + messageType: MSmartPacket.MESSAGE_TYPE.ACTION, + payload: MSmartPacket.buildPayload(MSmartConst.ACTION.GET_STATUS) + }).toHexString()); + const parsedResponse = BEightParser.PARSE(response); + + if (parsedResponse instanceof MSmartStatusDTO) { + return parsedResponse.stain_clean_switch ? "on" : "off"; + } else { + throw new Error("Invalid response from robot"); + } + }, + setter: async (value) => { + let val; + + switch (value) { + case "off": + val = 0; + break; + case "on": + val = 1; + break; + default: + throw new Error(`Invalid stain cleaning value: ${value}`); + } + + await this.robot.sendCommand(new MSmartPacket({ + messageType: MSmartPacket.MESSAGE_TYPE.SETTING, + payload: MSmartPacket.buildPayload( + MSmartConst.SETTING.SET_VARIOUS_TOGGLES, + Buffer.from([ + 0x08, // Stain Cleaning + val + ]) + ) + }).toHexString()); + } + }); default: throw new Error(`There's no quirk with id ${id}`); } @@ -439,6 +484,7 @@ MideaQuirkFactory.KNOWN_QUIRKS = { CARPET_FIRST: "4b100fec-08d5-4227-9edf-eb0198d6ea20", DEEP_CARPET_CLEANING: "d2ad3f99-c1b0-4195-9a98-4f13bdb0f1e8", INCREASED_CARPET_AVOIDANCE: "f3ff1c65-9fe7-4312-b196-83ce91107fe8", + STAIN_CLEANING: "d4688a29-a6e4-43c2-ab3a-08ddae40655c", }; module.exports = MideaQuirkFactory; diff --git a/backend/lib/robots/midea/MideaValetudoRobot.js b/backend/lib/robots/midea/MideaValetudoRobot.js index 934a5344..70150259 100644 --- a/backend/lib/robots/midea/MideaValetudoRobot.js +++ b/backend/lib/robots/midea/MideaValetudoRobot.js @@ -148,6 +148,7 @@ class MideaValetudoRobot extends ValetudoRobot { capabilities.MideaMopDockMopWashTemperatureControlCapability, capabilities.MideaCarpetModeControlCapability, capabilities.MideaCarpetSensorModeControlCapability, + capabilities.MideaPetObstacleAvoidanceControlCapability, ].forEach(capability => { this.registerCapability(new capability({robot: this})); }); @@ -172,6 +173,7 @@ class MideaValetudoRobot extends ValetudoRobot { quirkFactory.getQuirk(MideaQuirkFactory.KNOWN_QUIRKS.CARPET_FIRST), quirkFactory.getQuirk(MideaQuirkFactory.KNOWN_QUIRKS.DEEP_CARPET_CLEANING), quirkFactory.getQuirk(MideaQuirkFactory.KNOWN_QUIRKS.INCREASED_CARPET_AVOIDANCE), + quirkFactory.getQuirk(MideaQuirkFactory.KNOWN_QUIRKS.STAIN_CLEANING), ] })); diff --git a/backend/lib/robots/midea/capabilities/MideaObstacleAvoidanceControlCapability.js b/backend/lib/robots/midea/capabilities/MideaObstacleAvoidanceControlCapability.js index 579a2c26..9d158e43 100644 --- a/backend/lib/robots/midea/capabilities/MideaObstacleAvoidanceControlCapability.js +++ b/backend/lib/robots/midea/capabilities/MideaObstacleAvoidanceControlCapability.js @@ -13,12 +13,10 @@ class MideaObstacleAvoidanceControlCapability extends ObstacleAvoidanceControlCa * @returns {Promise} */ async isEnabled() { - const packet = new MSmartPacket({ + const response = await this.robot.sendCommand(new MSmartPacket({ messageType: MSmartPacket.MESSAGE_TYPE.ACTION, payload: MSmartPacket.buildPayload(MSmartConst.ACTION.GET_STATUS) - }); - - const response = await this.robot.sendCommand(packet.toHexString()); + }).toHexString()); const parsedResponse = BEightParser.PARSE(response); if (parsedResponse instanceof MSmartStatusDTO) { @@ -32,12 +30,10 @@ class MideaObstacleAvoidanceControlCapability extends ObstacleAvoidanceControlCa * @returns {Promise} */ async enable() { - const statusPacket = new MSmartPacket({ + const response = await this.robot.sendCommand(new MSmartPacket({ messageType: MSmartPacket.MESSAGE_TYPE.ACTION, payload: MSmartPacket.buildPayload(MSmartConst.ACTION.GET_STATUS) - }); - - const response = await this.robot.sendCommand(statusPacket.toHexString()); + }).toHexString()); const status = BEightParser.PARSE(response); if (!(status instanceof MSmartStatusDTO)) { @@ -45,21 +41,19 @@ class MideaObstacleAvoidanceControlCapability extends ObstacleAvoidanceControlCa } if (status.ai_recognition_switch === false) { - const tosPacket = new MSmartPacket({ + await this.robot.sendCommand(new MSmartPacket({ messageType: MSmartPacket.MESSAGE_TYPE.SETTING, payload: MSmartPacket.buildPayload( MSmartConst.SETTING.SET_VARIOUS_TOGGLES, Buffer.from([ - 0x0f, // AI Recognition (ToS) + 0x0f, // AI Recognition 0x01 // true ]) ) - }); - - await this.robot.sendCommand(tosPacket.toHexString()); + }).toHexString()); } - const avoidancePacket = new MSmartPacket({ + await this.robot.sendCommand(new MSmartPacket({ messageType: MSmartPacket.MESSAGE_TYPE.SETTING, payload: MSmartPacket.buildPayload( MSmartConst.SETTING.SET_VARIOUS_TOGGLES, @@ -68,16 +62,14 @@ class MideaObstacleAvoidanceControlCapability extends ObstacleAvoidanceControlCa 0x01 // true ]) ) - }); - - await this.robot.sendCommand(avoidancePacket.toHexString()); + }).toHexString()); } /** * @returns {Promise} */ async disable() { - const packet = new MSmartPacket({ + await this.robot.sendCommand(new MSmartPacket({ messageType: MSmartPacket.MESSAGE_TYPE.SETTING, payload: MSmartPacket.buildPayload( MSmartConst.SETTING.SET_VARIOUS_TOGGLES, @@ -86,9 +78,7 @@ class MideaObstacleAvoidanceControlCapability extends ObstacleAvoidanceControlCa 0x00 // false ]) ) - }); - - await this.robot.sendCommand(packet.toHexString()); + }).toHexString()); } } diff --git a/backend/lib/robots/midea/capabilities/MideaObstacleImagesCapability.js b/backend/lib/robots/midea/capabilities/MideaObstacleImagesCapability.js index 69f3c472..7db39570 100644 --- a/backend/lib/robots/midea/capabilities/MideaObstacleImagesCapability.js +++ b/backend/lib/robots/midea/capabilities/MideaObstacleImagesCapability.js @@ -15,12 +15,10 @@ class MideaObstacleImagesCapability extends ObstacleImagesCapability { * @returns {Promise} */ async isEnabled() { - const packet = new MSmartPacket({ + const response = await this.robot.sendCommand(new MSmartPacket({ messageType: MSmartPacket.MESSAGE_TYPE.ACTION, payload: MSmartPacket.buildPayload(MSmartConst.ACTION.GET_STATUS) - }); - - const response = await this.robot.sendCommand(packet.toHexString()); + }).toHexString()); const parsedResponse = BEightParser.PARSE(response); if (parsedResponse instanceof MSmartStatusDTO) { @@ -34,7 +32,7 @@ class MideaObstacleImagesCapability extends ObstacleImagesCapability { * @returns {Promise} */ async enable() { - const packet = new MSmartPacket({ + await this.robot.sendCommand(new MSmartPacket({ messageType: MSmartPacket.MESSAGE_TYPE.SETTING, payload: MSmartPacket.buildPayload( MSmartConst.SETTING.SET_VARIOUS_TOGGLES, @@ -43,16 +41,14 @@ class MideaObstacleImagesCapability extends ObstacleImagesCapability { 0x01 // true ]) ) - }); - - await this.robot.sendCommand(packet.toHexString()); + }).toHexString()); } /** * @returns {Promise} */ async disable() { - const packet = new MSmartPacket({ + await this.robot.sendCommand(new MSmartPacket({ messageType: MSmartPacket.MESSAGE_TYPE.SETTING, payload: MSmartPacket.buildPayload( MSmartConst.SETTING.SET_VARIOUS_TOGGLES, @@ -61,9 +57,7 @@ class MideaObstacleImagesCapability extends ObstacleImagesCapability { 0x00 // false ]) ) - }); - - await this.robot.sendCommand(packet.toHexString()); + }).toHexString()); } /** diff --git a/backend/lib/robots/midea/capabilities/MideaPetObstacleAvoidanceControlCapability.js b/backend/lib/robots/midea/capabilities/MideaPetObstacleAvoidanceControlCapability.js new file mode 100644 index 00000000..f0e3c9ce --- /dev/null +++ b/backend/lib/robots/midea/capabilities/MideaPetObstacleAvoidanceControlCapability.js @@ -0,0 +1,62 @@ +const BEightParser = require("../../../msmart/BEightParser"); +const MSmartConst = require("../../../msmart/MSmartConst"); +const MSmartPacket = require("../../../msmart/MSmartPacket"); +const MSmartStatusDTO = require("../../../msmart/dtos/MSmartStatusDTO"); +const PetObstacleAvoidanceControlCapability = require("../../../core/capabilities/PetObstacleAvoidanceControlCapability"); + +/** + * @extends PetObstacleAvoidanceControlCapability + */ +class MideaPetObstacleAvoidanceControlCapability extends PetObstacleAvoidanceControlCapability { + + /** + * @returns {Promise} + */ + async isEnabled() { + const response = await this.robot.sendCommand(new MSmartPacket({ + messageType: MSmartPacket.MESSAGE_TYPE.ACTION, + payload: MSmartPacket.buildPayload(MSmartConst.ACTION.GET_STATUS) + }).toHexString()); + const parsedResponse = BEightParser.PARSE(response); + + if (parsedResponse instanceof MSmartStatusDTO) { + return parsedResponse.pet_mode_switch; + } else { + throw new Error("Invalid response from robot"); + } + } + + /** + * @returns {Promise} + */ + async enable() { + await this.robot.sendCommand(new MSmartPacket({ + messageType: MSmartPacket.MESSAGE_TYPE.SETTING, + payload: MSmartPacket.buildPayload( + MSmartConst.SETTING.SET_VARIOUS_TOGGLES, + Buffer.from([ + 0x0e, // Pet Mode + 0x01 // true + ]) + ) + }).toHexString()); + } + + /** + * @returns {Promise} + */ + async disable() { + await this.robot.sendCommand(new MSmartPacket({ + messageType: MSmartPacket.MESSAGE_TYPE.SETTING, + payload: MSmartPacket.buildPayload( + MSmartConst.SETTING.SET_VARIOUS_TOGGLES, + Buffer.from([ + 0x0e, // Pet mode + 0x00 // false + ]) + ) + }).toHexString()); + } +} + +module.exports = MideaPetObstacleAvoidanceControlCapability; diff --git a/backend/lib/robots/midea/capabilities/index.js b/backend/lib/robots/midea/capabilities/index.js index 56ecc175..c7aa6051 100644 --- a/backend/lib/robots/midea/capabilities/index.js +++ b/backend/lib/robots/midea/capabilities/index.js @@ -24,6 +24,7 @@ module.exports = { MideaObstacleAvoidanceControlCapability: require("./MideaObstacleAvoidanceControlCapability"), MideaObstacleImagesCapability: require("./MideaObstacleImagesCapability"), MideaOperationModeControlCapability: require("./MideaOperationModeControlCapability"), + MideaPetObstacleAvoidanceControlCapability: require("./MideaPetObstacleAvoidanceControlCapability"), MideaSpeakerTestCapability: require("./MideaSpeakerTestCapability"), MideaSpeakerVolumeControlCapability: require("./MideaSpeakerVolumeControlCapability"), MideaWaterUsageControlCapability: require("./MideaWaterUsageControlCapability"),