mirror of
https://github.com/Hypfer/Valetudo.git
synced 2025-10-26 11:27:27 +00:00
feat(vendor.dreame): Add support for the STYTJO6ZHM
This commit is contained in:
parent
deca9e8bf3
commit
519c5b4a43
@ -3,6 +3,7 @@ const DreameGen2LidarValetudoRobot = require("./DreameGen2LidarValetudoRobot");
|
||||
const DreameGen2ValetudoRobot = require("./DreameGen2ValetudoRobot");
|
||||
const DreameValetudoRobot = require("./DreameValetudoRobot");
|
||||
const MiioValetudoRobot = require("../MiioValetudoRobot");
|
||||
const ValetudoSelectionPreset = require("../../entities/core/ValetudoSelectionPreset");
|
||||
|
||||
class DreameD9ProValetudoRobot extends DreameGen2LidarValetudoRobot {
|
||||
/**
|
||||
@ -14,6 +15,21 @@ class DreameD9ProValetudoRobot extends DreameGen2LidarValetudoRobot {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.registerCapability(new capabilities.DreameCarpetModeControlCapability({
|
||||
robot: this,
|
||||
siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.CARPET_MODE.PIID
|
||||
}));
|
||||
|
||||
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.DreameConsumableMonitoringCapability({
|
||||
robot: this,
|
||||
miot_properties: {
|
||||
|
||||
@ -3,6 +3,7 @@ const DreameGen2LidarValetudoRobot = require("./DreameGen2LidarValetudoRobot");
|
||||
const DreameGen2ValetudoRobot = require("./DreameGen2ValetudoRobot");
|
||||
const DreameValetudoRobot = require("./DreameValetudoRobot");
|
||||
const MiioValetudoRobot = require("../MiioValetudoRobot");
|
||||
const ValetudoSelectionPreset = require("../../entities/core/ValetudoSelectionPreset");
|
||||
|
||||
class DreameD9ValetudoRobot extends DreameGen2LidarValetudoRobot {
|
||||
/**
|
||||
@ -14,6 +15,21 @@ class DreameD9ValetudoRobot extends DreameGen2LidarValetudoRobot {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.registerCapability(new capabilities.DreameCarpetModeControlCapability({
|
||||
robot: this,
|
||||
siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.CARPET_MODE.PIID
|
||||
}));
|
||||
|
||||
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.DreameConsumableMonitoringCapability({
|
||||
robot: this,
|
||||
miot_properties: {
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
const DreameGen2ValetudoRobot = require("./DreameGen2ValetudoRobot");
|
||||
|
||||
const capabilities = require("./capabilities");
|
||||
const DreameValetudoRobot = require("./DreameValetudoRobot");
|
||||
const ValetudoSelectionPreset = require("../../entities/core/ValetudoSelectionPreset");
|
||||
|
||||
|
||||
class DreameGen2VSlamValetudoRobot extends DreameGen2ValetudoRobot {
|
||||
constructor(options) {
|
||||
@ -12,6 +15,21 @@ class DreameGen2VSlamValetudoRobot extends DreameGen2ValetudoRobot {
|
||||
siid: DreameGen2ValetudoRobot.MIOT_SERVICES.PERSISTENT_MAPS.SIID,
|
||||
piid: DreameGen2ValetudoRobot.MIOT_SERVICES.PERSISTENT_MAPS.PROPERTIES.ENABLED.PIID
|
||||
}));
|
||||
|
||||
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.DreameCarpetModeControlCapability({
|
||||
robot: this,
|
||||
siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.CARPET_MODE.PIID
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -37,6 +37,15 @@ class DreameGen2ValetudoRobot extends DreameValetudoRobot {
|
||||
)
|
||||
);
|
||||
|
||||
/** @type {Array<{siid: number, piid: number, did: number}>} */
|
||||
this.statePropertiesToPoll = this.getStatePropertiesToPoll().map(e => {
|
||||
return {
|
||||
siid: e.siid,
|
||||
piid: e.piid,
|
||||
did: this.deviceId
|
||||
};
|
||||
});
|
||||
|
||||
this.lastMapPoll = new Date(0);
|
||||
|
||||
this.mode = 0; //Idle
|
||||
@ -75,15 +84,6 @@ class DreameGen2ValetudoRobot extends DreameValetudoRobot {
|
||||
piid: MIOT_SERVICES.VACUUM_2.PROPERTIES.FAN_SPEED.PIID
|
||||
}));
|
||||
|
||||
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: MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: MIOT_SERVICES.VACUUM_2.PROPERTIES.WATER_USAGE.PIID
|
||||
}));
|
||||
|
||||
this.registerCapability(new capabilities.DreameLocateCapability({
|
||||
robot: this,
|
||||
siid: MIOT_SERVICES.AUDIO.SIID,
|
||||
@ -225,12 +225,6 @@ class DreameGen2ValetudoRobot extends DreameValetudoRobot {
|
||||
install_voicepack_piid: MIOT_SERVICES.AUDIO.PROPERTIES.INSTALL_VOICEPACK.PIID
|
||||
}));
|
||||
|
||||
this.registerCapability(new capabilities.DreameCarpetModeControlCapability({
|
||||
robot: this,
|
||||
siid: MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: MIOT_SERVICES.VACUUM_2.PROPERTIES.CARPET_MODE.PIID
|
||||
}));
|
||||
|
||||
this.registerCapability(new capabilities.DreamePendingMapChangeHandlingCapability({
|
||||
robot: this,
|
||||
miot_actions: {
|
||||
@ -349,6 +343,7 @@ class DreameGen2ValetudoRobot extends DreameValetudoRobot {
|
||||
case MIOT_SERVICES.SIDE_BRUSH.SIID:
|
||||
case MIOT_SERVICES.FILTER.SIID:
|
||||
case MIOT_SERVICES.SENSOR.SIID:
|
||||
case MIOT_SERVICES.MOP.SIID:
|
||||
this.parseAndUpdateState([e]);
|
||||
break;
|
||||
case MIOT_SERVICES.DEVICE.SIID:
|
||||
@ -390,8 +385,13 @@ class DreameGen2ValetudoRobot extends DreameValetudoRobot {
|
||||
return false;
|
||||
}
|
||||
|
||||
async pollState() {
|
||||
const response = await this.sendCommand("get_properties", [
|
||||
/**
|
||||
* May be extended by children
|
||||
*
|
||||
* @return {Array<{piid: number, siid: number}>}
|
||||
*/
|
||||
getStatePropertiesToPoll() {
|
||||
return [
|
||||
{
|
||||
siid: MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: MIOT_SERVICES.VACUUM_2.PROPERTIES.MODE.PIID
|
||||
@ -424,11 +424,14 @@ class DreameGen2ValetudoRobot extends DreameValetudoRobot {
|
||||
siid: MIOT_SERVICES.BATTERY.SIID,
|
||||
piid: MIOT_SERVICES.BATTERY.PROPERTIES.CHARGING.PIID
|
||||
}
|
||||
].map(e => {
|
||||
e.did = this.deviceId;
|
||||
];
|
||||
}
|
||||
|
||||
return e;
|
||||
}));
|
||||
async pollState() {
|
||||
const response = await this.sendCommand(
|
||||
"get_properties",
|
||||
this.statePropertiesToPoll
|
||||
);
|
||||
|
||||
if (response) {
|
||||
this.parseAndUpdateState(response);
|
||||
@ -520,6 +523,7 @@ class DreameGen2ValetudoRobot extends DreameValetudoRobot {
|
||||
case MIOT_SERVICES.VACUUM_2.PROPERTIES.CARPET_MODE.PIID:
|
||||
case MIOT_SERVICES.VACUUM_2.PROPERTIES.KEY_LOCK.PIID:
|
||||
case MIOT_SERVICES.VACUUM_2.PROPERTIES.OBSTACLE_AVOIDANCE.PIID:
|
||||
case MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_STATE.PIID:
|
||||
//ignored for now
|
||||
break;
|
||||
|
||||
@ -552,6 +556,7 @@ class DreameGen2ValetudoRobot extends DreameValetudoRobot {
|
||||
case MIOT_SERVICES.SIDE_BRUSH.SIID:
|
||||
case MIOT_SERVICES.FILTER.SIID:
|
||||
case MIOT_SERVICES.SENSOR.SIID:
|
||||
case MIOT_SERVICES.MOP.SIID:
|
||||
if (this.capabilities[ConsumableMonitoringCapability.TYPE]) {
|
||||
this.capabilities[ConsumableMonitoringCapability.TYPE].parseConsumablesMessage(elem);
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ const DreameQuirkFactory = require("./DreameQuirkFactory");
|
||||
const DreameValetudoRobot = require("./DreameValetudoRobot");
|
||||
const MiioValetudoRobot = require("../MiioValetudoRobot");
|
||||
const QuirksCapability = require("../../core/capabilities/QuirksCapability");
|
||||
const ValetudoSelectionPreset = require("../../entities/core/ValetudoSelectionPreset");
|
||||
|
||||
class DreameL10ProValetudoRobot extends DreameGen2LidarValetudoRobot {
|
||||
/**
|
||||
@ -20,6 +21,21 @@ class DreameL10ProValetudoRobot extends DreameGen2LidarValetudoRobot {
|
||||
robot: this
|
||||
});
|
||||
|
||||
this.registerCapability(new capabilities.DreameCarpetModeControlCapability({
|
||||
robot: this,
|
||||
siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.CARPET_MODE.PIID
|
||||
}));
|
||||
|
||||
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.DreameConsumableMonitoringCapability({
|
||||
robot: this,
|
||||
miot_properties: {
|
||||
|
||||
@ -310,6 +310,12 @@ module.exports = {
|
||||
OBSTACLE_AVOIDANCE: {
|
||||
PIID: 21
|
||||
},
|
||||
MOP_DOCK_SETTINGS: {
|
||||
PIID: 23
|
||||
},
|
||||
MOP_DOCK_STATE: {
|
||||
PIID: 25
|
||||
},
|
||||
KEY_LOCK: {
|
||||
PIID: 27
|
||||
},
|
||||
@ -448,6 +454,22 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
},
|
||||
MOP: {
|
||||
SIID: 18,
|
||||
PROPERTIES: {
|
||||
TIME_LEFT: { //Hours
|
||||
PIID: 2
|
||||
},
|
||||
PERCENT_LEFT: {
|
||||
PIID: 1
|
||||
}
|
||||
},
|
||||
ACTIONS: {
|
||||
RESET: {
|
||||
AIID: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
MAP: {
|
||||
SIID: 6,
|
||||
PROPERTIES: {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
const DreameMiotHelper = require("./DreameMiotHelper");
|
||||
const DreameMiotServices = require("./DreameMiotServices");
|
||||
const DreameUtils = require("./DreameUtils");
|
||||
const Quirk = require("../../core/Quirk");
|
||||
|
||||
class DreameQuirkFactory {
|
||||
@ -198,6 +199,124 @@ class DreameQuirkFactory {
|
||||
);
|
||||
}
|
||||
});
|
||||
case DreameQuirkFactory.KNOWN_QUIRKS.MOP_ONLY_MODE:
|
||||
return new Quirk({
|
||||
id: id,
|
||||
title: "Mop Only",
|
||||
description: "Disable the vacuum functionality when the mop pads are attached.",
|
||||
options: ["on", "off"],
|
||||
getter: async () => {
|
||||
const res = await this.helper.readProperty(
|
||||
DreameMiotServices["GEN2"].VACUUM_2.SIID,
|
||||
DreameMiotServices["GEN2"].VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID
|
||||
);
|
||||
|
||||
const deserializedResponse = DreameUtils.DESERIALIZE_MOP_DOCK_SETTINGS(res);
|
||||
|
||||
switch (deserializedResponse.operationMode) {
|
||||
case 1:
|
||||
return "on";
|
||||
case 0:
|
||||
return "off";
|
||||
default:
|
||||
throw new Error(`Received invalid value ${deserializedResponse.operationMode}`);
|
||||
}
|
||||
},
|
||||
setter: async (value) => {
|
||||
let val;
|
||||
|
||||
switch (value) {
|
||||
case "on":
|
||||
val = 1;
|
||||
break;
|
||||
case "off":
|
||||
val = 0;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Received invalid value ${value}`);
|
||||
}
|
||||
|
||||
const res = await this.helper.readProperty(
|
||||
DreameMiotServices["GEN2"].VACUUM_2.SIID,
|
||||
DreameMiotServices["GEN2"].VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID
|
||||
);
|
||||
const deserializedResponse = DreameUtils.DESERIALIZE_MOP_DOCK_SETTINGS(res);
|
||||
|
||||
return this.helper.writeProperty(
|
||||
DreameMiotServices["GEN2"].VACUUM_2.SIID,
|
||||
DreameMiotServices["GEN2"].VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID,
|
||||
DreameUtils.SERIALIZE_MOP_DOCK_SETTINGS(
|
||||
deserializedResponse.waterGrade,
|
||||
deserializedResponse.padCleaningFrequency,
|
||||
val
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
case DreameQuirkFactory.KNOWN_QUIRKS.MOP_CLEANING_FREQUENCY:
|
||||
return new Quirk({
|
||||
id: id,
|
||||
title: "Mop Cleaning Frequency",
|
||||
description: "Determine how often the robot should clean and re-wet its mopping pads during a cleanup.",
|
||||
options: ["every_segment", "every_5_m2", "every_10_m2", "every_15_m2"],
|
||||
getter: async () => {
|
||||
const res = await this.helper.readProperty(
|
||||
DreameMiotServices["GEN2"].VACUUM_2.SIID,
|
||||
DreameMiotServices["GEN2"].VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID
|
||||
);
|
||||
|
||||
const deserializedResponse = DreameUtils.DESERIALIZE_MOP_DOCK_SETTINGS(res);
|
||||
|
||||
switch (deserializedResponse.padCleaningFrequency) {
|
||||
case 0:
|
||||
return "every_segment";
|
||||
case 5:
|
||||
return "every_5_m2";
|
||||
case 10:
|
||||
return "every_10_m2";
|
||||
case 15:
|
||||
return "every_15_m2";
|
||||
default:
|
||||
throw new Error(`Received invalid value ${deserializedResponse.operationMode}`);
|
||||
}
|
||||
},
|
||||
setter: async (value) => {
|
||||
let val;
|
||||
|
||||
switch (value) {
|
||||
case "every_segment":
|
||||
val = 0;
|
||||
break;
|
||||
case "every_5_m2":
|
||||
val = 5;
|
||||
break;
|
||||
case "every_10_m2":
|
||||
val = 10;
|
||||
break;
|
||||
case "every_15_m2":
|
||||
val = 15;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Received invalid value ${value}`);
|
||||
}
|
||||
|
||||
const res = await this.helper.readProperty(
|
||||
DreameMiotServices["GEN2"].VACUUM_2.SIID,
|
||||
DreameMiotServices["GEN2"].VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID
|
||||
);
|
||||
const deserializedResponse = DreameUtils.DESERIALIZE_MOP_DOCK_SETTINGS(res);
|
||||
|
||||
return this.helper.writeProperty(
|
||||
DreameMiotServices["GEN2"].VACUUM_2.SIID,
|
||||
DreameMiotServices["GEN2"].VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID,
|
||||
DreameUtils.SERIALIZE_MOP_DOCK_SETTINGS(
|
||||
deserializedResponse.waterGrade,
|
||||
val,
|
||||
deserializedResponse.operationMode
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
default:
|
||||
throw new Error(`There's no quirk with id ${id}`);
|
||||
}
|
||||
@ -208,7 +327,9 @@ DreameQuirkFactory.KNOWN_QUIRKS = {
|
||||
CARPET_MODE_SENSITIVITY: "f8cb91ab-a47a-445f-b300-0aac0d4937c0",
|
||||
TIGHT_MOP_PATTERN: "8471c118-f1e1-4866-ad2e-3c11865a5ba8",
|
||||
AUTO_EMPTY_INTERVAL: "d38118f2-fb5d-4ed9-b668-262db15e5269",
|
||||
OBSTACLE_AVOIDANCE: "4e386a76-b5f9-4f12-b04e-b8539a507163"
|
||||
OBSTACLE_AVOIDANCE: "4e386a76-b5f9-4f12-b04e-b8539a507163",
|
||||
MOP_ONLY_MODE: "6afbb882-c4c4-4672-b008-887454e6e0d1",
|
||||
MOP_CLEANING_FREQUENCY: "a6709b18-57af-4e11-8b4c-8ae33147ab34"
|
||||
};
|
||||
|
||||
module.exports = DreameQuirkFactory;
|
||||
|
||||
186
backend/lib/robots/dreame/DreameSTYTJO6ZHMValetudoRobot.js
Normal file
186
backend/lib/robots/dreame/DreameSTYTJO6ZHMValetudoRobot.js
Normal file
@ -0,0 +1,186 @@
|
||||
const capabilities = require("./capabilities");
|
||||
const DreameGen2LidarValetudoRobot = require("./DreameGen2LidarValetudoRobot");
|
||||
const DreameGen2ValetudoRobot = require("./DreameGen2ValetudoRobot");
|
||||
const DreameQuirkFactory = require("./DreameQuirkFactory");
|
||||
const DreameValetudoRobot = require("./DreameValetudoRobot");
|
||||
const MiioValetudoRobot = require("../MiioValetudoRobot");
|
||||
const QuirksCapability = require("../../core/capabilities/QuirksCapability");
|
||||
const ValetudoSelectionPreset = require("../../entities/core/ValetudoSelectionPreset");
|
||||
|
||||
const DreameUtils = require("./DreameUtils");
|
||||
const entities = require("../../entities");
|
||||
const Logger = require("../../Logger");
|
||||
const stateAttrs = entities.state.attributes;
|
||||
|
||||
const WATER_GRADES = {
|
||||
[stateAttrs.PresetSelectionStateAttribute.INTENSITY.LOW]: 1,
|
||||
[stateAttrs.PresetSelectionStateAttribute.INTENSITY.MEDIUM]: 2,
|
||||
[stateAttrs.PresetSelectionStateAttribute.INTENSITY.HIGH]: 3,
|
||||
};
|
||||
|
||||
class DreameSTYTJO6ZHMValetudoRobot extends DreameGen2LidarValetudoRobot {
|
||||
/**
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {import("../../Configuration")} options.config
|
||||
* @param {import("../../ValetudoEventStore")} options.valetudoEventStore
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
const QuirkFactory = new DreameQuirkFactory({
|
||||
robot: this
|
||||
});
|
||||
|
||||
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.DreameKeyLockCapability({
|
||||
robot: this,
|
||||
siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.KEY_LOCK.PIID
|
||||
}));
|
||||
|
||||
this.registerCapability(new capabilities.DreameMopDockWaterUsageControlCapability({
|
||||
robot: this,
|
||||
presets: Object.keys(WATER_GRADES).map(k => {
|
||||
return new ValetudoSelectionPreset({name: k, value: WATER_GRADES[k]});
|
||||
}),
|
||||
siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID
|
||||
}));
|
||||
|
||||
this.registerCapability(new QuirksCapability({
|
||||
robot: this,
|
||||
quirks: [
|
||||
QuirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.MOP_ONLY_MODE),
|
||||
QuirkFactory.getQuirk(DreameQuirkFactory.KNOWN_QUIRKS.MOP_CLEANING_FREQUENCY)
|
||||
]
|
||||
}));
|
||||
}
|
||||
|
||||
getStatePropertiesToPoll() {
|
||||
const superProps = super.getStatePropertiesToPoll();
|
||||
|
||||
return [
|
||||
// We don't have to poll the water usage piid as it doesn't control anything on this robot
|
||||
...superProps.filter(e => {
|
||||
return !(
|
||||
e.siid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID &&
|
||||
e.piid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.WATER_USAGE.PIID
|
||||
);
|
||||
}),
|
||||
|
||||
{
|
||||
siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
parseAndUpdateState(data) {
|
||||
if (!Array.isArray(data)) {
|
||||
Logger.error("Received non-array state", data);
|
||||
return;
|
||||
}
|
||||
|
||||
data.forEach(elem => {
|
||||
switch (elem.siid) {
|
||||
case DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID: {
|
||||
switch (elem.piid) {
|
||||
case DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID: {
|
||||
const deserializedValue = DreameUtils.DESERIALIZE_MOP_DOCK_SETTINGS(elem.value);
|
||||
|
||||
let matchingWaterGrade = Object.keys(WATER_GRADES).find(key => {
|
||||
return WATER_GRADES[key] === deserializedValue.waterGrade;
|
||||
});
|
||||
|
||||
this.state.upsertFirstMatchingAttribute(new stateAttrs.PresetSelectionStateAttribute({
|
||||
metaData: {
|
||||
rawValue: elem.value
|
||||
},
|
||||
type: stateAttrs.PresetSelectionStateAttribute.TYPE.WATER_GRADE,
|
||||
value: matchingWaterGrade
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// This filters out both the regular water-grade piid and the mopDock special one as otherwise those would confuse the state
|
||||
return super.parseAndUpdateState(data.filter(e => {
|
||||
return (
|
||||
!(
|
||||
e.siid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID &&
|
||||
e.piid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.WATER_USAGE.PIID
|
||||
) &&
|
||||
!(
|
||||
e.siid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID &&
|
||||
e.piid === DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.MOP_DOCK_SETTINGS.PIID
|
||||
)
|
||||
);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
getModelName() {
|
||||
return "STYTJO6ZHM";
|
||||
}
|
||||
|
||||
static IMPLEMENTATION_AUTO_DETECTION_HANDLER() {
|
||||
const deviceConf = MiioValetudoRobot.READ_DEVICE_CONF(DreameValetudoRobot.DEVICE_CONF_PATH);
|
||||
|
||||
return !!(deviceConf && deviceConf.model === "dreame.vacuum.p2149o");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = DreameSTYTJO6ZHMValetudoRobot;
|
||||
38
backend/lib/robots/dreame/DreameUtils.js
Normal file
38
backend/lib/robots/dreame/DreameUtils.js
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
class DreameUtils {
|
||||
/**
|
||||
*
|
||||
* @param {number} input
|
||||
* @return {{padCleaningFrequency: number, operationMode: number, waterGrade: number}}
|
||||
*/
|
||||
static DESERIALIZE_MOP_DOCK_SETTINGS(input) {
|
||||
const padded = input.toString(2).padStart(24, "0");
|
||||
|
||||
return {
|
||||
waterGrade: parseInt(padded.substring(0,8),2),
|
||||
padCleaningFrequency: parseInt(padded.substring(8,16),2),
|
||||
operationMode: parseInt(padded.substring(16,24),2),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} waterGrade
|
||||
* @param {number} padCleaningFrequency
|
||||
* @param {number} operationMode
|
||||
* @return {number}
|
||||
*/
|
||||
static SERIALIZE_MOP_DOCK_SETTINGS(waterGrade, padCleaningFrequency, operationMode) {
|
||||
const waterGradeInt8Str = waterGrade.toString(2).padStart(8, "0");
|
||||
const padCleaningFrequencyInt8Str = padCleaningFrequency.toString(2).padStart(8, "0");
|
||||
const operationModeInt8Str = operationMode.toString(2).padStart(8, "0");
|
||||
|
||||
|
||||
return parseInt(
|
||||
`${waterGradeInt8Str}${padCleaningFrequencyInt8Str}${operationModeInt8Str}`,
|
||||
2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DreameUtils;
|
||||
@ -5,6 +5,7 @@ const DreameQuirkFactory = require("./DreameQuirkFactory");
|
||||
const DreameValetudoRobot = require("./DreameValetudoRobot");
|
||||
const MiioValetudoRobot = require("../MiioValetudoRobot");
|
||||
const QuirksCapability = require("../../core/capabilities/QuirksCapability");
|
||||
const ValetudoSelectionPreset = require("../../entities/core/ValetudoSelectionPreset");
|
||||
|
||||
class DreameZ10ProValetudoRobot extends DreameGen2LidarValetudoRobot {
|
||||
|
||||
@ -21,6 +22,21 @@ class DreameZ10ProValetudoRobot extends DreameGen2LidarValetudoRobot {
|
||||
robot: this
|
||||
});
|
||||
|
||||
this.registerCapability(new capabilities.DreameCarpetModeControlCapability({
|
||||
robot: this,
|
||||
siid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.SIID,
|
||||
piid: DreameGen2ValetudoRobot.MIOT_SERVICES.VACUUM_2.PROPERTIES.CARPET_MODE.PIID
|
||||
}));
|
||||
|
||||
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.DreameConsumableMonitoringCapability({
|
||||
robot: this,
|
||||
miot_properties: {
|
||||
|
||||
@ -30,6 +30,10 @@ class DreameConsumableMonitoringCapability extends ConsumableMonitoringCapabilit
|
||||
* @param {number} options.miot_actions.reset_sensor.siid
|
||||
* @param {number} options.miot_actions.reset_sensor.aiid
|
||||
*
|
||||
* @param {object} [options.miot_actions.reset_mop]
|
||||
* @param {number} options.miot_actions.reset_mop.siid
|
||||
* @param {number} options.miot_actions.reset_mop.aiid
|
||||
*
|
||||
*
|
||||
* @param {object} options.miot_properties
|
||||
* @param {object} options.miot_properties.main_brush
|
||||
@ -47,6 +51,10 @@ class DreameConsumableMonitoringCapability extends ConsumableMonitoringCapabilit
|
||||
* @param {object} [options.miot_properties.sensor]
|
||||
* @param {number} options.miot_properties.sensor.siid
|
||||
* @param {number} options.miot_properties.sensor.piid
|
||||
*
|
||||
* @param {object} [options.miot_properties.mop]
|
||||
* @param {number} options.miot_properties.mop.siid
|
||||
* @param {number} options.miot_properties.mop.piid
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
@ -73,6 +81,10 @@ class DreameConsumableMonitoringCapability extends ConsumableMonitoringCapabilit
|
||||
props.push(this.miot_properties.sensor);
|
||||
}
|
||||
|
||||
if (this.miot_properties.mop) {
|
||||
props.push(this.miot_properties.mop);
|
||||
}
|
||||
|
||||
|
||||
const response = await this.robot.sendCommand("get_properties", props.map(e => {
|
||||
return Object.assign({}, e, {did: this.robot.deviceId});
|
||||
@ -128,6 +140,15 @@ class DreameConsumableMonitoringCapability extends ConsumableMonitoringCapabilit
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ConsumableStateAttribute.TYPE.MOP:
|
||||
if (this.miot_actions.reset_mop) {
|
||||
switch (subType) {
|
||||
case ConsumableStateAttribute.SUB_TYPE.ALL:
|
||||
payload = this.miot_actions.reset_mop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@ -203,8 +224,11 @@ class DreameConsumableMonitoringCapability extends ConsumableMonitoringCapabilit
|
||||
}
|
||||
|
||||
default:
|
||||
if (this.miot_properties.sensor) {
|
||||
if (msg.siid === this.miot_properties.sensor.siid && msg.piid === this.miot_properties.sensor.piid) {
|
||||
if (
|
||||
this.miot_properties.sensor &&
|
||||
msg.siid === this.miot_properties.sensor.siid
|
||||
) {
|
||||
if (msg.piid === this.miot_properties.sensor.piid) {
|
||||
consumable = new ConsumableStateAttribute({
|
||||
type: ConsumableStateAttribute.TYPE.SENSOR,
|
||||
subType: ConsumableStateAttribute.SUB_TYPE.ALL,
|
||||
@ -214,6 +238,20 @@ class DreameConsumableMonitoringCapability extends ConsumableMonitoringCapabilit
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (
|
||||
this.miot_properties.mop &&
|
||||
msg.siid === this.miot_properties.mop.siid
|
||||
) {
|
||||
if (msg.piid === this.miot_properties.mop.piid) {
|
||||
consumable = new ConsumableStateAttribute({
|
||||
type: ConsumableStateAttribute.TYPE.MOP,
|
||||
subType: ConsumableStateAttribute.SUB_TYPE.ALL,
|
||||
remaining: {
|
||||
value: Math.round(Math.max(0, msg.value * 60)),
|
||||
unit: ConsumableStateAttribute.UNITS.MINUTES
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
Logger.warn("Unhandled consumable update", msg);
|
||||
}
|
||||
@ -255,6 +293,16 @@ class DreameConsumableMonitoringCapability extends ConsumableMonitoringCapabilit
|
||||
);
|
||||
}
|
||||
|
||||
if (this.miot_properties.mop) {
|
||||
availableConsumables.push(
|
||||
{
|
||||
type: ConsumableStateAttribute.TYPE.MOP,
|
||||
subType: ConsumableStateAttribute.SUB_TYPE.ALL,
|
||||
unit: ConsumableStateAttribute.UNITS.MINUTES
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
availableConsumables: availableConsumables
|
||||
};
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
const DreameMiotHelper = require("../DreameMiotHelper");
|
||||
const DreameUtils = require("../DreameUtils");
|
||||
const WaterUsageControlCapability = require("../../../core/capabilities/WaterUsageControlCapability");
|
||||
|
||||
/**
|
||||
* @extends WaterUsageControlCapability<import("../DreameValetudoRobot")>
|
||||
*/
|
||||
class DreameMopDockWaterUsageControlCapability extends WaterUsageControlCapability {
|
||||
|
||||
/**
|
||||
* @param {object} options
|
||||
* @param {import("../DreameValetudoRobot")} options.robot
|
||||
* @param {Array<import("../../../entities/core/ValetudoSelectionPreset")>} options.presets
|
||||
*
|
||||
* @param {number} options.siid MIOT Service ID
|
||||
* @param {number} options.piid MIOT Property ID
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.siid = options.siid;
|
||||
this.piid = options.piid;
|
||||
|
||||
this.helper = new DreameMiotHelper({robot: this.robot});
|
||||
}
|
||||
/**
|
||||
* @param {string} preset
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async selectPreset(preset) {
|
||||
const matchedPreset = this.presets.find(p => {
|
||||
return p.name === preset;
|
||||
});
|
||||
|
||||
if (matchedPreset) {
|
||||
const res = await this.helper.readProperty(this.siid, this.piid);
|
||||
|
||||
const deserializedResponse = DreameUtils.DESERIALIZE_MOP_DOCK_SETTINGS(res);
|
||||
|
||||
return this.helper.writeProperty(
|
||||
this.siid,
|
||||
this.piid,
|
||||
DreameUtils.SERIALIZE_MOP_DOCK_SETTINGS(
|
||||
matchedPreset.value,
|
||||
deserializedResponse.padCleaningFrequency,
|
||||
deserializedResponse.operationMode
|
||||
)
|
||||
);
|
||||
} else {
|
||||
throw new Error("Invalid Preset");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = DreameMopDockWaterUsageControlCapability;
|
||||
@ -32,7 +32,7 @@ class DreameWaterUsageControlCapability extends WaterUsageControlCapability {
|
||||
});
|
||||
|
||||
if (matchedPreset) {
|
||||
await this.helper.writeProperty(this.siid, this.piid, matchedPreset.value);
|
||||
return this.helper.writeProperty(this.siid, this.piid, matchedPreset.value);
|
||||
} else {
|
||||
throw new Error("Invalid Preset");
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ module.exports = {
|
||||
DreameMapSegmentRenameCapability: require("./DreameMapSegmentRenameCapability"),
|
||||
DreameMapSegmentationCapability: require("./DreameMapSegmentationCapability"),
|
||||
DreameMappingPassCapability: require("./DreameMappingPassCapability"),
|
||||
DreameMopDockWaterUsageControlCapability: require("./DreameMopDockWaterUsageControlCapability"),
|
||||
DreamePendingMapChangeHandlingCapability: require("./DreamePendingMapChangeHandlingCapability"),
|
||||
DreamePersistentMapControlCapability: require("./DreamePersistentMapControlCapability"),
|
||||
DreameSpeakerTestCapability: require("./DreameSpeakerTestCapability"),
|
||||
@ -28,5 +29,5 @@ module.exports = {
|
||||
DreameTotalStatisticsCapability: require("./DreameTotalStatisticsCapability"),
|
||||
DreameVoicePackManagementCapability: require("./DreameVoicePackManagementCapability"),
|
||||
DreameWaterUsageControlCapability: require("./DreameWaterUsageControlCapability"),
|
||||
DreameZoneCleaningCapability: require("./DreameZoneCleaningCapability")
|
||||
DreameZoneCleaningCapability: require("./DreameZoneCleaningCapability"),
|
||||
};
|
||||
|
||||
@ -6,5 +6,6 @@ module.exports = {
|
||||
"DreameF9ValetudoRobot": require("./DreameF9ValetudoRobot"),
|
||||
"DreameL10ProValetudoRobot": require("./DreameL10ProValetudoRobot"),
|
||||
"DreameMovaZ500ValetudoRobot": require("./DreameMovaZ500ValetudoRobot"),
|
||||
"DreameSTYTJO6ZHMValetudoRobot": require("./DreameSTYTJO6ZHMValetudoRobot"),
|
||||
"DreameZ10ProValetudoRobot": require("./DreameZ10ProValetudoRobot")
|
||||
};
|
||||
|
||||
@ -259,7 +259,8 @@ function getModelDescription(vendor, model) {
|
||||
*/
|
||||
const HIDDEN_IMPLEMENTATIONS = [
|
||||
"RoborockS6MaxVValetudoRobot",
|
||||
"RoborockS7ValetudoRobot"
|
||||
"RoborockS7ValetudoRobot",
|
||||
"DreameSTYTJO6ZHMValetudoRobot"
|
||||
];
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user