matterbridge-roborock-vacuum-plugin 1.0.7-rc01 → 1.0.7-rc03
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/README.md +11 -1
- package/dist/behaviorFactory.js +6 -0
- package/dist/behaviors/roborock.vacuum/S7_MAXV/a27.js +97 -0
- package/dist/behaviors/roborock.vacuum/S7_MAXV/initalData.js +76 -0
- package/dist/behaviors/roborock.vacuum/S7_MAXV/runtimes.js +33 -0
- package/dist/initialData/getOperationalStates.js +3 -0
- package/dist/initialData/getSupportedAreas.js +4 -4
- package/dist/initialData/getSupportedCleanModes.js +3 -0
- package/dist/initialData/getSupportedRunModes.js +3 -0
- package/dist/model/RoomMap.js +0 -6
- package/dist/platform.js +3 -2
- package/dist/rvc.js +2 -1
- package/dist/share/runtimeHelper.js +10 -0
- package/jest.config.js +19 -0
- package/matterbridge-roborock-vacuum-plugin.config.json +1 -1
- package/matterbridge-roborock-vacuum-plugin.schema.json +1 -1
- package/package.json +1 -1
- package/src/behaviorFactory.ts +7 -0
- package/src/behaviors/roborock.vacuum/S7_MAXV/a27.ts +121 -0
- package/src/behaviors/roborock.vacuum/S7_MAXV/initalData.ts +80 -0
- package/src/behaviors/roborock.vacuum/S7_MAXV/runtimes.ts +26 -0
- package/src/initialData/getOperationalStates.ts +3 -0
- package/src/initialData/getSupportedAreas.test.ts +55 -0
- package/src/initialData/getSupportedAreas.ts +4 -21
- package/src/initialData/getSupportedCleanModes.ts +3 -0
- package/src/initialData/getSupportedRunModes.ts +3 -0
- package/src/model/RoomMap.ts +6 -6
- package/src/platform.ts +3 -2
- package/src/rvc.ts +2 -1
- package/src/share/runtimeHelper.ts +10 -0
- package/tsconfig.jest.json +12 -0
package/README.md
CHANGED
|
@@ -42,13 +42,23 @@
|
|
|
42
42
|
---
|
|
43
43
|
### 🆔 How to Get Your DUID
|
|
44
44
|
|
|
45
|
-
To get the **DUID** for your devices
|
|
45
|
+
To get the **DUID** for your devices, you have two options:
|
|
46
46
|
|
|
47
|
+
**Option 1: From Matterbridge Logs**
|
|
47
48
|
1. **Start Matterbridge** with the plugin enabled.
|
|
48
49
|
2. **Watch the Docker console logs directly** (not the Matterbridge UI logs, as they may be truncated).
|
|
49
50
|
3. Look for the log message that says:
|
|
50
51
|
```text
|
|
51
52
|
Initializing - devices: [...]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Option 2: From the Roborock App**
|
|
56
|
+
1. Open the **Roborock app** on your phone.
|
|
57
|
+
2. Go to your **Device**.
|
|
58
|
+
3. Tap **Settings** > **Product Info**.
|
|
59
|
+
4. Find the **DID** field. The value will look like `rr_xxxxxxx`.
|
|
60
|
+
5. **Remove the `rr_` prefix** from the DID value. The remaining string is your DUID.
|
|
61
|
+
|
|
52
62
|
---
|
|
53
63
|
### 🚧 Project Status
|
|
54
64
|
|
package/dist/behaviorFactory.js
CHANGED
|
@@ -2,6 +2,7 @@ import { BehaviorDeviceGeneric } from './behaviors/BehaviorDeviceGeneric.js';
|
|
|
2
2
|
import { setCommandHandlerA187 } from './behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.js';
|
|
3
3
|
import { setDefaultCommandHandler } from './behaviors/roborock.vacuum/default/default.js';
|
|
4
4
|
import { DeviceModel } from './roborockCommunication/Zmodel/deviceModel.js';
|
|
5
|
+
import { setCommandHandlerA27 } from './behaviors/roborock.vacuum/S7_MAXV/a27.js';
|
|
5
6
|
export function configurateBehavior(model, duid, roborockService, logger) {
|
|
6
7
|
switch (model) {
|
|
7
8
|
case DeviceModel.QREVO_EDGE_5V1: {
|
|
@@ -9,6 +10,11 @@ export function configurateBehavior(model, duid, roborockService, logger) {
|
|
|
9
10
|
setCommandHandlerA187(duid, deviceHandler, logger, roborockService);
|
|
10
11
|
return deviceHandler;
|
|
11
12
|
}
|
|
13
|
+
case DeviceModel.S7_MAXV: {
|
|
14
|
+
const deviceHandler = new BehaviorDeviceGeneric(logger);
|
|
15
|
+
setCommandHandlerA27(duid, deviceHandler, logger, roborockService);
|
|
16
|
+
return deviceHandler;
|
|
17
|
+
}
|
|
12
18
|
default: {
|
|
13
19
|
const deviceHandler = new BehaviorDeviceGeneric(logger);
|
|
14
20
|
setDefaultCommandHandler(duid, deviceHandler, logger, roborockService);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { debugStringify } from 'matterbridge/logger';
|
|
2
|
+
import { BehaviorRoborock } from '../../BehaviorDeviceGeneric.js';
|
|
3
|
+
export class BehaviorA27 extends BehaviorRoborock {
|
|
4
|
+
}
|
|
5
|
+
export var BehaviorRoborockA27;
|
|
6
|
+
(function (BehaviorRoborockA27) {
|
|
7
|
+
class State {
|
|
8
|
+
device;
|
|
9
|
+
}
|
|
10
|
+
BehaviorRoborockA27.State = State;
|
|
11
|
+
})(BehaviorRoborockA27 || (BehaviorRoborockA27 = {}));
|
|
12
|
+
export var VacuumSuctionPowerA27;
|
|
13
|
+
(function (VacuumSuctionPowerA27) {
|
|
14
|
+
VacuumSuctionPowerA27[VacuumSuctionPowerA27["Quiet"] = 101] = "Quiet";
|
|
15
|
+
VacuumSuctionPowerA27[VacuumSuctionPowerA27["Balanced"] = 102] = "Balanced";
|
|
16
|
+
VacuumSuctionPowerA27[VacuumSuctionPowerA27["Turbo"] = 103] = "Turbo";
|
|
17
|
+
VacuumSuctionPowerA27[VacuumSuctionPowerA27["Max"] = 104] = "Max";
|
|
18
|
+
VacuumSuctionPowerA27[VacuumSuctionPowerA27["Off"] = 105] = "Off";
|
|
19
|
+
VacuumSuctionPowerA27[VacuumSuctionPowerA27["Custom"] = 106] = "Custom";
|
|
20
|
+
VacuumSuctionPowerA27[VacuumSuctionPowerA27["MaxPlus"] = 108] = "MaxPlus";
|
|
21
|
+
})(VacuumSuctionPowerA27 || (VacuumSuctionPowerA27 = {}));
|
|
22
|
+
export var MopWaterFlowA27;
|
|
23
|
+
(function (MopWaterFlowA27) {
|
|
24
|
+
MopWaterFlowA27[MopWaterFlowA27["Off"] = 200] = "Off";
|
|
25
|
+
MopWaterFlowA27[MopWaterFlowA27["Low"] = 201] = "Low";
|
|
26
|
+
MopWaterFlowA27[MopWaterFlowA27["Medium"] = 202] = "Medium";
|
|
27
|
+
MopWaterFlowA27[MopWaterFlowA27["High"] = 203] = "High";
|
|
28
|
+
MopWaterFlowA27[MopWaterFlowA27["Custom"] = 204] = "Custom";
|
|
29
|
+
})(MopWaterFlowA27 || (MopWaterFlowA27 = {}));
|
|
30
|
+
export var MopRouteA27;
|
|
31
|
+
(function (MopRouteA27) {
|
|
32
|
+
MopRouteA27[MopRouteA27["Standard"] = 300] = "Standard";
|
|
33
|
+
MopRouteA27[MopRouteA27["Deep"] = 301] = "Deep";
|
|
34
|
+
MopRouteA27[MopRouteA27["Custom"] = 302] = "Custom";
|
|
35
|
+
MopRouteA27[MopRouteA27["DeepPlus"] = 303] = "DeepPlus";
|
|
36
|
+
MopRouteA27[MopRouteA27["Fast"] = 304] = "Fast";
|
|
37
|
+
})(MopRouteA27 || (MopRouteA27 = {}));
|
|
38
|
+
const RvcRunMode = {
|
|
39
|
+
[1]: 'Idle',
|
|
40
|
+
[2]: 'Cleaning',
|
|
41
|
+
[3]: 'Mapping',
|
|
42
|
+
};
|
|
43
|
+
const RvcCleanMode = {
|
|
44
|
+
[5]: 'Mop',
|
|
45
|
+
[6]: 'Vacuum',
|
|
46
|
+
[7]: 'Vac & Mop',
|
|
47
|
+
[8]: 'Custom',
|
|
48
|
+
};
|
|
49
|
+
const CleanSetting = {
|
|
50
|
+
[5]: { suctionPower: VacuumSuctionPowerA27.Off, waterFlow: MopWaterFlowA27.Medium, mopRoute: MopRouteA27.Custom },
|
|
51
|
+
[6]: { suctionPower: VacuumSuctionPowerA27.Balanced, waterFlow: MopWaterFlowA27.Off, mopRoute: MopRouteA27.Custom },
|
|
52
|
+
[7]: { suctionPower: VacuumSuctionPowerA27.Balanced, waterFlow: MopWaterFlowA27.Medium, mopRoute: MopRouteA27.Custom },
|
|
53
|
+
[8]: { suctionPower: VacuumSuctionPowerA27.Custom, waterFlow: MopWaterFlowA27.Custom, mopRoute: MopRouteA27.Custom },
|
|
54
|
+
};
|
|
55
|
+
export function setCommandHandlerA27(duid, handler, logger, roborockService) {
|
|
56
|
+
handler.setCommandHandler('changeToMode', async (newMode) => {
|
|
57
|
+
const activity = RvcRunMode[newMode] || RvcCleanMode[newMode];
|
|
58
|
+
switch (activity) {
|
|
59
|
+
case 'Cleaning': {
|
|
60
|
+
logger.notice('BehaviorA27-ChangeRunMode to: ', activity);
|
|
61
|
+
await roborockService.startClean(duid);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
case 'Mop':
|
|
65
|
+
case 'Vacuum':
|
|
66
|
+
case 'Vac & Mop':
|
|
67
|
+
case 'Custom': {
|
|
68
|
+
const setting = CleanSetting[newMode];
|
|
69
|
+
logger.notice(`BehaviorA27-ChangeCleanMode to: ${activity}, code: ${debugStringify(setting)}`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
default:
|
|
73
|
+
logger.notice('BehaviorA27-changeToMode-Unknown: ', newMode);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
handler.setCommandHandler('selectAreas', async (newAreas) => {
|
|
78
|
+
logger.notice(`BehaviorA27-selectAreas: ${newAreas}`);
|
|
79
|
+
roborockService.setSelectedAreas(duid, newAreas ?? []);
|
|
80
|
+
});
|
|
81
|
+
handler.setCommandHandler('pause', async () => {
|
|
82
|
+
logger.notice('BehaviorA27-Pause');
|
|
83
|
+
await roborockService.pauseClean(duid);
|
|
84
|
+
});
|
|
85
|
+
handler.setCommandHandler('resume', async () => {
|
|
86
|
+
logger.notice('BehaviorA27-Resume');
|
|
87
|
+
await roborockService.resumeClean(duid);
|
|
88
|
+
});
|
|
89
|
+
handler.setCommandHandler('goHome', async () => {
|
|
90
|
+
logger.notice('BehaviorA27-GoHome');
|
|
91
|
+
await roborockService.stopAndGoHome(duid);
|
|
92
|
+
});
|
|
93
|
+
handler.setCommandHandler('PlaySoundToLocate', async (identifyTime) => {
|
|
94
|
+
logger.notice('BehaviorA27-PlaySoundToLocate');
|
|
95
|
+
await roborockService.playSoundToLocate(duid);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { RvcCleanMode, RvcOperationalState, RvcRunMode } from 'matterbridge/matter/clusters';
|
|
2
|
+
export function getSupportedRunModesA27() {
|
|
3
|
+
return [
|
|
4
|
+
{
|
|
5
|
+
label: 'Idle',
|
|
6
|
+
mode: 1,
|
|
7
|
+
modeTags: [{ value: RvcRunMode.ModeTag.Idle }],
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
label: 'Cleaning',
|
|
11
|
+
mode: 2,
|
|
12
|
+
modeTags: [{ value: RvcRunMode.ModeTag.Cleaning }],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
label: 'Mapping',
|
|
16
|
+
mode: 3,
|
|
17
|
+
modeTags: [{ value: RvcRunMode.ModeTag.Mapping }],
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
export function getSupportedCleanModesA27() {
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
label: 'Mop',
|
|
25
|
+
mode: 5,
|
|
26
|
+
modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Auto }],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: 'Vacuum',
|
|
30
|
+
mode: 6,
|
|
31
|
+
modeTags: [{ value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Auto }],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
label: 'Mop & Vacuum',
|
|
35
|
+
mode: 7,
|
|
36
|
+
modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.DeepClean }],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
label: 'Custom',
|
|
40
|
+
mode: 8,
|
|
41
|
+
modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Quick }],
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
export function getOperationalStatesA27() {
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
operationalStateId: RvcOperationalState.OperationalState.Stopped,
|
|
49
|
+
operationalStateLabel: 'Stopped',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
operationalStateId: RvcOperationalState.OperationalState.Running,
|
|
53
|
+
operationalStateLabel: 'Running',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
operationalStateId: RvcOperationalState.OperationalState.Paused,
|
|
57
|
+
operationalStateLabel: 'Paused',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
operationalStateId: RvcOperationalState.OperationalState.Error,
|
|
61
|
+
operationalStateLabel: 'Error',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
operationalStateId: RvcOperationalState.OperationalState.SeekingCharger,
|
|
65
|
+
operationalStateLabel: 'SeekingCharger',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
operationalStateId: RvcOperationalState.OperationalState.Charging,
|
|
69
|
+
operationalStateLabel: 'Charging',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
operationalStateId: RvcOperationalState.OperationalState.Docked,
|
|
73
|
+
operationalStateLabel: 'Docked',
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { MopWaterFlowA27, VacuumSuctionPowerA27 } from './a27.js';
|
|
2
|
+
export function getCurrentCleanModeA27(fan_power, water_box_mode) {
|
|
3
|
+
if (!fan_power || !water_box_mode)
|
|
4
|
+
return undefined;
|
|
5
|
+
if (fan_power == VacuumSuctionPowerA27.Custom || water_box_mode == MopWaterFlowA27.Custom)
|
|
6
|
+
return 8;
|
|
7
|
+
if (fan_power == VacuumSuctionPowerA27.Off)
|
|
8
|
+
return 5;
|
|
9
|
+
if (water_box_mode == MopWaterFlowA27.Off)
|
|
10
|
+
return 6;
|
|
11
|
+
else
|
|
12
|
+
return 7;
|
|
13
|
+
}
|
|
14
|
+
export function getCurrentCleanModeFromFanPowerA27(fan_power) {
|
|
15
|
+
if (!fan_power)
|
|
16
|
+
return undefined;
|
|
17
|
+
if (fan_power == VacuumSuctionPowerA27.Custom)
|
|
18
|
+
return 8;
|
|
19
|
+
if (fan_power == VacuumSuctionPowerA27.Off)
|
|
20
|
+
return 5;
|
|
21
|
+
else
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
export function getCurrentCleanModeFromWaterBoxModeA27(water_box_mode) {
|
|
25
|
+
if (!water_box_mode)
|
|
26
|
+
return undefined;
|
|
27
|
+
if (water_box_mode == MopWaterFlowA27.Custom)
|
|
28
|
+
return 8;
|
|
29
|
+
if (water_box_mode == MopWaterFlowA27.Off)
|
|
30
|
+
return 6;
|
|
31
|
+
else
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
@@ -3,10 +3,13 @@ import { getOperationalStatesA187 } from '../behaviors/roborock.vacuum/QREVO_EDG
|
|
|
3
3
|
import { getDefaultOperationalStates } from '../behaviors/roborock.vacuum/default/initalData.js';
|
|
4
4
|
import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
|
|
5
5
|
import { VacuumErrorCode } from '../roborockCommunication/Zenum/vacuumAndDockErrorCode.js';
|
|
6
|
+
import { getOperationalStatesA27 } from '../behaviors/roborock.vacuum/S7_MAXV/initalData.js';
|
|
6
7
|
export function getOperationalStates(model) {
|
|
7
8
|
switch (model) {
|
|
8
9
|
case DeviceModel.QREVO_EDGE_5V1:
|
|
9
10
|
return getOperationalStatesA187();
|
|
11
|
+
case DeviceModel.S7_MAXV:
|
|
12
|
+
return getOperationalStatesA27();
|
|
10
13
|
default:
|
|
11
14
|
return getDefaultOperationalStates();
|
|
12
15
|
}
|
|
@@ -19,13 +19,13 @@ export function getSupportedAreas(rooms, roomMap, log) {
|
|
|
19
19
|
},
|
|
20
20
|
];
|
|
21
21
|
}
|
|
22
|
-
const supportedAreas = rooms.map((room, index) => {
|
|
22
|
+
const supportedAreas = roomMap.rooms.map((room, index) => {
|
|
23
23
|
return {
|
|
24
|
-
areaId:
|
|
24
|
+
areaId: room.id,
|
|
25
25
|
mapId: null,
|
|
26
26
|
areaInfo: {
|
|
27
27
|
locationInfo: {
|
|
28
|
-
locationName: room.name,
|
|
28
|
+
locationName: room.displayName ?? rooms.find((r) => r.id == room.globalId)?.name ?? 'Unknown Room',
|
|
29
29
|
floorNumber: null,
|
|
30
30
|
areaType: null,
|
|
31
31
|
},
|
|
@@ -37,7 +37,7 @@ export function getSupportedAreas(rooms, roomMap, log) {
|
|
|
37
37
|
return duplicated
|
|
38
38
|
? [
|
|
39
39
|
{
|
|
40
|
-
areaId:
|
|
40
|
+
areaId: 2,
|
|
41
41
|
mapId: null,
|
|
42
42
|
areaInfo: {
|
|
43
43
|
locationInfo: {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { getSupportedCleanModesA187 } from '../behaviors/roborock.vacuum/QREVO_EDGE_5V1/initalData.js';
|
|
2
2
|
import { getDefaultSupportedCleanModes } from '../behaviors/roborock.vacuum/default/initalData.js';
|
|
3
3
|
import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
|
|
4
|
+
import { getSupportedCleanModesA27 } from '../behaviors/roborock.vacuum/S7_MAXV/initalData.js';
|
|
4
5
|
export function getSupportedCleanModes(model) {
|
|
5
6
|
switch (model) {
|
|
6
7
|
case DeviceModel.QREVO_EDGE_5V1:
|
|
7
8
|
return getSupportedCleanModesA187();
|
|
9
|
+
case DeviceModel.S7_MAXV:
|
|
10
|
+
return getSupportedCleanModesA27();
|
|
8
11
|
default:
|
|
9
12
|
return getDefaultSupportedCleanModes();
|
|
10
13
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getSupportedRunModesA187 } from '../behaviors/roborock.vacuum/QREVO_EDGE_5V1/initalData.js';
|
|
2
2
|
import { getDefaultSupportedRunModes } from '../behaviors/roborock.vacuum/default/initalData.js';
|
|
3
3
|
import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
|
|
4
|
+
import { getSupportedRunModesA27 } from '../behaviors/roborock.vacuum/S7_MAXV/initalData.js';
|
|
4
5
|
export function getRunningMode(model, modeTag) {
|
|
5
6
|
if (!model || !modeTag)
|
|
6
7
|
return null;
|
|
@@ -12,6 +13,8 @@ export function getSupportedRunModes(model) {
|
|
|
12
13
|
switch (model) {
|
|
13
14
|
case DeviceModel.QREVO_EDGE_5V1:
|
|
14
15
|
return getSupportedRunModesA187();
|
|
16
|
+
case DeviceModel.S7_MAXV:
|
|
17
|
+
return getSupportedRunModesA27();
|
|
15
18
|
default:
|
|
16
19
|
return getDefaultSupportedRunModes();
|
|
17
20
|
}
|
package/dist/model/RoomMap.js
CHANGED
package/dist/platform.js
CHANGED
|
@@ -73,13 +73,14 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
73
73
|
let vacuum = undefined;
|
|
74
74
|
if (this.config.whiteList.length > 0) {
|
|
75
75
|
const firstDUID = this.config.whiteList[0];
|
|
76
|
-
|
|
76
|
+
const duid = firstDUID.split('-')[1];
|
|
77
|
+
vacuum = devices.find((d) => d.duid == duid);
|
|
77
78
|
}
|
|
78
79
|
else {
|
|
79
80
|
vacuum = devices.find((d) => isSupportedDevice(d.data.model));
|
|
80
81
|
}
|
|
81
82
|
if (!vacuum) {
|
|
82
|
-
this.log.error('Initializing: No
|
|
83
|
+
this.log.error('Initializing: No device found');
|
|
83
84
|
return;
|
|
84
85
|
}
|
|
85
86
|
await this.roborockService.initializeMessageClient(username, vacuum, userData);
|
package/dist/rvc.js
CHANGED
|
@@ -10,7 +10,8 @@ export class RoborockVacuumCleaner extends RoboticVacuumCleaner {
|
|
|
10
10
|
const cleanModes = getSupportedCleanModes(device.data.model);
|
|
11
11
|
const supportedRunModes = getSupportedRunModes(device.data.model);
|
|
12
12
|
const supportedAreas = getSupportedAreas(device.rooms, roomMap, log);
|
|
13
|
-
|
|
13
|
+
const deviceName = `${device.name}-${device.duid}`.replace(/\s+/g, '');
|
|
14
|
+
super(deviceName, device.duid, supportedRunModes[0].mode, supportedRunModes, cleanModes[0].mode, cleanModes, undefined, undefined, RvcOperationalState.OperationalState.Docked, getOperationalStates(device.data.model), supportedAreas, undefined, supportedAreas[0].areaId);
|
|
14
15
|
this.username = username;
|
|
15
16
|
this.device = device;
|
|
16
17
|
this.rrHomeId = device.rrHomeId;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { getCurrentCleanModeA187, getCurrentCleanModeFromFanPowerA187, getCurrentCleanModeFromWaterBoxModeA187 } from '../behaviors/roborock.vacuum/QREVO_EDGE_5V1/runtimes.js';
|
|
2
|
+
import { getCurrentCleanModeA27, getCurrentCleanModeFromFanPowerA27, getCurrentCleanModeFromWaterBoxModeA27 } from '../behaviors/roborock.vacuum/S7_MAXV/runtimes.js';
|
|
2
3
|
import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
|
|
3
4
|
export function getCurrentCleanModeFunc(model) {
|
|
4
5
|
switch (model) {
|
|
5
6
|
case DeviceModel.QREVO_EDGE_5V1: {
|
|
6
7
|
return getCurrentCleanModeA187;
|
|
7
8
|
}
|
|
9
|
+
case DeviceModel.S7_MAXV: {
|
|
10
|
+
return getCurrentCleanModeA27;
|
|
11
|
+
}
|
|
8
12
|
default:
|
|
9
13
|
return (_, __) => undefined;
|
|
10
14
|
}
|
|
@@ -14,6 +18,9 @@ export function getCurrentCleanModeFromFanPowerFunc(model) {
|
|
|
14
18
|
case DeviceModel.QREVO_EDGE_5V1: {
|
|
15
19
|
return getCurrentCleanModeFromFanPowerA187;
|
|
16
20
|
}
|
|
21
|
+
case DeviceModel.S7_MAXV: {
|
|
22
|
+
return getCurrentCleanModeFromFanPowerA27;
|
|
23
|
+
}
|
|
17
24
|
default:
|
|
18
25
|
return (_) => undefined;
|
|
19
26
|
}
|
|
@@ -23,6 +30,9 @@ export function getCurrentCleanModeFromWaterBoxModeFunc(model) {
|
|
|
23
30
|
case DeviceModel.QREVO_EDGE_5V1: {
|
|
24
31
|
return getCurrentCleanModeFromWaterBoxModeA187;
|
|
25
32
|
}
|
|
33
|
+
case DeviceModel.S7_MAXV: {
|
|
34
|
+
return getCurrentCleanModeFromWaterBoxModeA27;
|
|
35
|
+
}
|
|
26
36
|
default:
|
|
27
37
|
return (_) => undefined;
|
|
28
38
|
}
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
testEnvironment: 'node',
|
|
3
|
+
extensionsToTreatAsEsm: ['.ts'],
|
|
4
|
+
moduleNameMapper: {
|
|
5
|
+
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
6
|
+
},
|
|
7
|
+
transform: {
|
|
8
|
+
'^.+\\.ts$': [
|
|
9
|
+
'ts-jest',
|
|
10
|
+
{
|
|
11
|
+
useESM: true,
|
|
12
|
+
tsconfig: 'tsconfig.jest.json',
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
transformIgnorePatterns: ['/node_modules/'],
|
|
17
|
+
testPathIgnorePatterns: ['/node_modules/', '/dist/', '/frontend/'],
|
|
18
|
+
coveragePathIgnorePatterns: ['/node_modules/', '/dist/', '/frontend/', '/src/mock/'],
|
|
19
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
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-rc03 by https://github.com/RinDevJunior",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"required": [],
|
|
6
6
|
"properties": {
|
package/package.json
CHANGED
package/src/behaviorFactory.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { EndpointCommandsA187, setCommandHandlerA187 } from './behaviors/roboroc
|
|
|
4
4
|
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
|
+
import { EndpointCommandsA27, setCommandHandlerA27 } from './behaviors/roborock.vacuum/S7_MAXV/a27.js';
|
|
7
8
|
|
|
8
9
|
export type BehaviorFactoryResult = BehaviorDeviceGeneric<DefaultEndpointCommands> | BehaviorDeviceGeneric<EndpointCommandsA187>;
|
|
9
10
|
|
|
@@ -15,6 +16,12 @@ export function configurateBehavior(model: string, duid: string, roborockService
|
|
|
15
16
|
return deviceHandler;
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
case DeviceModel.S7_MAXV: {
|
|
20
|
+
const deviceHandler = new BehaviorDeviceGeneric<EndpointCommandsA27>(logger);
|
|
21
|
+
setCommandHandlerA27(duid, deviceHandler, logger, roborockService);
|
|
22
|
+
return deviceHandler;
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
default: {
|
|
19
26
|
const deviceHandler = new BehaviorDeviceGeneric<DefaultEndpointCommands>(logger);
|
|
20
27
|
setDefaultCommandHandler(duid, deviceHandler, logger, roborockService);
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { MaybePromise } from 'matterbridge/matter';
|
|
2
|
+
import { AnsiLogger, debugStringify } from 'matterbridge/logger';
|
|
3
|
+
import { BehaviorDeviceGeneric, BehaviorRoborock, DeviceCommands } from '../../BehaviorDeviceGeneric.js';
|
|
4
|
+
import RoborockService from '../../../roborockService.js';
|
|
5
|
+
|
|
6
|
+
export interface EndpointCommandsA27 extends DeviceCommands {
|
|
7
|
+
selectAreas: (newAreas: any) => MaybePromise;
|
|
8
|
+
changeToMode: (newMode: number) => MaybePromise;
|
|
9
|
+
pause: () => MaybePromise;
|
|
10
|
+
resume: () => MaybePromise;
|
|
11
|
+
goHome: () => MaybePromise;
|
|
12
|
+
PlaySoundToLocate: (identifyTime: number) => MaybePromise;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class BehaviorA27 extends BehaviorRoborock {
|
|
16
|
+
declare state: BehaviorRoborockA27.State;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export namespace BehaviorRoborockA27 {
|
|
20
|
+
export class State {
|
|
21
|
+
device!: BehaviorDeviceGeneric<EndpointCommandsA27>;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//suction_power
|
|
26
|
+
export enum VacuumSuctionPowerA27 {
|
|
27
|
+
Quiet = 101,
|
|
28
|
+
Balanced = 102,
|
|
29
|
+
Turbo = 103,
|
|
30
|
+
Max = 104,
|
|
31
|
+
Off = 105,
|
|
32
|
+
Custom = 106,
|
|
33
|
+
MaxPlus = 108,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//water_box_mode
|
|
37
|
+
export enum MopWaterFlowA27 {
|
|
38
|
+
Off = 200,
|
|
39
|
+
Low = 201,
|
|
40
|
+
Medium = 202,
|
|
41
|
+
High = 203,
|
|
42
|
+
Custom = 204,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//set_mop_mode
|
|
46
|
+
export enum MopRouteA27 {
|
|
47
|
+
Standard = 300,
|
|
48
|
+
Deep = 301,
|
|
49
|
+
Custom = 302,
|
|
50
|
+
DeepPlus = 303,
|
|
51
|
+
Fast = 304,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const RvcRunMode: Record<number, string> = {
|
|
55
|
+
[1]: 'Idle', //DO NOT HANDLE HERE,
|
|
56
|
+
[2]: 'Cleaning',
|
|
57
|
+
[3]: 'Mapping',
|
|
58
|
+
};
|
|
59
|
+
const RvcCleanMode: Record<number, string> = {
|
|
60
|
+
[5]: 'Mop',
|
|
61
|
+
[6]: 'Vacuum',
|
|
62
|
+
[7]: 'Vac & Mop',
|
|
63
|
+
[8]: 'Custom',
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const CleanSetting: Record<number, { suctionPower: number; waterFlow: number; mopRoute: number }> = {
|
|
67
|
+
[5]: { suctionPower: VacuumSuctionPowerA27.Off, waterFlow: MopWaterFlowA27.Medium, mopRoute: MopRouteA27.Custom }, //'Mop'
|
|
68
|
+
[6]: { suctionPower: VacuumSuctionPowerA27.Balanced, waterFlow: MopWaterFlowA27.Off, mopRoute: MopRouteA27.Custom }, //'Vacuum'
|
|
69
|
+
[7]: { suctionPower: VacuumSuctionPowerA27.Balanced, waterFlow: MopWaterFlowA27.Medium, mopRoute: MopRouteA27.Custom }, //'Vac & Mop'
|
|
70
|
+
[8]: { suctionPower: VacuumSuctionPowerA27.Custom, waterFlow: MopWaterFlowA27.Custom, mopRoute: MopRouteA27.Custom }, // 'Custom'
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export function setCommandHandlerA27(duid: string, handler: BehaviorDeviceGeneric<DeviceCommands>, logger: AnsiLogger, roborockService: RoborockService): void {
|
|
74
|
+
handler.setCommandHandler('changeToMode', async (newMode: number) => {
|
|
75
|
+
const activity = RvcRunMode[newMode] || RvcCleanMode[newMode];
|
|
76
|
+
switch (activity) {
|
|
77
|
+
case 'Cleaning': {
|
|
78
|
+
logger.notice('BehaviorA27-ChangeRunMode to: ', activity);
|
|
79
|
+
await roborockService.startClean(duid);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
case 'Mop':
|
|
83
|
+
case 'Vacuum':
|
|
84
|
+
case 'Vac & Mop':
|
|
85
|
+
case 'Custom': {
|
|
86
|
+
const setting = CleanSetting[newMode];
|
|
87
|
+
logger.notice(`BehaviorA27-ChangeCleanMode to: ${activity}, code: ${debugStringify(setting)}`);
|
|
88
|
+
//await roborockService.changeCleanMode(duid, setting);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
default:
|
|
92
|
+
logger.notice('BehaviorA27-changeToMode-Unknown: ', newMode);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
handler.setCommandHandler('selectAreas', async (newAreas: number[]) => {
|
|
98
|
+
logger.notice(`BehaviorA27-selectAreas: ${newAreas}`);
|
|
99
|
+
roborockService.setSelectedAreas(duid, newAreas ?? []);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
handler.setCommandHandler('pause', async () => {
|
|
103
|
+
logger.notice('BehaviorA27-Pause');
|
|
104
|
+
await roborockService.pauseClean(duid);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
handler.setCommandHandler('resume', async () => {
|
|
108
|
+
logger.notice('BehaviorA27-Resume');
|
|
109
|
+
await roborockService.resumeClean(duid);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
handler.setCommandHandler('goHome', async () => {
|
|
113
|
+
logger.notice('BehaviorA27-GoHome');
|
|
114
|
+
await roborockService.stopAndGoHome(duid);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
handler.setCommandHandler('PlaySoundToLocate', async (identifyTime: number) => {
|
|
118
|
+
logger.notice('BehaviorA27-PlaySoundToLocate');
|
|
119
|
+
await roborockService.playSoundToLocate(duid);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { RvcCleanMode, RvcOperationalState, RvcRunMode } from 'matterbridge/matter/clusters';
|
|
2
|
+
|
|
3
|
+
export function getSupportedRunModesA27(): RvcRunMode.ModeOption[] {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
label: 'Idle',
|
|
7
|
+
mode: 1,
|
|
8
|
+
modeTags: [{ value: RvcRunMode.ModeTag.Idle }],
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
label: 'Cleaning',
|
|
12
|
+
mode: 2,
|
|
13
|
+
modeTags: [{ value: RvcRunMode.ModeTag.Cleaning }],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
label: 'Mapping',
|
|
17
|
+
mode: 3,
|
|
18
|
+
modeTags: [{ value: RvcRunMode.ModeTag.Mapping }],
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getSupportedCleanModesA27(): RvcCleanMode.ModeOption[] {
|
|
24
|
+
return [
|
|
25
|
+
{
|
|
26
|
+
label: 'Mop',
|
|
27
|
+
mode: 5,
|
|
28
|
+
modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Auto }],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
label: 'Vacuum',
|
|
32
|
+
mode: 6,
|
|
33
|
+
modeTags: [{ value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Auto }],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: 'Mop & Vacuum',
|
|
37
|
+
mode: 7,
|
|
38
|
+
modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.DeepClean }],
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
{
|
|
42
|
+
label: 'Custom',
|
|
43
|
+
mode: 8,
|
|
44
|
+
modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Quick }],
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getOperationalStatesA27(): RvcOperationalState.OperationalStateStruct[] {
|
|
50
|
+
return [
|
|
51
|
+
{
|
|
52
|
+
operationalStateId: RvcOperationalState.OperationalState.Stopped,
|
|
53
|
+
operationalStateLabel: 'Stopped',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
operationalStateId: RvcOperationalState.OperationalState.Running,
|
|
57
|
+
operationalStateLabel: 'Running',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
operationalStateId: RvcOperationalState.OperationalState.Paused,
|
|
61
|
+
operationalStateLabel: 'Paused',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
operationalStateId: RvcOperationalState.OperationalState.Error,
|
|
65
|
+
operationalStateLabel: 'Error',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
operationalStateId: RvcOperationalState.OperationalState.SeekingCharger,
|
|
69
|
+
operationalStateLabel: 'SeekingCharger',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
operationalStateId: RvcOperationalState.OperationalState.Charging,
|
|
73
|
+
operationalStateLabel: 'Charging',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
operationalStateId: RvcOperationalState.OperationalState.Docked,
|
|
77
|
+
operationalStateLabel: 'Docked',
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { MopWaterFlowA27, VacuumSuctionPowerA27 } from './a27.js';
|
|
2
|
+
|
|
3
|
+
export function getCurrentCleanModeA27(fan_power: number | undefined, water_box_mode: number | undefined): number | undefined {
|
|
4
|
+
if (!fan_power || !water_box_mode) return undefined;
|
|
5
|
+
if (fan_power == VacuumSuctionPowerA27.Custom || water_box_mode == MopWaterFlowA27.Custom) return 8; // 'Custom',
|
|
6
|
+
if (fan_power == VacuumSuctionPowerA27.Off) return 5; // 'Mop',
|
|
7
|
+
if (water_box_mode == MopWaterFlowA27.Off)
|
|
8
|
+
return 6; // 'Vacuum',
|
|
9
|
+
else return 7; //Vac & Mop
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getCurrentCleanModeFromFanPowerA27(fan_power: number | undefined): number | undefined {
|
|
13
|
+
if (!fan_power) return undefined;
|
|
14
|
+
if (fan_power == VacuumSuctionPowerA27.Custom) return 8; // 'Custom',
|
|
15
|
+
if (fan_power == VacuumSuctionPowerA27.Off)
|
|
16
|
+
return 5; // 'Mop',
|
|
17
|
+
else return undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getCurrentCleanModeFromWaterBoxModeA27(water_box_mode: number | undefined): number | undefined {
|
|
21
|
+
if (!water_box_mode) return undefined;
|
|
22
|
+
if (water_box_mode == MopWaterFlowA27.Custom) return 8; // 'Custom',
|
|
23
|
+
if (water_box_mode == MopWaterFlowA27.Off)
|
|
24
|
+
return 6; // 'Vacuum',
|
|
25
|
+
else return undefined;
|
|
26
|
+
}
|
|
@@ -3,11 +3,14 @@ import { getOperationalStatesA187 } from '../behaviors/roborock.vacuum/QREVO_EDG
|
|
|
3
3
|
import { getDefaultOperationalStates } from '../behaviors/roborock.vacuum/default/initalData.js';
|
|
4
4
|
import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
|
|
5
5
|
import { VacuumErrorCode } from '../roborockCommunication/Zenum/vacuumAndDockErrorCode.js';
|
|
6
|
+
import { getOperationalStatesA27 } from '../behaviors/roborock.vacuum/S7_MAXV/initalData.js';
|
|
6
7
|
|
|
7
8
|
export function getOperationalStates(model: string): RvcOperationalState.OperationalStateStruct[] {
|
|
8
9
|
switch (model) {
|
|
9
10
|
case DeviceModel.QREVO_EDGE_5V1:
|
|
10
11
|
return getOperationalStatesA187();
|
|
12
|
+
case DeviceModel.S7_MAXV:
|
|
13
|
+
return getOperationalStatesA27();
|
|
11
14
|
default:
|
|
12
15
|
return getDefaultOperationalStates();
|
|
13
16
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getSupportedAreas } from '../initialData/getSupportedAreas';
|
|
2
|
+
import RoomMap from '../model/RoomMap';
|
|
3
|
+
import { jest } from '@jest/globals';
|
|
4
|
+
|
|
5
|
+
const mockLogger = {
|
|
6
|
+
debug: jest.fn(),
|
|
7
|
+
error: jest.fn(),
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
describe('getSupportedAreas', () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
jest.clearAllMocks();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('returns default area when rooms and roomMap are empty', () => {
|
|
16
|
+
const result = getSupportedAreas(
|
|
17
|
+
[
|
|
18
|
+
{ id: 2775739, name: 'Garage' },
|
|
19
|
+
{ id: 1474466, name: 'Outside' },
|
|
20
|
+
{ id: 1459590, name: 'AAA room' },
|
|
21
|
+
{ id: 1459587, name: 'BBB’s Room' },
|
|
22
|
+
{ id: 1459580, name: 'CCC’s room' },
|
|
23
|
+
{ id: 1458155, name: 'Dining room' },
|
|
24
|
+
{ id: 1457889, name: 'Bathroom' },
|
|
25
|
+
{ id: 1457888, name: 'Living room' },
|
|
26
|
+
{ id: 991195, name: 'Downstairs Bathroom' },
|
|
27
|
+
{ id: 991190, name: 'Garage Entryway' },
|
|
28
|
+
{ id: 991187, name: 'TV Room' },
|
|
29
|
+
{ id: 991185, name: 'Bedroom' },
|
|
30
|
+
{ id: 612205, name: 'DDD’s Room' },
|
|
31
|
+
{ id: 612204, name: 'Upstairs Bathroom' },
|
|
32
|
+
{ id: 612202, name: 'Hallway' },
|
|
33
|
+
{ id: 612200, name: 'EEE Room' },
|
|
34
|
+
{ id: 609148, name: 'Dining Room' },
|
|
35
|
+
{ id: 609146, name: 'Kitchen' },
|
|
36
|
+
{ id: 609145, name: 'Living Room' },
|
|
37
|
+
],
|
|
38
|
+
{
|
|
39
|
+
rooms: [
|
|
40
|
+
{ id: 16, globalId: 609146, displayName: 'Kitchen' },
|
|
41
|
+
{ id: 17, globalId: 1457889, displayName: 'Bathroom' },
|
|
42
|
+
{ id: 18, globalId: 612202, displayName: 'Hallway' },
|
|
43
|
+
{ id: 19, globalId: 1458155, displayName: 'Dining room' },
|
|
44
|
+
{ id: 20, globalId: 1457888, displayName: 'Living room' },
|
|
45
|
+
{ id: 21, globalId: 1459580, displayName: 'BBB’s room' },
|
|
46
|
+
{ id: 22, globalId: 612205, displayName: 'CCC’s Room' },
|
|
47
|
+
{ id: 23, globalId: 1474466, displayName: 'Outside' },
|
|
48
|
+
],
|
|
49
|
+
} as RoomMap,
|
|
50
|
+
mockLogger as any,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
expect(result.length).toEqual(8);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -3,23 +3,6 @@ import { ServiceArea } from 'matterbridge/matter/clusters';
|
|
|
3
3
|
import RoomMap from '../model/RoomMap.js';
|
|
4
4
|
import { Room } from '../roborockCommunication/Zmodel/room.js';
|
|
5
5
|
|
|
6
|
-
/*
|
|
7
|
-
rooms = [
|
|
8
|
-
{ id: 123456, name: 'Study' },
|
|
9
|
-
{ id: 123457, name: 'Bedroom' },
|
|
10
|
-
{ id: 123458, name: 'Kitchen' },
|
|
11
|
-
{ id: 123459, name: 'Living room' }
|
|
12
|
-
]
|
|
13
|
-
roomMap = {
|
|
14
|
-
rooms: [
|
|
15
|
-
{ id: 1, globalId: "123456", displayName: undefined },
|
|
16
|
-
{ id: 2, globalId: "123457", displayName: undefined },
|
|
17
|
-
{ id: 3, globalId: "123458", displayName: undefined },
|
|
18
|
-
{ id: 4, globalId: "123459", displayName: undefined },
|
|
19
|
-
],
|
|
20
|
-
};
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
6
|
export function getSupportedAreas(rooms: Room[], roomMap: RoomMap | undefined, log?: AnsiLogger): ServiceArea.Area[] {
|
|
24
7
|
log?.debug('getSupportedAreas', debugStringify(rooms));
|
|
25
8
|
log?.debug('getSupportedAreas', roomMap ? debugStringify(roomMap) : 'undefined');
|
|
@@ -42,13 +25,13 @@ export function getSupportedAreas(rooms: Room[], roomMap: RoomMap | undefined, l
|
|
|
42
25
|
];
|
|
43
26
|
}
|
|
44
27
|
|
|
45
|
-
const supportedAreas: ServiceArea.Area[] = rooms.map((room, index) => {
|
|
28
|
+
const supportedAreas: ServiceArea.Area[] = roomMap.rooms.map((room, index) => {
|
|
46
29
|
return {
|
|
47
|
-
areaId:
|
|
30
|
+
areaId: room.id,
|
|
48
31
|
mapId: null,
|
|
49
32
|
areaInfo: {
|
|
50
33
|
locationInfo: {
|
|
51
|
-
locationName: room.name,
|
|
34
|
+
locationName: room.displayName ?? rooms.find((r) => r.id == room.globalId)?.name ?? 'Unknown Room',
|
|
52
35
|
floorNumber: null,
|
|
53
36
|
areaType: null,
|
|
54
37
|
},
|
|
@@ -62,7 +45,7 @@ export function getSupportedAreas(rooms: Room[], roomMap: RoomMap | undefined, l
|
|
|
62
45
|
return duplicated
|
|
63
46
|
? [
|
|
64
47
|
{
|
|
65
|
-
areaId:
|
|
48
|
+
areaId: 2,
|
|
66
49
|
mapId: null,
|
|
67
50
|
areaInfo: {
|
|
68
51
|
locationInfo: {
|
|
@@ -2,11 +2,14 @@ import { RvcCleanMode } from 'matterbridge/matter/clusters';
|
|
|
2
2
|
import { getSupportedCleanModesA187 } from '../behaviors/roborock.vacuum/QREVO_EDGE_5V1/initalData.js';
|
|
3
3
|
import { getDefaultSupportedCleanModes } from '../behaviors/roborock.vacuum/default/initalData.js';
|
|
4
4
|
import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
|
|
5
|
+
import { getSupportedCleanModesA27 } from '../behaviors/roborock.vacuum/S7_MAXV/initalData.js';
|
|
5
6
|
|
|
6
7
|
export function getSupportedCleanModes(model: string): RvcCleanMode.ModeOption[] {
|
|
7
8
|
switch (model) {
|
|
8
9
|
case DeviceModel.QREVO_EDGE_5V1:
|
|
9
10
|
return getSupportedCleanModesA187();
|
|
11
|
+
case DeviceModel.S7_MAXV:
|
|
12
|
+
return getSupportedCleanModesA27();
|
|
10
13
|
default:
|
|
11
14
|
return getDefaultSupportedCleanModes();
|
|
12
15
|
}
|
|
@@ -2,6 +2,7 @@ import { RvcRunMode } from 'matterbridge/matter/clusters';
|
|
|
2
2
|
import { getSupportedRunModesA187 } from '../behaviors/roborock.vacuum/QREVO_EDGE_5V1/initalData.js';
|
|
3
3
|
import { getDefaultSupportedRunModes } from '../behaviors/roborock.vacuum/default/initalData.js';
|
|
4
4
|
import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
|
|
5
|
+
import { getSupportedRunModesA27 } from '../behaviors/roborock.vacuum/S7_MAXV/initalData.js';
|
|
5
6
|
|
|
6
7
|
export function getRunningMode(model: string | undefined, modeTag: RvcRunMode.ModeTag | undefined): number | null {
|
|
7
8
|
if (!model || !modeTag) return null;
|
|
@@ -15,6 +16,8 @@ export function getSupportedRunModes(model: string): RvcRunMode.ModeOption[] {
|
|
|
15
16
|
switch (model) {
|
|
16
17
|
case DeviceModel.QREVO_EDGE_5V1:
|
|
17
18
|
return getSupportedRunModesA187();
|
|
19
|
+
case DeviceModel.S7_MAXV:
|
|
20
|
+
return getSupportedRunModesA27();
|
|
18
21
|
default:
|
|
19
22
|
return getDefaultSupportedRunModes();
|
|
20
23
|
}
|
package/src/model/RoomMap.ts
CHANGED
|
@@ -34,11 +34,11 @@ export default class RoomMap {
|
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
getGlobalId(id: number): number | undefined {
|
|
38
|
-
|
|
39
|
-
}
|
|
37
|
+
// getGlobalId(id: number): number | undefined {
|
|
38
|
+
// return this.rooms.find((r) => Number(r.id) == Number(id))?.globalId;
|
|
39
|
+
// }
|
|
40
40
|
|
|
41
|
-
getRoomId(globalId: number): number | undefined {
|
|
42
|
-
|
|
43
|
-
}
|
|
41
|
+
// getRoomId(globalId: number): number | undefined {
|
|
42
|
+
// return this.rooms.find((r) => Number(r.globalId) == Number(globalId))?.id;
|
|
43
|
+
// }
|
|
44
44
|
}
|
package/src/platform.ts
CHANGED
|
@@ -97,13 +97,14 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
97
97
|
let vacuum: Device | undefined = undefined;
|
|
98
98
|
if ((this.config.whiteList as string[]).length > 0) {
|
|
99
99
|
const firstDUID = (this.config.whiteList as string[])[0];
|
|
100
|
-
|
|
100
|
+
const duid = firstDUID.split('-')[1];
|
|
101
|
+
vacuum = devices.find((d) => d.duid == duid);
|
|
101
102
|
} else {
|
|
102
103
|
vacuum = devices.find((d) => isSupportedDevice(d.data.model));
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
if (!vacuum) {
|
|
106
|
-
this.log.error('Initializing: No
|
|
107
|
+
this.log.error('Initializing: No device found');
|
|
107
108
|
return;
|
|
108
109
|
}
|
|
109
110
|
await this.roborockService.initializeMessageClient(username, vacuum, userData);
|
package/src/rvc.ts
CHANGED
|
@@ -16,8 +16,9 @@ export class RoborockVacuumCleaner extends RoboticVacuumCleaner {
|
|
|
16
16
|
const cleanModes = getSupportedCleanModes(device.data.model);
|
|
17
17
|
const supportedRunModes = getSupportedRunModes(device.data.model);
|
|
18
18
|
const supportedAreas = getSupportedAreas(device.rooms, roomMap, log);
|
|
19
|
+
const deviceName = `${device.name}-${device.duid}`.replace(/\s+/g, '');
|
|
19
20
|
super(
|
|
20
|
-
|
|
21
|
+
deviceName, //name
|
|
21
22
|
device.duid, //serial
|
|
22
23
|
supportedRunModes[0].mode, //currentRunMode
|
|
23
24
|
supportedRunModes, //supportedRunModes
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getCurrentCleanModeA187, getCurrentCleanModeFromFanPowerA187, getCurrentCleanModeFromWaterBoxModeA187 } from '../behaviors/roborock.vacuum/QREVO_EDGE_5V1/runtimes.js';
|
|
2
|
+
import { getCurrentCleanModeA27, getCurrentCleanModeFromFanPowerA27, getCurrentCleanModeFromWaterBoxModeA27 } from '../behaviors/roborock.vacuum/S7_MAXV/runtimes.js';
|
|
2
3
|
import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
|
|
3
4
|
|
|
4
5
|
export type CleanModeFunc1 = (fan_power: number | undefined, water_box_mode: number | undefined) => number | undefined;
|
|
@@ -9,6 +10,9 @@ export function getCurrentCleanModeFunc(model: string): CleanModeFunc1 {
|
|
|
9
10
|
case DeviceModel.QREVO_EDGE_5V1: {
|
|
10
11
|
return getCurrentCleanModeA187;
|
|
11
12
|
}
|
|
13
|
+
case DeviceModel.S7_MAXV: {
|
|
14
|
+
return getCurrentCleanModeA27;
|
|
15
|
+
}
|
|
12
16
|
default:
|
|
13
17
|
return (_, __) => undefined;
|
|
14
18
|
}
|
|
@@ -19,6 +23,9 @@ export function getCurrentCleanModeFromFanPowerFunc(model: string): CleanModeFun
|
|
|
19
23
|
case DeviceModel.QREVO_EDGE_5V1: {
|
|
20
24
|
return getCurrentCleanModeFromFanPowerA187;
|
|
21
25
|
}
|
|
26
|
+
case DeviceModel.S7_MAXV: {
|
|
27
|
+
return getCurrentCleanModeFromFanPowerA27;
|
|
28
|
+
}
|
|
22
29
|
default:
|
|
23
30
|
return (_) => undefined;
|
|
24
31
|
}
|
|
@@ -29,6 +36,9 @@ export function getCurrentCleanModeFromWaterBoxModeFunc(model: string): CleanMod
|
|
|
29
36
|
case DeviceModel.QREVO_EDGE_5V1: {
|
|
30
37
|
return getCurrentCleanModeFromWaterBoxModeA187;
|
|
31
38
|
}
|
|
39
|
+
case DeviceModel.S7_MAXV: {
|
|
40
|
+
return getCurrentCleanModeFromWaterBoxModeA27;
|
|
41
|
+
}
|
|
32
42
|
default:
|
|
33
43
|
return (_) => undefined;
|
|
34
44
|
}
|