matterbridge-roborock-vacuum-plugin 1.0.7 → 1.0.8-rc02

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.
Files changed (77) hide show
  1. package/.github/workflows/publish.yml +4 -1
  2. package/README.md +2 -0
  3. package/README_SUPPORTED.md +54 -0
  4. package/dist/behaviorFactory.js +8 -2
  5. package/dist/behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.js +3 -3
  6. package/dist/behaviors/roborock.vacuum/S7_MAXV/a27.js +50 -7
  7. package/dist/behaviors/roborock.vacuum/S8_PRO_ULTRA/a51.js +139 -0
  8. package/dist/behaviors/roborock.vacuum/S8_PRO_ULTRA/initalData.js +76 -0
  9. package/dist/behaviors/roborock.vacuum/S8_PRO_ULTRA/runtimes.js +33 -0
  10. package/dist/behaviors/roborock.vacuum/default/default.js +86 -5
  11. package/dist/behaviors/roborock.vacuum/default/initalData.js +15 -5
  12. package/dist/behaviors/roborock.vacuum/default/runtimes.js +33 -0
  13. package/dist/initialData/getSupportedScenes.js +26 -0
  14. package/dist/initialData/index.js +1 -0
  15. package/dist/model/ExperimentalFeatureSetting.js +1 -0
  16. package/dist/platform.js +16 -12
  17. package/dist/platformRunner.js +4 -3
  18. package/dist/roborockCommunication/RESTAPI/roborockIoTApi.js +14 -3
  19. package/dist/roborockCommunication/Zmodel/scene.js +16 -0
  20. package/dist/roborockCommunication/broadcast/abstractClient.js +2 -2
  21. package/dist/roborockCommunication/broadcast/client/LocalNetworkClient.js +7 -7
  22. package/dist/roborockCommunication/broadcast/client/MQTTClient.js +1 -1
  23. package/dist/roborockCommunication/broadcast/messageProcessor.js +15 -6
  24. package/dist/roborockCommunication/helper/messageDeserializer.js +13 -8
  25. package/dist/roborockCommunication/helper/messageSerializer.js +3 -1
  26. package/dist/roborockCommunication/index.js +1 -0
  27. package/dist/roborockService.js +58 -19
  28. package/dist/rvc.js +2 -2
  29. package/dist/share/function.js +6 -6
  30. package/dist/share/runtimeHelper.js +14 -3
  31. package/jest.config.js +2 -0
  32. package/jest.setup.js +2 -0
  33. package/matterbridge-roborock-vacuum-plugin.config.json +2 -2
  34. package/matterbridge-roborock-vacuum-plugin.schema.json +181 -104
  35. package/package.json +1 -1
  36. package/src/behaviorFactory.ts +10 -3
  37. package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.ts +5 -5
  38. package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/runtimes.test.ts +79 -0
  39. package/src/behaviors/roborock.vacuum/S7_MAXV/a27.test.ts +134 -0
  40. package/src/behaviors/roborock.vacuum/S7_MAXV/a27.ts +62 -9
  41. package/src/behaviors/roborock.vacuum/S7_MAXV/initalData.ts +0 -1
  42. package/src/behaviors/roborock.vacuum/S8_PRO_ULTRA/a51.ts +173 -0
  43. package/src/behaviors/roborock.vacuum/S8_PRO_ULTRA/initalData.ts +79 -0
  44. package/src/behaviors/roborock.vacuum/S8_PRO_ULTRA/runtimes.ts +26 -0
  45. package/src/behaviors/roborock.vacuum/default/default.ts +101 -6
  46. package/src/behaviors/roborock.vacuum/default/initalData.ts +15 -5
  47. package/src/behaviors/roborock.vacuum/default/runtimes.ts +26 -0
  48. package/src/initialData/getSupportedScenes.ts +32 -0
  49. package/src/initialData/index.ts +1 -0
  50. package/src/model/ExperimentalFeatureSetting.ts +26 -0
  51. package/src/platform.ts +21 -15
  52. package/src/platformRunner.ts +6 -4
  53. package/src/roborockCommunication/RESTAPI/roborockIoTApi.ts +20 -7
  54. package/src/roborockCommunication/Zmodel/device.ts +3 -0
  55. package/src/roborockCommunication/Zmodel/scene.ts +42 -0
  56. package/src/roborockCommunication/broadcast/abstractClient.ts +2 -2
  57. package/src/roborockCommunication/broadcast/client/LocalNetworkClient.ts +9 -8
  58. package/src/roborockCommunication/broadcast/client/MQTTClient.ts +1 -1
  59. package/src/roborockCommunication/broadcast/listener/index.ts +2 -2
  60. package/src/roborockCommunication/broadcast/messageProcessor.ts +15 -9
  61. package/src/roborockCommunication/helper/messageDeserializer.ts +17 -12
  62. package/src/roborockCommunication/helper/messageSerializer.ts +4 -1
  63. package/src/roborockCommunication/index.ts +10 -6
  64. package/src/roborockService.ts +74 -23
  65. package/src/rvc.ts +2 -2
  66. package/src/share/function.ts +6 -6
  67. package/src/share/runtimeHelper.ts +14 -3
  68. package/src/{behaviors → tests/behaviors}/roborock.vacuum/QREVO_EDGE_5V1/a187.test.ts +7 -6
  69. package/src/tests/behaviors/roborock.vacuum/QREVO_EDGE_5V1/runtimes.test.ts +83 -0
  70. package/src/tests/behaviors/roborock.vacuum/S7_MAXV/a27.test.ts +134 -0
  71. package/src/{initialData → tests/initialData}/getSupportedAreas.test.ts +2 -3
  72. package/src/tests/roborockService.test.ts +155 -0
  73. package/tsconfig.jest.json +4 -1
  74. package/dist/appliances.js +0 -6
  75. package/dist/model/CleanModeSettings.js +0 -5
  76. package/src/appliances.ts +0 -15
  77. package/src/model/CleanModeSettings.ts +0 -17
