matterbridge-roborock-vacuum-plugin 1.0.7-rc03 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/behaviorFactory.js +2 -2
- package/dist/behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.js +56 -11
- package/dist/model/CleanModeSettings.js +5 -0
- package/dist/platform.js +10 -1
- package/dist/roborockCommunication/broadcast/messageProcessor.js +12 -7
- package/dist/roborockService.js +5 -2
- package/matterbridge-roborock-vacuum-plugin.config.json +1 -1
- package/matterbridge-roborock-vacuum-plugin.schema.json +118 -5
- package/package.json +1 -1
- package/src/behaviorFactory.ts +9 -2
- package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.test.ts +201 -0
- package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.ts +68 -12
- package/src/model/CleanModeSettings.ts +17 -0
- package/src/platform.ts +13 -1
- package/src/roborockCommunication/broadcast/messageProcessor.ts +16 -7
- package/src/roborockService.ts +9 -2
package/dist/behaviorFactory.js
CHANGED
|
@@ -3,11 +3,11 @@ import { setCommandHandlerA187 } from './behaviors/roborock.vacuum/QREVO_EDGE_5V
|
|
|
3
3
|
import { setDefaultCommandHandler } from './behaviors/roborock.vacuum/default/default.js';
|
|
4
4
|
import { DeviceModel } from './roborockCommunication/Zmodel/deviceModel.js';
|
|
5
5
|
import { setCommandHandlerA27 } from './behaviors/roborock.vacuum/S7_MAXV/a27.js';
|
|
6
|
-
export function configurateBehavior(model, duid, roborockService, logger) {
|
|
6
|
+
export function configurateBehavior(model, duid, roborockService, cleanModeSettings, logger) {
|
|
7
7
|
switch (model) {
|
|
8
8
|
case DeviceModel.QREVO_EDGE_5V1: {
|
|
9
9
|
const deviceHandler = new BehaviorDeviceGeneric(logger);
|
|
10
|
-
setCommandHandlerA187(duid, deviceHandler, logger, roborockService);
|
|
10
|
+
setCommandHandlerA187(duid, deviceHandler, logger, roborockService, cleanModeSettings);
|
|
11
11
|
return deviceHandler;
|
|
12
12
|
}
|
|
13
13
|
case DeviceModel.S7_MAXV: {
|
|
@@ -27,15 +27,16 @@ export var MopWaterFlowA187;
|
|
|
27
27
|
MopWaterFlowA187[MopWaterFlowA187["Medium"] = 202] = "Medium";
|
|
28
28
|
MopWaterFlowA187[MopWaterFlowA187["High"] = 203] = "High";
|
|
29
29
|
MopWaterFlowA187[MopWaterFlowA187["Custom"] = 204] = "Custom";
|
|
30
|
+
MopWaterFlowA187[MopWaterFlowA187["CustomizeWithDistanceOff"] = 207] = "CustomizeWithDistanceOff";
|
|
30
31
|
MopWaterFlowA187[MopWaterFlowA187["Smart"] = 209] = "Smart";
|
|
31
32
|
})(MopWaterFlowA187 || (MopWaterFlowA187 = {}));
|
|
32
33
|
export var MopRouteA187;
|
|
33
34
|
(function (MopRouteA187) {
|
|
34
|
-
MopRouteA187[MopRouteA187["Fast"] = 304] = "Fast";
|
|
35
35
|
MopRouteA187[MopRouteA187["Standard"] = 300] = "Standard";
|
|
36
36
|
MopRouteA187[MopRouteA187["Deep"] = 301] = "Deep";
|
|
37
37
|
MopRouteA187[MopRouteA187["Custom"] = 302] = "Custom";
|
|
38
38
|
MopRouteA187[MopRouteA187["DeepPlus"] = 303] = "DeepPlus";
|
|
39
|
+
MopRouteA187[MopRouteA187["Fast"] = 304] = "Fast";
|
|
39
40
|
MopRouteA187[MopRouteA187["Smart"] = 306] = "Smart";
|
|
40
41
|
})(MopRouteA187 || (MopRouteA187 = {}));
|
|
41
42
|
const RvcRunMode = {
|
|
@@ -51,13 +52,13 @@ const RvcCleanMode = {
|
|
|
51
52
|
[8]: 'Custom',
|
|
52
53
|
};
|
|
53
54
|
const CleanSetting = {
|
|
54
|
-
[4]: { suctionPower: 0, waterFlow: 0, mopRoute: MopRouteA187.Smart },
|
|
55
|
-
[5]: { suctionPower: VacuumSuctionPowerA187.Off, waterFlow: MopWaterFlowA187.Medium, mopRoute: MopRouteA187.Custom },
|
|
56
|
-
[6]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Off, mopRoute: MopRouteA187.Custom },
|
|
57
|
-
[7]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Medium, mopRoute: MopRouteA187.Custom },
|
|
58
|
-
[8]: { suctionPower: VacuumSuctionPowerA187.Custom, waterFlow: MopWaterFlowA187.Custom, mopRoute: MopRouteA187.Custom },
|
|
55
|
+
[4]: { suctionPower: 0, waterFlow: 0, distance_off: 0, mopRoute: MopRouteA187.Smart },
|
|
56
|
+
[5]: { suctionPower: VacuumSuctionPowerA187.Off, waterFlow: MopWaterFlowA187.Medium, distance_off: 0, mopRoute: MopRouteA187.Custom },
|
|
57
|
+
[6]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Off, distance_off: 0, mopRoute: MopRouteA187.Custom },
|
|
58
|
+
[7]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Medium, distance_off: 0, mopRoute: MopRouteA187.Custom },
|
|
59
|
+
[8]: { suctionPower: VacuumSuctionPowerA187.Custom, waterFlow: MopWaterFlowA187.Custom, distance_off: 0, mopRoute: MopRouteA187.Custom },
|
|
59
60
|
};
|
|
60
|
-
export function setCommandHandlerA187(duid, handler, logger, roborockService) {
|
|
61
|
+
export function setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings) {
|
|
61
62
|
handler.setCommandHandler('changeToMode', async (newMode) => {
|
|
62
63
|
const activity = RvcRunMode[newMode] || RvcCleanMode[newMode];
|
|
63
64
|
switch (activity) {
|
|
@@ -67,20 +68,64 @@ export function setCommandHandlerA187(duid, handler, logger, roborockService) {
|
|
|
67
68
|
return;
|
|
68
69
|
}
|
|
69
70
|
case 'Smart Plan':
|
|
70
|
-
case 'Mop':
|
|
71
|
-
case 'Vacuum':
|
|
72
|
-
case 'Vac & Mop':
|
|
73
71
|
case 'Custom': {
|
|
74
72
|
const setting = CleanSetting[newMode];
|
|
75
|
-
logger.notice(`BehaviorA187-ChangeCleanMode to: ${activity},
|
|
73
|
+
logger.notice(`BehaviorA187-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting)}`);
|
|
76
74
|
await roborockService.changeCleanMode(duid, setting);
|
|
77
75
|
return;
|
|
78
76
|
}
|
|
77
|
+
case 'Mop':
|
|
78
|
+
case 'Vacuum':
|
|
79
|
+
case 'Vac & Mop': {
|
|
80
|
+
const setting = cleanModeSettings ? getSettingFromCleanMode(activity, cleanModeSettings) : CleanSetting[newMode];
|
|
81
|
+
logger.notice(`BehaviorA187-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting ?? {})}`);
|
|
82
|
+
if (setting) {
|
|
83
|
+
await roborockService.changeCleanMode(duid, setting);
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
79
87
|
default:
|
|
80
88
|
logger.notice('BehaviorA187-changeToMode-Unknown: ', newMode);
|
|
81
89
|
return;
|
|
82
90
|
}
|
|
83
91
|
});
|
|
92
|
+
const getSettingFromCleanMode = (activity, cleanModeSettings) => {
|
|
93
|
+
switch (activity) {
|
|
94
|
+
case 'Mop': {
|
|
95
|
+
const mopSetting = cleanModeSettings?.mopping;
|
|
96
|
+
const waterFlow = MopWaterFlowA187[mopSetting?.waterFlowMode] ?? MopWaterFlowA187.Medium;
|
|
97
|
+
const distance_off = waterFlow == MopWaterFlowA187.CustomizeWithDistanceOff ? 210 - 5 * (mopSetting?.distanceOff ?? 25) : 0;
|
|
98
|
+
return {
|
|
99
|
+
suctionPower: VacuumSuctionPowerA187.Off,
|
|
100
|
+
waterFlow,
|
|
101
|
+
distance_off,
|
|
102
|
+
mopRoute: MopRouteA187[mopSetting?.mopRouteMode] ?? MopRouteA187.Standard,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
case 'Vacuum': {
|
|
106
|
+
const vacuumSetting = cleanModeSettings?.vacuuming;
|
|
107
|
+
return {
|
|
108
|
+
suctionPower: VacuumSuctionPowerA187[vacuumSetting?.fanMode] ?? VacuumSuctionPowerA187.Balanced,
|
|
109
|
+
waterFlow: MopWaterFlowA187.Off,
|
|
110
|
+
distance_off: 0,
|
|
111
|
+
mopRoute: MopRouteA187[vacuumSetting?.mopRouteMode] ?? MopRouteA187.Standard,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
case 'Vac & Mop': {
|
|
115
|
+
const vacmopSetting = cleanModeSettings?.vacmop;
|
|
116
|
+
const waterFlow = MopWaterFlowA187[vacmopSetting?.waterFlowMode] ?? MopWaterFlowA187.Medium;
|
|
117
|
+
const distance_off = waterFlow == MopWaterFlowA187.CustomizeWithDistanceOff ? 210 - 5 * (vacmopSetting?.distanceOff ?? 25) : 0;
|
|
118
|
+
return {
|
|
119
|
+
suctionPower: VacuumSuctionPowerA187[vacmopSetting?.fanMode] ?? VacuumSuctionPowerA187.Balanced,
|
|
120
|
+
waterFlow,
|
|
121
|
+
distance_off,
|
|
122
|
+
mopRoute: MopRouteA187[vacmopSetting?.mopRouteMode] ?? MopRouteA187.Standard,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
default:
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
84
129
|
handler.setCommandHandler('selectAreas', async (newAreas) => {
|
|
85
130
|
logger.notice(`BehaviorA187-selectAreas: ${newAreas}`);
|
|
86
131
|
roborockService.setSelectedAreas(duid, newAreas ?? []);
|
package/dist/platform.js
CHANGED
|
@@ -91,6 +91,11 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
91
91
|
}
|
|
92
92
|
async onConfigure() {
|
|
93
93
|
await super.onConfigure();
|
|
94
|
+
if (this.config.enableExperimentalFeature) {
|
|
95
|
+
const cleanModeSettings = this.config.cleanModeSettings;
|
|
96
|
+
this.log.notice(`Experimental Feature has been enable`);
|
|
97
|
+
this.log.notice(`cleanModeSettings ${debugStringify(cleanModeSettings)}`);
|
|
98
|
+
}
|
|
94
99
|
const self = this;
|
|
95
100
|
this.rvcInterval = setInterval(async () => {
|
|
96
101
|
self.platformRunner?.requestHomeData();
|
|
@@ -108,11 +113,15 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
108
113
|
this.log.error('Initializing: No supported devices found');
|
|
109
114
|
return;
|
|
110
115
|
}
|
|
116
|
+
let cleanModeSettings = undefined;
|
|
117
|
+
if (this.config.enableExperimentalFeature) {
|
|
118
|
+
cleanModeSettings = this.config.cleanModeSettings;
|
|
119
|
+
}
|
|
111
120
|
const self = this;
|
|
112
121
|
await this.roborockService.initializeMessageClientForLocal(vacuum);
|
|
113
122
|
const roomMap = await this.platformRunner.getRoomMapFromDevice(vacuum);
|
|
114
123
|
this.log.debug('Initializing - roomMap: ', debugStringify(roomMap));
|
|
115
|
-
const behaviorHandler = configurateBehavior(vacuum.data.model, vacuum.duid, this.roborockService, this.log);
|
|
124
|
+
const behaviorHandler = configurateBehavior(vacuum.data.model, vacuum.duid, this.roborockService, cleanModeSettings, this.log);
|
|
116
125
|
this.roborockService.setSupportedAreas(vacuum.duid, getSupportedAreas(vacuum.rooms, roomMap, this.log));
|
|
117
126
|
this.robot = new RoborockVacuumCleaner(username, vacuum, roomMap, this.log);
|
|
118
127
|
this.robot.configurateHandler(behaviorHandler);
|
|
@@ -63,24 +63,29 @@ export class MessageProcessor {
|
|
|
63
63
|
const request = new RequestMessage(def);
|
|
64
64
|
return this.client.send(duid, request);
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.logger?.warn('XXXXXXX: ', debugStringify(response));
|
|
69
|
-
return response;
|
|
66
|
+
getCustomMessage(duid, def) {
|
|
67
|
+
return this.client.get(duid, def);
|
|
70
68
|
}
|
|
71
69
|
async findMyRobot(duid) {
|
|
72
70
|
const request = new RequestMessage({ method: 'find_me' });
|
|
73
71
|
return this.client.send(duid, request);
|
|
74
72
|
}
|
|
75
|
-
async changeCleanMode(duid, suctionPower, waterFlow, mopRoute) {
|
|
76
|
-
this.logger?.notice(`Change clean mode for ${duid} to suctionPower: ${suctionPower}, waterFlow: ${waterFlow}`);
|
|
73
|
+
async changeCleanMode(duid, suctionPower, waterFlow, mopRoute, distance_off) {
|
|
74
|
+
this.logger?.notice(`Change clean mode for ${duid} to suctionPower: ${suctionPower}, waterFlow: ${waterFlow}, mopRoute: ${mopRoute}, distance_off: ${distance_off}`);
|
|
75
|
+
const currentMopMode = await this.getCustomMessage(duid, new RequestMessage({ method: 'get_custom_mode' }));
|
|
76
|
+
if (currentMopMode == 110) {
|
|
77
|
+
await this.client.send(duid, new RequestMessage({ method: 'set_mop_mode', params: [302] }));
|
|
78
|
+
}
|
|
77
79
|
if (mopRoute && mopRoute != 0) {
|
|
78
80
|
await this.client.send(duid, new RequestMessage({ method: 'set_mop_mode', params: [mopRoute] }));
|
|
79
81
|
}
|
|
80
82
|
if (suctionPower && suctionPower != 0) {
|
|
81
83
|
await this.client.send(duid, new RequestMessage({ method: 'set_custom_mode', params: [suctionPower] }));
|
|
82
84
|
}
|
|
83
|
-
if (waterFlow && waterFlow != 0) {
|
|
85
|
+
if (waterFlow && waterFlow == 207 && distance_off && distance_off != 0) {
|
|
86
|
+
await this.client.send(duid, new RequestMessage({ method: 'set_water_box_custom_mode', params: { 'water_box_mode': waterFlow, 'distance_off': distance_off } }));
|
|
87
|
+
}
|
|
88
|
+
else if (waterFlow && waterFlow != 0) {
|
|
84
89
|
await this.client.send(duid, new RequestMessage({ method: 'set_water_box_custom_mode', params: [waterFlow] }));
|
|
85
90
|
}
|
|
86
91
|
}
|
package/dist/roborockService.js
CHANGED
|
@@ -48,9 +48,9 @@ export default class RoborockService {
|
|
|
48
48
|
getSupportedAreas(duid) {
|
|
49
49
|
return this.supportedAreas.get(duid);
|
|
50
50
|
}
|
|
51
|
-
async changeCleanMode(duid, { suctionPower, waterFlow, mopRoute }) {
|
|
51
|
+
async changeCleanMode(duid, { suctionPower, waterFlow, distance_off, mopRoute }) {
|
|
52
52
|
this.logger.notice('changeCleanMode');
|
|
53
|
-
return this.messageProcessor?.changeCleanMode(duid, suctionPower, waterFlow, mopRoute);
|
|
53
|
+
return this.messageProcessor?.changeCleanMode(duid, suctionPower, waterFlow, mopRoute, distance_off);
|
|
54
54
|
}
|
|
55
55
|
async startClean(duid) {
|
|
56
56
|
const areas = this.supportedAreas.get(duid);
|
|
@@ -89,6 +89,9 @@ export default class RoborockService {
|
|
|
89
89
|
this.logger.debug('customGetInSecure-message', method);
|
|
90
90
|
return this.getMessageProcessor()?.getCustomMessage(duid, new RequestMessage({ method, secure: true }));
|
|
91
91
|
}
|
|
92
|
+
async customSend(duid, request) {
|
|
93
|
+
return this.getMessageProcessor()?.sendCustomMessage(duid, request);
|
|
94
|
+
}
|
|
92
95
|
stopService() {
|
|
93
96
|
if (this.messageClient) {
|
|
94
97
|
this.messageClient.disconnect();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "Matterbridge Roborock Vacuum Plugin",
|
|
3
|
-
"description": "matterbridge-roborock-vacuum-plugin v. 1.0.7
|
|
3
|
+
"description": "matterbridge-roborock-vacuum-plugin v. 1.0.7 by https://github.com/RinDevJunior",
|
|
4
4
|
"type": "object",
|
|
5
|
-
"required": [],
|
|
5
|
+
"required": ["username", "password"],
|
|
6
6
|
"properties": {
|
|
7
7
|
"name": {
|
|
8
8
|
"description": "Plugin name",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"ui:widget": "hidden"
|
|
18
18
|
},
|
|
19
19
|
"whiteList": {
|
|
20
|
-
"description": "(ONLY SET IF YOU HAVE MULTIPLE VACUUMS) Only THE FIRST ONE device with
|
|
20
|
+
"description": "(ONLY SET IF YOU HAVE MULTIPLE VACUUMS) Only THE FIRST ONE device with <Name>-<duid> in the list will be exposed. If the list is empty, THE FIRST device will be exposed.",
|
|
21
21
|
"type": "array",
|
|
22
22
|
"items": {
|
|
23
23
|
"type": "string"
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
"password": {
|
|
33
33
|
"description": "Roborock password (required for the plugin to work)",
|
|
34
|
-
"type": "string"
|
|
34
|
+
"type": "string",
|
|
35
|
+
"ui:widget": "password"
|
|
35
36
|
},
|
|
36
37
|
"refreshInterval": {
|
|
37
38
|
"description": "Refresh interval in seconds (default: 60)",
|
|
@@ -43,6 +44,103 @@
|
|
|
43
44
|
"type": "boolean",
|
|
44
45
|
"default": false
|
|
45
46
|
},
|
|
47
|
+
"cleanModeSettings": {
|
|
48
|
+
"description": "Configure default cleaning parameters for vacuum.",
|
|
49
|
+
"type": "object",
|
|
50
|
+
"properties": {
|
|
51
|
+
"vacuuming": {
|
|
52
|
+
"description": "Vacuuming only",
|
|
53
|
+
"type": "object",
|
|
54
|
+
"properties": {
|
|
55
|
+
"fanMode": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"description": "Suction power mode to use in Vacuuming only mode (e.g., 'Quiet', 'Balanced', 'Turbo', 'Max', 'MaxPlus').",
|
|
58
|
+
"default": "Balanced"
|
|
59
|
+
},
|
|
60
|
+
"mopRouteMode": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"description": "Mop route intensity to use in Vacuuming only mode (e.g., 'Standard', 'Deep', 'DeepPlus', 'Fast').",
|
|
63
|
+
"default": "Standard"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"mopping": {
|
|
68
|
+
"description": "Mopping only",
|
|
69
|
+
"type": "object",
|
|
70
|
+
"properties": {
|
|
71
|
+
"waterFlowMode": {
|
|
72
|
+
"type": "string",
|
|
73
|
+
"description": "Water flow mode to use in Mopping only mode (e.g., 'Low', 'Medium', 'High', 'CustomizeWithDistanceOff').",
|
|
74
|
+
"default": "Medium"
|
|
75
|
+
},
|
|
76
|
+
"mopRouteMode": {
|
|
77
|
+
"type": "string",
|
|
78
|
+
"description": "Mop route intensity to use in Mopping only mode (e.g., 'Standard', 'Deep', 'DeepPlus', 'Fast').",
|
|
79
|
+
"default": "Standard"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"allOf": [
|
|
83
|
+
{
|
|
84
|
+
"if": {
|
|
85
|
+
"properties": {
|
|
86
|
+
"waterFlowMode": { "const": "CustomizeWithDistanceOff" }
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"then": {
|
|
90
|
+
"properties": {
|
|
91
|
+
"distanceOff": {
|
|
92
|
+
"type": "number",
|
|
93
|
+
"description": "Distance Off - Default = 25",
|
|
94
|
+
"default": 25
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"required": ["distanceOff"]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
"vacmop": {
|
|
103
|
+
"description": "Vacuuming and Mopping",
|
|
104
|
+
"type": "object",
|
|
105
|
+
"properties": {
|
|
106
|
+
"fanMode": {
|
|
107
|
+
"type": "string",
|
|
108
|
+
"description": "Suction power mode to use in Vacuuming and Mopping mode (e.g., 'Quiet', 'Balanced', 'Turbo', 'Max', 'MaxPlus').",
|
|
109
|
+
"default": "Balanced"
|
|
110
|
+
},
|
|
111
|
+
"waterFlowMode": {
|
|
112
|
+
"type": "string",
|
|
113
|
+
"description": "Water flow mode to use in Vacuuming and Mopping mode (e.g., 'Low', 'Medium', 'High', 'CustomizeWithDistanceOff').",
|
|
114
|
+
"default": "Medium"
|
|
115
|
+
},
|
|
116
|
+
"mopRouteMode": {
|
|
117
|
+
"type": "string",
|
|
118
|
+
"description": "Mop route intensity to use in Vacuuming and Mopping mode (e.g., 'Standard', 'Deep', 'DeepPlus', 'Fast').",
|
|
119
|
+
"default": "Standard"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"allOf": [
|
|
123
|
+
{
|
|
124
|
+
"if": {
|
|
125
|
+
"properties": {
|
|
126
|
+
"waterFlowMode": { "const": "CustomizeWithDistanceOff" }
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"then": {
|
|
130
|
+
"properties": {
|
|
131
|
+
"distanceOff": {
|
|
132
|
+
"type": "number",
|
|
133
|
+
"description": "Distance Off - Default = 25",
|
|
134
|
+
"default": 25
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"required": ["distanceOff"]
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
46
144
|
"debug": {
|
|
47
145
|
"description": "Enable the debug for the plugin (development only)",
|
|
48
146
|
"type": "boolean",
|
|
@@ -53,5 +151,20 @@
|
|
|
53
151
|
"type": "boolean",
|
|
54
152
|
"default": false
|
|
55
153
|
}
|
|
56
|
-
}
|
|
154
|
+
},
|
|
155
|
+
"dependencies": {
|
|
156
|
+
"cleanModeSettings": ["enableExperimentalFeature"]
|
|
157
|
+
},
|
|
158
|
+
"allOf": [
|
|
159
|
+
{
|
|
160
|
+
"if": {
|
|
161
|
+
"properties": { "enableExperimentalFeature": { "const": false } }
|
|
162
|
+
},
|
|
163
|
+
"then": {
|
|
164
|
+
"properties": {
|
|
165
|
+
"cleanModeSettings": false
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
]
|
|
57
170
|
}
|
package/package.json
CHANGED
package/src/behaviorFactory.ts
CHANGED
|
@@ -5,14 +5,21 @@ import RoborockService from './roborockService.js';
|
|
|
5
5
|
import { DefaultEndpointCommands, setDefaultCommandHandler } from './behaviors/roborock.vacuum/default/default.js';
|
|
6
6
|
import { DeviceModel } from './roborockCommunication/Zmodel/deviceModel.js';
|
|
7
7
|
import { EndpointCommandsA27, setCommandHandlerA27 } from './behaviors/roborock.vacuum/S7_MAXV/a27.js';
|
|
8
|
+
import { CleanModeSettings } from './model/CleanModeSettings.js';
|
|
8
9
|
|
|
9
10
|
export type BehaviorFactoryResult = BehaviorDeviceGeneric<DefaultEndpointCommands> | BehaviorDeviceGeneric<EndpointCommandsA187>;
|
|
10
11
|
|
|
11
|
-
export function configurateBehavior(
|
|
12
|
+
export function configurateBehavior(
|
|
13
|
+
model: string,
|
|
14
|
+
duid: string,
|
|
15
|
+
roborockService: RoborockService,
|
|
16
|
+
cleanModeSettings: CleanModeSettings | undefined,
|
|
17
|
+
logger: AnsiLogger,
|
|
18
|
+
): BehaviorFactoryResult {
|
|
12
19
|
switch (model) {
|
|
13
20
|
case DeviceModel.QREVO_EDGE_5V1: {
|
|
14
21
|
const deviceHandler = new BehaviorDeviceGeneric<EndpointCommandsA187>(logger);
|
|
15
|
-
setCommandHandlerA187(duid, deviceHandler, logger, roborockService);
|
|
22
|
+
setCommandHandlerA187(duid, deviceHandler, logger, roborockService, cleanModeSettings);
|
|
16
23
|
return deviceHandler;
|
|
17
24
|
}
|
|
18
25
|
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { setCommandHandlerA187, VacuumSuctionPowerA187, MopWaterFlowA187, MopRouteA187 } from './a187';
|
|
2
|
+
import { BehaviorDeviceGeneric } from '../../BehaviorDeviceGeneric';
|
|
3
|
+
import { AnsiLogger } from 'matterbridge/logger';
|
|
4
|
+
import RoborockService from '../../../roborockService';
|
|
5
|
+
import { CleanModeSettings } from '../../../model/CleanModeSettings';
|
|
6
|
+
import { jest } from '@jest/globals';
|
|
7
|
+
import { distance } from 'jimp';
|
|
8
|
+
|
|
9
|
+
describe('setCommandHandlerA187', () => {
|
|
10
|
+
let handler: BehaviorDeviceGeneric<any>;
|
|
11
|
+
let logger: AnsiLogger;
|
|
12
|
+
let roborockService: jest.Mocked<RoborockService>;
|
|
13
|
+
let cleanModeSettings: CleanModeSettings;
|
|
14
|
+
const duid = 'test-duid';
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
handler = {
|
|
18
|
+
setCommandHandler: jest.fn(),
|
|
19
|
+
} as any;
|
|
20
|
+
|
|
21
|
+
logger = {
|
|
22
|
+
notice: jest.fn(),
|
|
23
|
+
warn: jest.fn(),
|
|
24
|
+
} as any;
|
|
25
|
+
|
|
26
|
+
roborockService = {
|
|
27
|
+
startClean: jest.fn(),
|
|
28
|
+
changeCleanMode: jest.fn(),
|
|
29
|
+
setSelectedAreas: jest.fn(),
|
|
30
|
+
pauseClean: jest.fn(),
|
|
31
|
+
resumeClean: jest.fn(),
|
|
32
|
+
stopAndGoHome: jest.fn(),
|
|
33
|
+
playSoundToLocate: jest.fn(),
|
|
34
|
+
} as any;
|
|
35
|
+
|
|
36
|
+
cleanModeSettings = {
|
|
37
|
+
vacuuming: { fanMode: 'Max', mopRouteMode: 'DeepPlus' },
|
|
38
|
+
mopping: { waterFlowMode: 'High', mopRouteMode: 'Fast', distanceOff: 25 },
|
|
39
|
+
vacmop: {
|
|
40
|
+
fanMode: 'Turbo',
|
|
41
|
+
waterFlowMode: 'Low',
|
|
42
|
+
mopRouteMode: 'Deep',
|
|
43
|
+
distanceOff: 25,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should set all command handlers', () => {
|
|
49
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
50
|
+
expect(handler.setCommandHandler).toHaveBeenCalledWith('changeToMode', expect.any(Function));
|
|
51
|
+
expect(handler.setCommandHandler).toHaveBeenCalledWith('selectAreas', expect.any(Function));
|
|
52
|
+
expect(handler.setCommandHandler).toHaveBeenCalledWith('pause', expect.any(Function));
|
|
53
|
+
expect(handler.setCommandHandler).toHaveBeenCalledWith('resume', expect.any(Function));
|
|
54
|
+
expect(handler.setCommandHandler).toHaveBeenCalledWith('goHome', expect.any(Function));
|
|
55
|
+
expect(handler.setCommandHandler).toHaveBeenCalledWith('PlaySoundToLocate', expect.any(Function));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should call startClean for Cleaning mode', async () => {
|
|
59
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
60
|
+
const [[, changeToModeHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'changeToMode');
|
|
61
|
+
await (changeToModeHandler as (mode: number) => Promise<void>)(2); // 2 = Cleaning
|
|
62
|
+
expect(roborockService.startClean).toHaveBeenCalledWith(duid);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should call changeCleanMode for Smart Plan', async () => {
|
|
66
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
67
|
+
const [[, changeToModeHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'changeToMode');
|
|
68
|
+
await (changeToModeHandler as (mode: number) => Promise<void>)(4); // 4 = Smart Plan
|
|
69
|
+
expect(roborockService.changeCleanMode).toHaveBeenCalledWith(duid, {
|
|
70
|
+
suctionPower: 0,
|
|
71
|
+
waterFlow: 0,
|
|
72
|
+
distance_off: 0,
|
|
73
|
+
mopRoute: MopRouteA187.Smart,
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should call changeCleanMode for Mop with correct values', async () => {
|
|
78
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
79
|
+
const [[, changeToModeHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'changeToMode');
|
|
80
|
+
await (changeToModeHandler as (mode: number) => Promise<void>)(5); // 5 = Mop
|
|
81
|
+
//mopping: { waterFlowMode: 'High', mopRouteMode: 'Fast', distanceOff: 85 },
|
|
82
|
+
expect(roborockService.changeCleanMode).toHaveBeenCalledWith(duid, {
|
|
83
|
+
suctionPower: VacuumSuctionPowerA187.Off,
|
|
84
|
+
waterFlow: MopWaterFlowA187.High,
|
|
85
|
+
mopRoute: MopRouteA187.Fast,
|
|
86
|
+
distance_off: 0,
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should call changeCleanMode for Mop with correct values', async () => {
|
|
91
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, {
|
|
92
|
+
vacuuming: { fanMode: 'Max', mopRouteMode: 'DeepPlus' },
|
|
93
|
+
mopping: { waterFlowMode: 'CustomizeWithDistanceOff', mopRouteMode: 'Fast', distanceOff: 25 },
|
|
94
|
+
vacmop: {
|
|
95
|
+
fanMode: 'Turbo',
|
|
96
|
+
waterFlowMode: 'Low',
|
|
97
|
+
mopRouteMode: 'Deep',
|
|
98
|
+
distanceOff: 25,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
const [[, changeToModeHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'changeToMode');
|
|
102
|
+
await (changeToModeHandler as (mode: number) => Promise<void>)(5); // 5 = Mop
|
|
103
|
+
//vacuuming: { fanMode: 'Max', mopRouteMode: 'DeepPlus' },
|
|
104
|
+
expect(roborockService.changeCleanMode).toHaveBeenCalledWith(duid, {
|
|
105
|
+
suctionPower: VacuumSuctionPowerA187.Off,
|
|
106
|
+
waterFlow: MopWaterFlowA187.CustomizeWithDistanceOff,
|
|
107
|
+
mopRoute: MopRouteA187.Fast,
|
|
108
|
+
distance_off: 85,
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should call changeCleanMode for Vacuum with correct values', async () => {
|
|
113
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
114
|
+
const [[, changeToModeHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'changeToMode');
|
|
115
|
+
await (changeToModeHandler as (mode: number) => Promise<void>)(6); // 6 = Vacuum
|
|
116
|
+
//vacuuming: { fanMode: 'Max', mopRouteMode: 'DeepPlus' },
|
|
117
|
+
expect(roborockService.changeCleanMode).toHaveBeenCalledWith(duid, {
|
|
118
|
+
suctionPower: VacuumSuctionPowerA187.Max,
|
|
119
|
+
waterFlow: MopWaterFlowA187.Off,
|
|
120
|
+
mopRoute: MopRouteA187.DeepPlus,
|
|
121
|
+
distance_off: 0,
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should call changeCleanMode for Vac & Mop with correct values', async () => {
|
|
126
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
127
|
+
const [[, changeToModeHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'changeToMode');
|
|
128
|
+
await (changeToModeHandler as (mode: number) => Promise<void>)(7); // 7 = Vac & Mop
|
|
129
|
+
/*
|
|
130
|
+
vacmop: {
|
|
131
|
+
fanMode: 'Turbo',
|
|
132
|
+
waterFlowMode: 'Low',
|
|
133
|
+
mopRouteMode: 'Deep',
|
|
134
|
+
distanceOff: 85,
|
|
135
|
+
},
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
expect(roborockService.changeCleanMode).toHaveBeenCalledWith(duid, {
|
|
139
|
+
suctionPower: VacuumSuctionPowerA187.Turbo,
|
|
140
|
+
waterFlow: MopWaterFlowA187.Low,
|
|
141
|
+
mopRoute: MopRouteA187.Deep,
|
|
142
|
+
distance_off: 0,
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should call changeCleanMode for Vac & Mop with correct values', async () => {
|
|
147
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, {
|
|
148
|
+
vacuuming: { fanMode: 'Max', mopRouteMode: 'DeepPlus' },
|
|
149
|
+
mopping: { waterFlowMode: 'CustomizeWithDistanceOff', mopRouteMode: 'Fast', distanceOff: 25 },
|
|
150
|
+
vacmop: {
|
|
151
|
+
fanMode: 'Turbo',
|
|
152
|
+
waterFlowMode: 'CustomizeWithDistanceOff',
|
|
153
|
+
mopRouteMode: 'Deep',
|
|
154
|
+
distanceOff: 25,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
const [[, changeToModeHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'changeToMode');
|
|
158
|
+
await (changeToModeHandler as (mode: number) => Promise<void>)(7); // 7 = Vac & Mop
|
|
159
|
+
expect(roborockService.changeCleanMode).toHaveBeenCalledWith(duid, {
|
|
160
|
+
suctionPower: VacuumSuctionPowerA187.Turbo,
|
|
161
|
+
waterFlow: MopWaterFlowA187.CustomizeWithDistanceOff,
|
|
162
|
+
mopRoute: MopRouteA187.Deep,
|
|
163
|
+
distance_off: 85,
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should call setSelectedAreas', async () => {
|
|
168
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
169
|
+
const [[, selectAreasHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'selectAreas');
|
|
170
|
+
await (selectAreasHandler as (areas: number[]) => Promise<void>)([1, 2, 3]);
|
|
171
|
+
expect(roborockService.setSelectedAreas).toHaveBeenCalledWith(duid, [1, 2, 3]);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should call pauseClean', async () => {
|
|
175
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
176
|
+
const [[, pauseHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'pause');
|
|
177
|
+
await (pauseHandler as () => Promise<void>)();
|
|
178
|
+
expect(roborockService.pauseClean).toHaveBeenCalledWith(duid);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should call resumeClean', async () => {
|
|
182
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
183
|
+
const [[, resumeHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'resume');
|
|
184
|
+
await (resumeHandler as () => Promise<void>)();
|
|
185
|
+
expect(roborockService.resumeClean).toHaveBeenCalledWith(duid);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should call stopAndGoHome', async () => {
|
|
189
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
190
|
+
const [[, goHomeHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'goHome');
|
|
191
|
+
await (goHomeHandler as () => Promise<void>)();
|
|
192
|
+
expect(roborockService.stopAndGoHome).toHaveBeenCalledWith(duid);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should call playSoundToLocate', async () => {
|
|
196
|
+
setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings);
|
|
197
|
+
const [[, playSoundHandler]] = (handler.setCommandHandler as jest.Mock).mock.calls.filter(([cmd]) => cmd === 'PlaySoundToLocate');
|
|
198
|
+
await (playSoundHandler as (arg: number) => Promise<void>)(1);
|
|
199
|
+
expect(roborockService.playSoundToLocate).toHaveBeenCalledWith(duid);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
@@ -2,6 +2,7 @@ import { MaybePromise } from 'matterbridge/matter';
|
|
|
2
2
|
import { AnsiLogger, debugStringify } from 'matterbridge/logger';
|
|
3
3
|
import { BehaviorDeviceGeneric, BehaviorRoborock, DeviceCommands } from '../../BehaviorDeviceGeneric.js';
|
|
4
4
|
import RoborockService from '../../../roborockService.js';
|
|
5
|
+
import { CleanModeSettings } from '../../../model/CleanModeSettings.js';
|
|
5
6
|
|
|
6
7
|
export interface EndpointCommandsA187 extends DeviceCommands {
|
|
7
8
|
selectAreas: (newAreas: any) => MaybePromise;
|
|
@@ -41,16 +42,17 @@ export enum MopWaterFlowA187 {
|
|
|
41
42
|
Medium = 202,
|
|
42
43
|
High = 203,
|
|
43
44
|
Custom = 204,
|
|
45
|
+
CustomizeWithDistanceOff = 207,
|
|
44
46
|
Smart = 209,
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
//set_mop_mode
|
|
48
50
|
export enum MopRouteA187 {
|
|
49
|
-
Fast = 304,
|
|
50
51
|
Standard = 300,
|
|
51
52
|
Deep = 301,
|
|
52
53
|
Custom = 302,
|
|
53
54
|
DeepPlus = 303,
|
|
55
|
+
Fast = 304,
|
|
54
56
|
Smart = 306,
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -67,15 +69,21 @@ const RvcCleanMode: Record<number, string> = {
|
|
|
67
69
|
[8]: 'Custom',
|
|
68
70
|
};
|
|
69
71
|
|
|
70
|
-
const CleanSetting: Record<number, { suctionPower: number; waterFlow: number; mopRoute: number }> = {
|
|
71
|
-
[4]: { suctionPower: 0, waterFlow: 0, mopRoute: MopRouteA187.Smart }, //'Smart Plan'
|
|
72
|
-
[5]: { suctionPower: VacuumSuctionPowerA187.Off, waterFlow: MopWaterFlowA187.Medium, mopRoute: MopRouteA187.Custom }, //'Mop'
|
|
73
|
-
[6]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Off, mopRoute: MopRouteA187.Custom }, //'Vacuum'
|
|
74
|
-
[7]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Medium, mopRoute: MopRouteA187.Custom }, //'Vac & Mop'
|
|
75
|
-
[8]: { suctionPower: VacuumSuctionPowerA187.Custom, waterFlow: MopWaterFlowA187.Custom, mopRoute: MopRouteA187.Custom }, // 'Custom'
|
|
72
|
+
const CleanSetting: Record<number, { suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number }> = {
|
|
73
|
+
[4]: { suctionPower: 0, waterFlow: 0, distance_off: 0, mopRoute: MopRouteA187.Smart }, //'Smart Plan'
|
|
74
|
+
[5]: { suctionPower: VacuumSuctionPowerA187.Off, waterFlow: MopWaterFlowA187.Medium, distance_off: 0, mopRoute: MopRouteA187.Custom }, //'Mop'
|
|
75
|
+
[6]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Off, distance_off: 0, mopRoute: MopRouteA187.Custom }, //'Vacuum'
|
|
76
|
+
[7]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Medium, distance_off: 0, mopRoute: MopRouteA187.Custom }, //'Vac & Mop'
|
|
77
|
+
[8]: { suctionPower: VacuumSuctionPowerA187.Custom, waterFlow: MopWaterFlowA187.Custom, distance_off: 0, mopRoute: MopRouteA187.Custom }, // 'Custom'
|
|
76
78
|
};
|
|
77
79
|
|
|
78
|
-
export function setCommandHandlerA187(
|
|
80
|
+
export function setCommandHandlerA187(
|
|
81
|
+
duid: string,
|
|
82
|
+
handler: BehaviorDeviceGeneric<DeviceCommands>,
|
|
83
|
+
logger: AnsiLogger,
|
|
84
|
+
roborockService: RoborockService,
|
|
85
|
+
cleanModeSettings: CleanModeSettings | undefined,
|
|
86
|
+
): void {
|
|
79
87
|
handler.setCommandHandler('changeToMode', async (newMode: number) => {
|
|
80
88
|
const activity = RvcRunMode[newMode] || RvcCleanMode[newMode];
|
|
81
89
|
switch (activity) {
|
|
@@ -85,21 +93,69 @@ export function setCommandHandlerA187(duid: string, handler: BehaviorDeviceGener
|
|
|
85
93
|
return;
|
|
86
94
|
}
|
|
87
95
|
case 'Smart Plan':
|
|
88
|
-
case 'Mop':
|
|
89
|
-
case 'Vacuum':
|
|
90
|
-
case 'Vac & Mop':
|
|
91
96
|
case 'Custom': {
|
|
92
97
|
const setting = CleanSetting[newMode];
|
|
93
|
-
logger.notice(`BehaviorA187-ChangeCleanMode to: ${activity},
|
|
98
|
+
logger.notice(`BehaviorA187-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting)}`);
|
|
94
99
|
await roborockService.changeCleanMode(duid, setting);
|
|
95
100
|
return;
|
|
96
101
|
}
|
|
102
|
+
case 'Mop':
|
|
103
|
+
case 'Vacuum':
|
|
104
|
+
case 'Vac & Mop': {
|
|
105
|
+
const setting = cleanModeSettings ? getSettingFromCleanMode(activity, cleanModeSettings) : CleanSetting[newMode];
|
|
106
|
+
logger.notice(`BehaviorA187-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting ?? {})}`);
|
|
107
|
+
if (setting) {
|
|
108
|
+
await roborockService.changeCleanMode(duid, setting);
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
97
112
|
default:
|
|
98
113
|
logger.notice('BehaviorA187-changeToMode-Unknown: ', newMode);
|
|
99
114
|
return;
|
|
100
115
|
}
|
|
101
116
|
});
|
|
102
117
|
|
|
118
|
+
const getSettingFromCleanMode = (
|
|
119
|
+
activity: string,
|
|
120
|
+
cleanModeSettings?: CleanModeSettings,
|
|
121
|
+
): { suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number } | undefined => {
|
|
122
|
+
switch (activity) {
|
|
123
|
+
case 'Mop': {
|
|
124
|
+
const mopSetting = cleanModeSettings?.mopping;
|
|
125
|
+
const waterFlow = MopWaterFlowA187[mopSetting?.waterFlowMode as keyof typeof MopWaterFlowA187] ?? MopWaterFlowA187.Medium;
|
|
126
|
+
const distance_off = waterFlow == MopWaterFlowA187.CustomizeWithDistanceOff ? 210 - 5 * (mopSetting?.distanceOff ?? 25) : 0;
|
|
127
|
+
return {
|
|
128
|
+
suctionPower: VacuumSuctionPowerA187.Off,
|
|
129
|
+
waterFlow,
|
|
130
|
+
distance_off,
|
|
131
|
+
mopRoute: MopRouteA187[mopSetting?.mopRouteMode as keyof typeof MopRouteA187] ?? MopRouteA187.Standard,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
case 'Vacuum': {
|
|
135
|
+
const vacuumSetting = cleanModeSettings?.vacuuming;
|
|
136
|
+
return {
|
|
137
|
+
suctionPower: VacuumSuctionPowerA187[vacuumSetting?.fanMode as keyof typeof VacuumSuctionPowerA187] ?? VacuumSuctionPowerA187.Balanced,
|
|
138
|
+
waterFlow: MopWaterFlowA187.Off,
|
|
139
|
+
distance_off: 0,
|
|
140
|
+
mopRoute: MopRouteA187[vacuumSetting?.mopRouteMode as keyof typeof MopRouteA187] ?? MopRouteA187.Standard,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
case 'Vac & Mop': {
|
|
144
|
+
const vacmopSetting = cleanModeSettings?.vacmop;
|
|
145
|
+
const waterFlow = MopWaterFlowA187[vacmopSetting?.waterFlowMode as keyof typeof MopWaterFlowA187] ?? MopWaterFlowA187.Medium;
|
|
146
|
+
const distance_off = waterFlow == MopWaterFlowA187.CustomizeWithDistanceOff ? 210 - 5 * (vacmopSetting?.distanceOff ?? 25) : 0;
|
|
147
|
+
return {
|
|
148
|
+
suctionPower: VacuumSuctionPowerA187[vacmopSetting?.fanMode as keyof typeof VacuumSuctionPowerA187] ?? VacuumSuctionPowerA187.Balanced,
|
|
149
|
+
waterFlow,
|
|
150
|
+
distance_off,
|
|
151
|
+
mopRoute: MopRouteA187[vacmopSetting?.mopRouteMode as keyof typeof MopRouteA187] ?? MopRouteA187.Standard,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
default:
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
103
159
|
handler.setCommandHandler('selectAreas', async (newAreas: number[]) => {
|
|
104
160
|
logger.notice(`BehaviorA187-selectAreas: ${newAreas}`);
|
|
105
161
|
roborockService.setSelectedAreas(duid, newAreas ?? []);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class CleanModeSettings {
|
|
2
|
+
vacuuming?: {
|
|
3
|
+
fanMode?: string;
|
|
4
|
+
mopRouteMode?: string;
|
|
5
|
+
};
|
|
6
|
+
mopping?: {
|
|
7
|
+
waterFlowMode?: string;
|
|
8
|
+
distanceOff?: number;
|
|
9
|
+
mopRouteMode?: string;
|
|
10
|
+
};
|
|
11
|
+
vacmop?: {
|
|
12
|
+
fanMode?: string;
|
|
13
|
+
waterFlowMode?: string;
|
|
14
|
+
distanceOff?: number;
|
|
15
|
+
mopRouteMode?: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
package/src/platform.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { configurateBehavior } from './behaviorFactory.js';
|
|
|
12
12
|
import { NotifyMessageTypes } from './notifyMessageTypes.js';
|
|
13
13
|
import { Device, RoborockAuthenticateApi, RoborockIoTApi } from './roborockCommunication/index.js';
|
|
14
14
|
import { getSupportedAreas } from './initialData/index.js';
|
|
15
|
+
import { CleanModeSettings } from './model/CleanModeSettings.js';
|
|
15
16
|
|
|
16
17
|
export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
17
18
|
robot: RoborockVacuumCleaner | undefined;
|
|
@@ -117,6 +118,13 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
117
118
|
|
|
118
119
|
override async onConfigure() {
|
|
119
120
|
await super.onConfigure();
|
|
121
|
+
if (this.config.enableExperimentalFeature) {
|
|
122
|
+
const cleanModeSettings = this.config.cleanModeSettings as CleanModeSettings;
|
|
123
|
+
|
|
124
|
+
this.log.notice(`Experimental Feature has been enable`);
|
|
125
|
+
this.log.notice(`cleanModeSettings ${debugStringify(cleanModeSettings)}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
120
128
|
const self = this;
|
|
121
129
|
this.rvcInterval = setInterval(
|
|
122
130
|
async () => {
|
|
@@ -138,6 +146,10 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
138
146
|
this.log.error('Initializing: No supported devices found');
|
|
139
147
|
return;
|
|
140
148
|
}
|
|
149
|
+
let cleanModeSettings: CleanModeSettings | undefined = undefined;
|
|
150
|
+
if (this.config.enableExperimentalFeature) {
|
|
151
|
+
cleanModeSettings = this.config.cleanModeSettings as CleanModeSettings;
|
|
152
|
+
}
|
|
141
153
|
|
|
142
154
|
const self = this;
|
|
143
155
|
await this.roborockService.initializeMessageClientForLocal(vacuum);
|
|
@@ -145,7 +157,7 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
145
157
|
|
|
146
158
|
this.log.debug('Initializing - roomMap: ', debugStringify(roomMap));
|
|
147
159
|
|
|
148
|
-
const behaviorHandler = configurateBehavior(vacuum.data.model, vacuum.duid, this.roborockService, this.log);
|
|
160
|
+
const behaviorHandler = configurateBehavior(vacuum.data.model, vacuum.duid, this.roborockService, cleanModeSettings, this.log);
|
|
149
161
|
|
|
150
162
|
this.roborockService.setSupportedAreas(vacuum.duid, getSupportedAreas(vacuum.rooms, roomMap, this.log));
|
|
151
163
|
this.robot = new RoborockVacuumCleaner(username, vacuum, roomMap, this.log);
|
|
@@ -90,10 +90,8 @@ export class MessageProcessor {
|
|
|
90
90
|
return this.client.send(duid, request);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
public
|
|
94
|
-
|
|
95
|
-
this.logger?.warn('XXXXXXX: ', debugStringify(response));
|
|
96
|
-
return response;
|
|
93
|
+
public getCustomMessage(duid: string, def: RequestMessage): Promise<any> {
|
|
94
|
+
return this.client.get<any>(duid, def);
|
|
97
95
|
}
|
|
98
96
|
|
|
99
97
|
public async findMyRobot(duid: string): Promise<void> {
|
|
@@ -101,8 +99,16 @@ export class MessageProcessor {
|
|
|
101
99
|
return this.client.send(duid, request);
|
|
102
100
|
}
|
|
103
101
|
|
|
104
|
-
public async changeCleanMode(duid: string, suctionPower: number, waterFlow: number, mopRoute: number): Promise<void> {
|
|
105
|
-
this.logger?.notice(`Change clean mode for ${duid} to suctionPower: ${suctionPower}, waterFlow: ${waterFlow}`);
|
|
102
|
+
public async changeCleanMode(duid: string, suctionPower: number, waterFlow: number, mopRoute: number, distance_off: number): Promise<void> {
|
|
103
|
+
this.logger?.notice(`Change clean mode for ${duid} to suctionPower: ${suctionPower}, waterFlow: ${waterFlow}, mopRoute: ${mopRoute}, distance_off: ${distance_off}`);
|
|
104
|
+
|
|
105
|
+
const currentMopMode = await this.getCustomMessage(duid, new RequestMessage({ method: 'get_custom_mode' }));
|
|
106
|
+
|
|
107
|
+
//110 == AI/Smart Plan
|
|
108
|
+
//302 == Custom
|
|
109
|
+
if (currentMopMode == 110) {
|
|
110
|
+
await this.client.send(duid, new RequestMessage({ method: 'set_mop_mode', params: [302] }));
|
|
111
|
+
}
|
|
106
112
|
|
|
107
113
|
if (mopRoute && mopRoute != 0) {
|
|
108
114
|
await this.client.send(duid, new RequestMessage({ method: 'set_mop_mode', params: [mopRoute] }));
|
|
@@ -112,7 +118,10 @@ export class MessageProcessor {
|
|
|
112
118
|
await this.client.send(duid, new RequestMessage({ method: 'set_custom_mode', params: [suctionPower] }));
|
|
113
119
|
}
|
|
114
120
|
|
|
115
|
-
|
|
121
|
+
//207 == CustomizeWithDistanceOff
|
|
122
|
+
if (waterFlow && waterFlow == 207 && distance_off && distance_off != 0) {
|
|
123
|
+
await this.client.send(duid, new RequestMessage({ method: 'set_water_box_custom_mode', params: { 'water_box_mode': waterFlow, 'distance_off': distance_off } }));
|
|
124
|
+
} else if (waterFlow && waterFlow != 0) {
|
|
116
125
|
await this.client.send(duid, new RequestMessage({ method: 'set_water_box_custom_mode', params: [waterFlow] }));
|
|
117
126
|
}
|
|
118
127
|
}
|
package/src/roborockService.ts
CHANGED
|
@@ -84,9 +84,12 @@ export default class RoborockService {
|
|
|
84
84
|
return this.supportedAreas.get(duid);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
public async changeCleanMode(
|
|
87
|
+
public async changeCleanMode(
|
|
88
|
+
duid: string,
|
|
89
|
+
{ suctionPower, waterFlow, distance_off, mopRoute }: { suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number },
|
|
90
|
+
): Promise<void> {
|
|
88
91
|
this.logger.notice('changeCleanMode');
|
|
89
|
-
return this.messageProcessor?.changeCleanMode(duid, suctionPower, waterFlow, mopRoute);
|
|
92
|
+
return this.messageProcessor?.changeCleanMode(duid, suctionPower, waterFlow, mopRoute, distance_off);
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
public async startClean(duid: string): Promise<void> {
|
|
@@ -133,6 +136,10 @@ export default class RoborockService {
|
|
|
133
136
|
return this.getMessageProcessor()?.getCustomMessage(duid, new RequestMessage({ method, secure: true }));
|
|
134
137
|
}
|
|
135
138
|
|
|
139
|
+
public async customSend(duid: string, request: any): Promise<void> {
|
|
140
|
+
return this.getMessageProcessor()?.sendCustomMessage(duid, request);
|
|
141
|
+
}
|
|
142
|
+
|
|
136
143
|
public stopService(): void {
|
|
137
144
|
if (this.messageClient) {
|
|
138
145
|
this.messageClient.disconnect();
|