matterbridge-roborock-vacuum-plugin 1.0.7-rc02 → 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 CHANGED
@@ -42,13 +42,23 @@
42
42
  ---
43
43
  ### 🆔 How to Get Your DUID
44
44
 
45
- To get the **DUID** for your devices. Follow the steps below to retrieve it:
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
 
@@ -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
  }
@@ -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/platform.js CHANGED
@@ -19,7 +19,6 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
19
19
  platformRunner;
20
20
  devices;
21
21
  serialNumber;
22
- whiteList;
23
22
  constructor(matterbridge, log, config) {
24
23
  super(matterbridge, log, config);
25
24
  if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.0.4')) {
@@ -32,8 +31,6 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
32
31
  config.blackList = [];
33
32
  if (config.enableExperimentalFeature === undefined)
34
33
  config.enableExperimentalFeature = false;
35
- this.whiteList = config.whiteList;
36
- config.whiteList = [];
37
34
  this.clientManager = new ClientManager(this.log);
38
35
  this.devices = new Map();
39
36
  }
@@ -74,15 +71,16 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
74
71
  const devices = await this.roborockService.listDevices(username);
75
72
  this.log.notice('Initializing - devices: ', debugStringify(devices));
76
73
  let vacuum = undefined;
77
- if (this.whiteList.length > 0) {
78
- const firstDUID = this.whiteList[0];
79
- vacuum = devices.find((d) => d.duid == firstDUID);
74
+ if (this.config.whiteList.length > 0) {
75
+ const firstDUID = this.config.whiteList[0];
76
+ const duid = firstDUID.split('-')[1];
77
+ vacuum = devices.find((d) => d.duid == duid);
80
78
  }
81
79
  else {
82
80
  vacuum = devices.find((d) => isSupportedDevice(d.data.model));
83
81
  }
84
82
  if (!vacuum) {
85
- this.log.error('Initializing: No supported devices found');
83
+ this.log.error('Initializing: No device found');
86
84
  return;
87
85
  }
88
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
- super(device.name, device.duid, supportedRunModes[0].mode, supportedRunModes, cleanModes[0].mode, cleanModes, undefined, undefined, RvcOperationalState.OperationalState.Docked, getOperationalStates(device.data.model), supportedAreas, undefined, supportedAreas[0].areaId);
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
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "matterbridge-roborock-vacuum-plugin",
3
3
  "type": "DynamicPlatform",
4
- "version": "1.0.7-rc02",
4
+ "version": "1.0.7-rc03",
5
5
  "whiteList": [],
6
6
  "blackList": [],
7
7
  "useInterval": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "title": "Matterbridge Roborock Vacuum Plugin",
3
- "description": "matterbridge-roborock-vacuum-plugin v. 1.0.7-rc02 by https://github.com/RinDevJunior",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge-roborock-vacuum-plugin",
3
- "version": "1.0.7-rc02",
3
+ "version": "1.0.7-rc03",
4
4
  "description": "Matterbridge Roborock Vacuum Plugin",
5
5
  "author": "https://github.com/RinDevJunior",
6
6
  "license": "MIT",
@@ -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
  }
@@ -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/platform.ts CHANGED
@@ -21,7 +21,6 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
21
21
  platformRunner: PlatformRunner | undefined;
22
22
  devices: Map<string, Device>;
23
23
  serialNumber: string | undefined;
24
- whiteList: string[];
25
24
 
26
25
  constructor(matterbridge: Matterbridge, log: AnsiLogger, config: PlatformConfig) {
27
26
  super(matterbridge, log, config);
@@ -36,10 +35,6 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
36
35
  if (config.whiteList === undefined) config.whiteList = [];
37
36
  if (config.blackList === undefined) config.blackList = [];
38
37
  if (config.enableExperimentalFeature === undefined) config.enableExperimentalFeature = false;
39
- this.whiteList = config.whiteList as string[];
40
-
41
- //reset default whitelist
42
- config.whiteList = [];
43
38
 
44
39
  this.clientManager = new ClientManager(this.log);
45
40
  this.devices = new Map<string, Device>();
@@ -100,15 +95,16 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
100
95
  this.log.notice('Initializing - devices: ', debugStringify(devices));
101
96
 
102
97
  let vacuum: Device | undefined = undefined;
103
- if (this.whiteList.length > 0) {
104
- const firstDUID = this.whiteList[0];
105
- vacuum = devices.find((d) => d.duid == firstDUID);
98
+ if ((this.config.whiteList as string[]).length > 0) {
99
+ const firstDUID = (this.config.whiteList as string[])[0];
100
+ const duid = firstDUID.split('-')[1];
101
+ vacuum = devices.find((d) => d.duid == duid);
106
102
  } else {
107
103
  vacuum = devices.find((d) => isSupportedDevice(d.data.model));
108
104
  }
109
105
 
110
106
  if (!vacuum) {
111
- this.log.error('Initializing: No supported devices found');
107
+ this.log.error('Initializing: No device found');
112
108
  return;
113
109
  }
114
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
- device.name, //name
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
  }