@@ -28,7 +28,10 @@ jobs:
28
28
  - name: Build (optional)
29
29
  run: npm run build
30
30
 
31
+ - name: Run tests
32
+ run: npm run test
33
+
31
34
  - name: Publish to npm
32
35
  run: npm publish
33
36
  env:
34
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
37
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md CHANGED
@@ -68,6 +68,8 @@ To get the **DUID** for your devices, you have two options:
68
68
 
69
69
  ---
70
70
 
71
+ **➡️ [See Supported & Tested Roborock Devices](./README_SUPPORTED.md)**
72
+
71
73
  ### 📦 Prerequisites
72
74
 
73
75
  - A working installation of [Matterbridge](https://github.com/Luligu/matterbridge)
@@ -0,0 +1,54 @@
1
+ # Supported & Tested Roborock Device Models
2
+
3
+ ## ✅ Tested Devices
4
+
5
+ | Device Name | Model Enum Key | Model String | Thank |
6
+ |----------------------------|------------------------|-------------------------------|------------------|
7
+ | Roborock Qrevo Edge 5V1 | `QREVO_EDGE_5V1` | `roborock.vacuum.a187` | |
8
+ | Roborock S8 Pro Ultra | `S8_PRO_ULTRA` | `roborock.vacuum.a70` | |
9
+ | Roborock S7 MaxV | `S7_MAXV` | `roborock.vacuum.a27` | |
10
+
11
+ These devices have been fully tested and are confirmed to work as expected.
12
+
13
+ ---
14
+
15
+ ## ⚠️ Other Supported Devices
16
+
17
+ All other models listed in the code are supported, but **may have some limitations**.
18
+
19
+ **Reason:**
20
+ I do not own these devices for direct testing.
21
+
22
+ If you have one of these models, please try it out and let me know your results!
23
+
24
+ ---
25
+
26
+ ### List of Other Models that I know the mode string
27
+
28
+ - Q5 (`roborock.vacuum.a34`)
29
+ - Q5_PRO (`roborock.vacuum.a72`)
30
+ - S5 (`roborock.vacuum.s5`)
31
+ - S5_MAX (`roborock.vacuum.s5e`)
32
+ - S6 (`roborock.vacuum.s6`)
33
+ - S6_MAXV (`roborock.vacuum.a10`)
34
+ - S6_PURE (`roborock.vacuum.a08`)
35
+ - Q7 (`roborock.vacuum.a40`)
36
+ - Q7_MAX (`roborock.vacuum.a38`)
37
+ - Q7_PLUS (`roborock.vacuum.a40`)
38
+ - S7 (`roborock.vacuum.a15`)
39
+ - S7_MAXV_ULTRA (`roborock.vacuum.a65`)
40
+ - S7_PRO_ULTRA (`roborock.vacuum.a62`)
41
+ - Q8_MAX (`roborock.vacuum.a73`)
42
+ - S8 (`roborock.vacuum.a51`)
43
+ - S8_MAXV_ULTRA (`roborock.vacuum.a97`)
44
+ - QREVO_MASTER (`roborock.vacuum.a117`)
45
+ - QREVO_CURV (`roborock.vacuum.a135`)
46
+ - QREVO_S (`roborock.vacuum.a104`)
47
+ - QREVO_PRO (`roborock.vacuum.a101`)
48
+ - QREVO_MAXV (`roborock.vacuum.a87`)
49
+ - QREVO_EDGE_5AE (`roborock.vacuum.xxxx`)
50
+
51
+ ---
52
+
53
+ > **Note:**
54
+ > If you have a device not listed above, feel free to try it and report your experience!
@@ -3,6 +3,7 @@ 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
+ import { setCommandHandlerA51 } from './behaviors/roborock.vacuum/S8_PRO_ULTRA/a51.js';
6
7
  export function configurateBehavior(model, duid, roborockService, cleanModeSettings, logger) {
7
8
  switch (model) {
8
9
  case DeviceModel.QREVO_EDGE_5V1: {
@@ -12,12 +13,17 @@ export function configurateBehavior(model, duid, roborockService, cleanModeSetti
12
13
  }
13
14
  case DeviceModel.S7_MAXV: {
14
15
  const deviceHandler = new BehaviorDeviceGeneric(logger);
15
- setCommandHandlerA27(duid, deviceHandler, logger, roborockService);
16
+ setCommandHandlerA27(duid, deviceHandler, logger, roborockService, cleanModeSettings);
17
+ return deviceHandler;
18
+ }
19
+ case DeviceModel.S8_PRO_ULTRA: {
20
+ const deviceHandler = new BehaviorDeviceGeneric(logger);
21
+ setCommandHandlerA51(duid, deviceHandler, logger, roborockService, cleanModeSettings);
16
22
  return deviceHandler;
17
23
  }
18
24
  default: {
19
25
  const deviceHandler = new BehaviorDeviceGeneric(logger);
20
- setDefaultCommandHandler(duid, deviceHandler, logger, roborockService);
26
+ setDefaultCommandHandler(duid, deviceHandler, logger, roborockService, cleanModeSettings);
21
27
  return deviceHandler;
22
28
  }
23
29
  }
@@ -53,9 +53,9 @@ const RvcCleanMode = {
53
53
  };
54
54
  const CleanSetting = {
55
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 },
56
+ [5]: { suctionPower: VacuumSuctionPowerA187.Off, waterFlow: MopWaterFlowA187.Medium, distance_off: 0, mopRoute: MopRouteA187.Standard },
57
+ [6]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Off, distance_off: 0, mopRoute: MopRouteA187.Standard },
58
+ [7]: { suctionPower: VacuumSuctionPowerA187.Balanced, waterFlow: MopWaterFlowA187.Medium, distance_off: 0, mopRoute: MopRouteA187.Standard },
59
59
  [8]: { suctionPower: VacuumSuctionPowerA187.Custom, waterFlow: MopWaterFlowA187.Custom, distance_off: 0, mopRoute: MopRouteA187.Custom },
60
60
  };
61
61
  export function setCommandHandlerA187(duid, handler, logger, roborockService, cleanModeSettings) {
@@ -47,12 +47,12 @@ const RvcCleanMode = {
47
47
  [8]: 'Custom',
48
48
  };
49
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 },
50
+ [5]: { suctionPower: VacuumSuctionPowerA27.Off, waterFlow: MopWaterFlowA27.Medium, distance_off: 0, mopRoute: MopRouteA27.Standard },
51
+ [6]: { suctionPower: VacuumSuctionPowerA27.Balanced, waterFlow: MopWaterFlowA27.Off, distance_off: 0, mopRoute: MopRouteA27.Standard },
52
+ [7]: { suctionPower: VacuumSuctionPowerA27.Balanced, waterFlow: MopWaterFlowA27.Medium, distance_off: 0, mopRoute: MopRouteA27.Standard },
53
+ [8]: { suctionPower: VacuumSuctionPowerA27.Custom, waterFlow: MopWaterFlowA27.Custom, distance_off: 0, mopRoute: MopRouteA27.Custom },
54
54
  };
55
- export function setCommandHandlerA27(duid, handler, logger, roborockService) {
55
+ export function setCommandHandlerA27(duid, handler, logger, roborockService, cleanModeSettings) {
56
56
  handler.setCommandHandler('changeToMode', async (newMode) => {
57
57
  const activity = RvcRunMode[newMode] || RvcCleanMode[newMode];
58
58
  switch (activity) {
@@ -63,10 +63,18 @@ export function setCommandHandlerA27(duid, handler, logger, roborockService) {
63
63
  }
64
64
  case 'Mop':
65
65
  case 'Vacuum':
66
- case 'Vac & Mop':
66
+ case 'Vac & Mop': {
67
+ const setting = cleanModeSettings ? getSettingFromCleanMode(activity, cleanModeSettings) : CleanSetting[newMode];
68
+ logger.notice(`BehaviorA27-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting ?? {})}`);
69
+ if (setting) {
70
+ await roborockService.changeCleanMode(duid, setting);
71
+ }
72
+ return;
73
+ }
67
74
  case 'Custom': {
68
75
  const setting = CleanSetting[newMode];
69
- logger.notice(`BehaviorA27-ChangeCleanMode to: ${activity}, code: ${debugStringify(setting)}`);
76
+ logger.notice(`BehaviorA27-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting)}`);
77
+ await roborockService.changeCleanMode(duid, setting);
70
78
  return;
71
79
  }
72
80
  default:
@@ -74,6 +82,41 @@ export function setCommandHandlerA27(duid, handler, logger, roborockService) {
74
82
  return;
75
83
  }
76
84
  });
85
+ const getSettingFromCleanMode = (activity, cleanModeSettings) => {
86
+ switch (activity) {
87
+ case 'Mop': {
88
+ const mopSetting = cleanModeSettings?.mopping;
89
+ const waterFlow = MopWaterFlowA27[mopSetting?.waterFlowMode] ?? MopWaterFlowA27.Medium;
90
+ return {
91
+ suctionPower: VacuumSuctionPowerA27.Off,
92
+ waterFlow,
93
+ distance_off: 0,
94
+ mopRoute: MopRouteA27[mopSetting?.mopRouteMode] ?? MopRouteA27.Standard,
95
+ };
96
+ }
97
+ case 'Vacuum': {
98
+ const vacuumSetting = cleanModeSettings?.vacuuming;
99
+ return {
100
+ suctionPower: VacuumSuctionPowerA27[vacuumSetting?.fanMode] ?? VacuumSuctionPowerA27.Balanced,
101
+ waterFlow: MopWaterFlowA27.Off,
102
+ distance_off: 0,
103
+ mopRoute: MopRouteA27[vacuumSetting?.mopRouteMode] ?? MopRouteA27.Standard,
104
+ };
105
+ }
106
+ case 'Vac & Mop': {
107
+ const vacmopSetting = cleanModeSettings?.vacmop;
108
+ const waterFlow = MopWaterFlowA27[vacmopSetting?.waterFlowMode] ?? MopWaterFlowA27.Medium;
109
+ return {
110
+ suctionPower: VacuumSuctionPowerA27[vacmopSetting?.fanMode] ?? VacuumSuctionPowerA27.Balanced,
111
+ waterFlow,
112
+ distance_off: 0,
113
+ mopRoute: MopRouteA27[vacmopSetting?.mopRouteMode] ?? MopRouteA27.Standard,
114
+ };
115
+ }
116
+ default:
117
+ return undefined;
118
+ }
119
+ };
77
120
  handler.setCommandHandler('selectAreas', async (newAreas) => {
78
121
  logger.notice(`BehaviorA27-selectAreas: ${newAreas}`);
79
122
  roborockService.setSelectedAreas(duid, newAreas ?? []);
@@ -0,0 +1,139 @@
1
+ import { debugStringify } from 'matterbridge/logger';
2
+ import { BehaviorRoborock } from '../../BehaviorDeviceGeneric.js';
3
+ export class BehaviorA51 extends BehaviorRoborock {
4
+ }
5
+ export var BehaviorRoborockA51;
6
+ (function (BehaviorRoborockA51) {
7
+ class State {
8
+ device;
9
+ }
10
+ BehaviorRoborockA51.State = State;
11
+ })(BehaviorRoborockA51 || (BehaviorRoborockA51 = {}));
12
+ export var VacuumSuctionPowerA51;
13
+ (function (VacuumSuctionPowerA51) {
14
+ VacuumSuctionPowerA51[VacuumSuctionPowerA51["Quiet"] = 101] = "Quiet";
15
+ VacuumSuctionPowerA51[VacuumSuctionPowerA51["Balanced"] = 102] = "Balanced";
16
+ VacuumSuctionPowerA51[VacuumSuctionPowerA51["Turbo"] = 103] = "Turbo";
17
+ VacuumSuctionPowerA51[VacuumSuctionPowerA51["Max"] = 104] = "Max";
18
+ VacuumSuctionPowerA51[VacuumSuctionPowerA51["Off"] = 105] = "Off";
19
+ VacuumSuctionPowerA51[VacuumSuctionPowerA51["Custom"] = 106] = "Custom";
20
+ VacuumSuctionPowerA51[VacuumSuctionPowerA51["MaxPlus"] = 108] = "MaxPlus";
21
+ })(VacuumSuctionPowerA51 || (VacuumSuctionPowerA51 = {}));
22
+ export var MopWaterFlowA51;
23
+ (function (MopWaterFlowA51) {
24
+ MopWaterFlowA51[MopWaterFlowA51["Off"] = 200] = "Off";
25
+ MopWaterFlowA51[MopWaterFlowA51["Low"] = 201] = "Low";
26
+ MopWaterFlowA51[MopWaterFlowA51["Medium"] = 202] = "Medium";
27
+ MopWaterFlowA51[MopWaterFlowA51["High"] = 203] = "High";
28
+ MopWaterFlowA51[MopWaterFlowA51["Custom"] = 204] = "Custom";
29
+ })(MopWaterFlowA51 || (MopWaterFlowA51 = {}));
30
+ export var MopRouteA51;
31
+ (function (MopRouteA51) {
32
+ MopRouteA51[MopRouteA51["Standard"] = 300] = "Standard";
33
+ MopRouteA51[MopRouteA51["Deep"] = 301] = "Deep";
34
+ MopRouteA51[MopRouteA51["Custom"] = 302] = "Custom";
35
+ MopRouteA51[MopRouteA51["DeepPlus"] = 303] = "DeepPlus";
36
+ MopRouteA51[MopRouteA51["Fast"] = 304] = "Fast";
37
+ })(MopRouteA51 || (MopRouteA51 = {}));
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: VacuumSuctionPowerA51.Off, waterFlow: MopWaterFlowA51.Medium, distance_off: 0, mopRoute: MopRouteA51.Standard },
51
+ [6]: { suctionPower: VacuumSuctionPowerA51.Balanced, waterFlow: MopWaterFlowA51.Off, distance_off: 0, mopRoute: MopRouteA51.Standard },
52
+ [7]: { suctionPower: VacuumSuctionPowerA51.Balanced, waterFlow: MopWaterFlowA51.Medium, distance_off: 0, mopRoute: MopRouteA51.Standard },
53
+ [8]: { suctionPower: VacuumSuctionPowerA51.Custom, waterFlow: MopWaterFlowA51.Custom, distance_off: 0, mopRoute: MopRouteA51.Custom },
54
+ };
55
+ export function setCommandHandlerA51(duid, handler, logger, roborockService, cleanModeSettings) {
56
+ handler.setCommandHandler('changeToMode', async (newMode) => {
57
+ const activity = RvcRunMode[newMode] || RvcCleanMode[newMode];
58
+ switch (activity) {
59
+ case 'Cleaning': {
60
+ await roborockService.startClean(duid);
61
+ return;
62
+ }
63
+ case 'Mop':
64
+ case 'Vacuum':
65
+ case 'Vac & Mop': {
66
+ const setting = cleanModeSettings ? getSettingFromCleanMode(activity, cleanModeSettings) : CleanSetting[newMode];
67
+ logger.notice(`BehaviorA51-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting ?? {})}`);
68
+ if (setting) {
69
+ await roborockService.changeCleanMode(duid, setting);
70
+ }
71
+ return;
72
+ }
73
+ case 'Custom': {
74
+ const setting = CleanSetting[newMode];
75
+ logger.notice(`BehaviorA51-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting)}`);
76
+ await roborockService.changeCleanMode(duid, setting);
77
+ return;
78
+ }
79
+ default:
80
+ logger.notice('BehaviorA51-changeToMode-Unknown: ', newMode);
81
+ return;
82
+ }
83
+ });
84
+ handler.setCommandHandler('selectAreas', async (newAreas) => {
85
+ logger.notice(`BehaviorA51-selectAreas: ${newAreas}`);
86
+ roborockService.setSelectedAreas(duid, newAreas ?? []);
87
+ });
88
+ handler.setCommandHandler('pause', async () => {
89
+ logger.notice('BehaviorA51-Pause');
90
+ await roborockService.pauseClean(duid);
91
+ });
92
+ handler.setCommandHandler('resume', async () => {
93
+ logger.notice('BehaviorA51-Resume');
94
+ await roborockService.resumeClean(duid);
95
+ });
96
+ handler.setCommandHandler('goHome', async () => {
97
+ logger.notice('BehaviorA51-GoHome');
98
+ await roborockService.stopAndGoHome(duid);
99
+ });
100
+ handler.setCommandHandler('PlaySoundToLocate', async (identifyTime) => {
101
+ logger.notice('BehaviorA51-PlaySoundToLocate');
102
+ await roborockService.playSoundToLocate(duid);
103
+ });
104
+ const getSettingFromCleanMode = (activity, cleanModeSettings) => {
105
+ switch (activity) {
106
+ case 'Mop': {
107
+ const mopSetting = cleanModeSettings?.mopping;
108
+ const waterFlow = MopWaterFlowA51[mopSetting?.waterFlowMode] ?? MopWaterFlowA51.Medium;
109
+ return {
110
+ suctionPower: VacuumSuctionPowerA51.Off,
111
+ waterFlow,
112
+ distance_off: 0,
113
+ mopRoute: MopRouteA51[mopSetting?.mopRouteMode] ?? MopRouteA51.Standard,
114
+ };
115
+ }
116
+ case 'Vacuum': {
117
+ const vacuumSetting = cleanModeSettings?.vacuuming;
118
+ return {
119
+ suctionPower: VacuumSuctionPowerA51[vacuumSetting?.fanMode] ?? VacuumSuctionPowerA51.Balanced,
120
+ waterFlow: MopWaterFlowA51.Off,
121
+ distance_off: 0,
122
+ mopRoute: MopRouteA51[vacuumSetting?.mopRouteMode] ?? MopRouteA51.Standard,
123
+ };
124
+ }
125
+ case 'Vac & Mop': {
126
+ const vacmopSetting = cleanModeSettings?.vacmop;
127
+ const waterFlow = MopWaterFlowA51[vacmopSetting?.waterFlowMode] ?? MopWaterFlowA51.Medium;
128
+ return {
129
+ suctionPower: VacuumSuctionPowerA51[vacmopSetting?.fanMode] ?? VacuumSuctionPowerA51.Balanced,
130
+ waterFlow,
131
+ distance_off: 0,
132
+ mopRoute: MopRouteA51[vacmopSetting?.mopRouteMode] ?? MopRouteA51.Standard,
133
+ };
134
+ }
135
+ default:
136
+ return undefined;
137
+ }
138
+ };
139
+ }
@@ -0,0 +1,76 @@
1
+ import { RvcCleanMode, RvcOperationalState, RvcRunMode } from 'matterbridge/matter/clusters';
2
+ export function getDefaultSupportedRunModes() {
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 getDefaultSupportedCleanModes() {
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 getDefaultOperationalStates() {
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 { MopWaterFlowA51, VacuumSuctionPowerA51 } from './a51.js';
2
+ export function getCurrentCleanModeA51(fan_power, water_box_mode) {
3
+ if (!fan_power || !water_box_mode)
4
+ return undefined;
5
+ if (fan_power == VacuumSuctionPowerA51.Custom || water_box_mode == MopWaterFlowA51.Custom)
6
+ return 8;
7
+ if (fan_power == VacuumSuctionPowerA51.Off)
8
+ return 5;
9
+ if (water_box_mode == MopWaterFlowA51.Off)
10
+ return 6;
11
+ else
12
+ return 7;
13
+ }
14
+ export function getCurrentCleanModeFromFanPowerA51(fan_power) {
15
+ if (!fan_power)
16
+ return undefined;
17
+ if (fan_power == VacuumSuctionPowerA51.Custom)
18
+ return 8;
19
+ if (fan_power == VacuumSuctionPowerA51.Off)
20
+ return 5;
21
+ else
22
+ return undefined;
23
+ }
24
+ export function getCurrentCleanModeFromWaterBoxModeA51(water_box_mode) {
25
+ if (!water_box_mode)
26
+ return undefined;
27
+ if (water_box_mode == MopWaterFlowA51.Custom)
28
+ return 8;
29
+ if (water_box_mode == MopWaterFlowA51.Off)
30
+ return 6;
31
+ else
32
+ return undefined;
33
+ }
@@ -1,3 +1,4 @@
1
+ import { debugStringify } from 'matterbridge/logger';
1
2
  import { BehaviorRoborock } from '../../BehaviorDeviceGeneric.js';
2
3
  export class DefaultBehavior extends BehaviorRoborock {
3
4
  }
@@ -8,16 +9,50 @@ export var DefaultBehaviorRoborock;
8
9
  }
9
10
  DefaultBehaviorRoborock.State = State;
10
11
  })(DefaultBehaviorRoborock || (DefaultBehaviorRoborock = {}));
12
+ export var VacuumSuctionPower;
13
+ (function (VacuumSuctionPower) {
14
+ VacuumSuctionPower[VacuumSuctionPower["Quiet"] = 101] = "Quiet";
15
+ VacuumSuctionPower[VacuumSuctionPower["Balanced"] = 102] = "Balanced";
16
+ VacuumSuctionPower[VacuumSuctionPower["Turbo"] = 103] = "Turbo";
17
+ VacuumSuctionPower[VacuumSuctionPower["Max"] = 104] = "Max";
18
+ VacuumSuctionPower[VacuumSuctionPower["Off"] = 105] = "Off";
19
+ VacuumSuctionPower[VacuumSuctionPower["Custom"] = 106] = "Custom";
20
+ VacuumSuctionPower[VacuumSuctionPower["MaxPlus"] = 108] = "MaxPlus";
21
+ })(VacuumSuctionPower || (VacuumSuctionPower = {}));
22
+ export var MopWaterFlow;
23
+ (function (MopWaterFlow) {
24
+ MopWaterFlow[MopWaterFlow["Off"] = 200] = "Off";
25
+ MopWaterFlow[MopWaterFlow["Low"] = 201] = "Low";
26
+ MopWaterFlow[MopWaterFlow["Medium"] = 202] = "Medium";
27
+ MopWaterFlow[MopWaterFlow["High"] = 203] = "High";
28
+ MopWaterFlow[MopWaterFlow["Custom"] = 204] = "Custom";
29
+ })(MopWaterFlow || (MopWaterFlow = {}));
30
+ export var MopRoute;
31
+ (function (MopRoute) {
32
+ MopRoute[MopRoute["Standard"] = 300] = "Standard";
33
+ MopRoute[MopRoute["Deep"] = 301] = "Deep";
34
+ MopRoute[MopRoute["Custom"] = 302] = "Custom";
35
+ MopRoute[MopRoute["DeepPlus"] = 303] = "DeepPlus";
36
+ MopRoute[MopRoute["Fast"] = 304] = "Fast";
37
+ })(MopRoute || (MopRoute = {}));
11
38
  const RvcRunMode = {
12
39
  [1]: 'Idle',
13
40
  [2]: 'Cleaning',
14
41
  [3]: 'Mapping',
15
42
  };
16
43
  const RvcCleanMode = {
17
- [4]: 'Mop',
18
- [5]: 'Vacuum',
44
+ [5]: 'Mop',
45
+ [6]: 'Vacuum',
46
+ [7]: 'Vac & Mop',
47
+ [8]: 'Custom',
19
48
  };
20
- export function setDefaultCommandHandler(duid, handler, logger, roborockService) {
49
+ const CleanSetting = {
50
+ [5]: { suctionPower: VacuumSuctionPower.Off, waterFlow: MopWaterFlow.Medium, distance_off: 0, mopRoute: MopRoute.Standard },
51
+ [6]: { suctionPower: VacuumSuctionPower.Balanced, waterFlow: MopWaterFlow.Off, distance_off: 0, mopRoute: MopRoute.Standard },
52
+ [7]: { suctionPower: VacuumSuctionPower.Balanced, waterFlow: MopWaterFlow.Medium, distance_off: 0, mopRoute: MopRoute.Standard },
53
+ [8]: { suctionPower: VacuumSuctionPower.Custom, waterFlow: MopWaterFlow.Custom, distance_off: 0, mopRoute: MopRoute.Custom },
54
+ };
55
+ export function setDefaultCommandHandler(duid, handler, logger, roborockService, cleanModeSettings) {
21
56
  handler.setCommandHandler('changeToMode', async (newMode) => {
22
57
  const activity = RvcRunMode[newMode] || RvcCleanMode[newMode];
23
58
  switch (activity) {
@@ -26,8 +61,19 @@ export function setDefaultCommandHandler(duid, handler, logger, roborockService)
26
61
  return;
27
62
  }
28
63
  case 'Mop':
29
- case 'Vacuum': {
30
- logger.notice('DefaultBehavior-ChangeCleanMode to: ', activity);
64
+ case 'Vacuum':
65
+ case 'Vac & Mop': {
66
+ const setting = cleanModeSettings ? getSettingFromCleanMode(activity, cleanModeSettings) : CleanSetting[newMode];
67
+ logger.notice(`DefaultBehavior-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting ?? {})}`);
68
+ if (setting) {
69
+ await roborockService.changeCleanMode(duid, setting);
70
+ }
71
+ return;
72
+ }
73
+ case 'Custom': {
74
+ const setting = CleanSetting[newMode];
75
+ logger.notice(`DefaultBehavior-ChangeCleanMode to: ${activity}, setting: ${debugStringify(setting)}`);
76
+ await roborockService.changeCleanMode(duid, setting);
31
77
  return;
32
78
  }
33
79
  default:
@@ -55,4 +101,39 @@ export function setDefaultCommandHandler(duid, handler, logger, roborockService)
55
101
  logger.notice('DefaultBehavior-PlaySoundToLocate');
56
102
  await roborockService.playSoundToLocate(duid);
57
103
  });
104
+ const getSettingFromCleanMode = (activity, cleanModeSettings) => {
105
+ switch (activity) {
106
+ case 'Mop': {
107
+ const mopSetting = cleanModeSettings?.mopping;
108
+ const waterFlow = MopWaterFlow[mopSetting?.waterFlowMode] ?? MopWaterFlow.Medium;
109
+ return {
110
+ suctionPower: VacuumSuctionPower.Off,
111
+ waterFlow,
112
+ distance_off: 0,
113
+ mopRoute: MopRoute[mopSetting?.mopRouteMode] ?? MopRoute.Standard,
114
+ };
115
+ }
116
+ case 'Vacuum': {
117
+ const vacuumSetting = cleanModeSettings?.vacuuming;
118
+ return {
119
+ suctionPower: VacuumSuctionPower[vacuumSetting?.fanMode] ?? VacuumSuctionPower.Balanced,
120
+ waterFlow: MopWaterFlow.Off,
121
+ distance_off: 0,
122
+ mopRoute: MopRoute[vacuumSetting?.mopRouteMode] ?? MopRoute.Standard,
123
+ };
124
+ }
125
+ case 'Vac & Mop': {
126
+ const vacmopSetting = cleanModeSettings?.vacmop;
127
+ const waterFlow = MopWaterFlow[vacmopSetting?.waterFlowMode] ?? MopWaterFlow.Medium;
128
+ return {
129
+ suctionPower: VacuumSuctionPower[vacmopSetting?.fanMode] ?? VacuumSuctionPower.Balanced,
130
+ waterFlow,
131
+ distance_off: 0,
132
+ mopRoute: MopRoute[vacmopSetting?.mopRouteMode] ?? MopRoute.Standard,
133
+ };
134
+ }
135
+ default:
136
+ return undefined;
137
+ }
138
+ };
58
139
  }
@@ -20,15 +20,25 @@ export function getDefaultSupportedRunModes() {
20
20
  }
21
21
  export function getDefaultSupportedCleanModes() {
22
22
  return [
23
+ {
24
+ label: 'Mop',
25
+ mode: 5,
26
+ modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Auto }],
27
+ },
23
28
  {
24
29
  label: 'Vacuum',
25
- mode: 4,
26
- modeTags: [{ value: RvcCleanMode.ModeTag.Vacuum }],
30
+ mode: 6,
31
+ modeTags: [{ value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Auto }],
27
32
  },
28
33
  {
29
- label: 'Mop',
30
- mode: 5,
31
- modeTags: [{ value: RvcCleanMode.ModeTag.Mop }],
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 }],
32
42
  },
33
43
  ];
34
44
  }
@@ -0,0 +1,33 @@
1
+ import { MopWaterFlow, VacuumSuctionPower } from './default.js';
2
+ export function getCurrentCleanModeDefault(fan_power, water_box_mode) {
3
+ if (!fan_power || !water_box_mode)
4
+ return undefined;
5
+ if (fan_power == VacuumSuctionPower.Custom || water_box_mode == MopWaterFlow.Custom)
6
+ return 8;
7
+ if (fan_power == VacuumSuctionPower.Off)
8
+ return 5;
9
+ if (water_box_mode == MopWaterFlow.Off)
10
+ return 6;
11
+ else
12
+ return 7;
13
+ }
14
+ export function getCurrentCleanModeFromFanPowerDefault(fan_power) {
15
+ if (!fan_power)
16
+ return undefined;
17
+ if (fan_power == VacuumSuctionPower.Custom)
18
+ return 8;
19
+ if (fan_power == VacuumSuctionPower.Off)
20
+ return 5;
21
+ else
22
+ return undefined;
23
+ }
24
+ export function getCurrentCleanModeFromWaterBoxModeDefault(water_box_mode) {
25
+ if (!water_box_mode)
26
+ return undefined;
27
+ if (water_box_mode == MopWaterFlow.Custom)
28
+ return 8;
29
+ if (water_box_mode == MopWaterFlow.Off)
30
+ return 6;
31
+ else
32
+ return undefined;
33
+ }
@@ -0,0 +1,26 @@
1
+ import { debugStringify } from 'matterbridge/logger';
2
+ import { randomInt } from 'crypto';
3
+ export function getSupportedScenes(scenes, log) {
4
+ log?.debug('getSupportedScenes', debugStringify(scenes));
5
+ if (!scenes || scenes.length === 0) {
6
+ log?.error('No scenes found');
7
+ return [];
8
+ }
9
+ const supportedAreas = scenes
10
+ .filter((s) => s.enabled && s.id)
11
+ .map((scene) => {
12
+ return {
13
+ areaId: scene.id + randomInt(5000, 9000),
14
+ mapId: null,
15
+ areaInfo: {
16
+ locationInfo: {
17
+ locationName: `Scene: ${scene.name}`,
18
+ floorNumber: null,
19
+ areaType: null,
20
+ },
21
+ landmarkInfo: null,
22
+ },
23
+ };
24
+ });
25
+ return supportedAreas;
26
+ }
@@ -3,3 +3,4 @@ export { getOperationalStates, getOperationalErrorState } from './getOperational
3
3
  export { getSupportedCleanModes } from './getSupportedCleanModes.js';
4
4
  export { getSupportedAreas } from './getSupportedAreas.js';
5
5
  export { getBatteryStatus, getBatteryState } from './getBatteryStatus.js';
6
+ export { getSupportedScenes } from './getSupportedScenes.js';