matterbridge-roborock-vacuum-plugin 1.0.8-rc06 → 1.0.8-rc07

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
@@ -74,11 +74,14 @@ To get the **DUID** for your devices, you have two options:
74
74
 
75
75
  ---
76
76
 
77
- **➡️ [See Supported & Tested Roborock Devices](./README_SUPPORTED.md)**
78
77
 
79
- > 📋 **Apple Home ↔️ Roborock Clean Mode Mapping:**
80
- > For a detailed table of how Apple Home clean modes map to Roborock settings, see
81
- > 👉 [Apple Home ↔️ Roborock Clean Mode Mapping](./README_CLEANMODE.md)
78
+ ### ➡️ [See Supported & Tested Roborock Devices](./README_SUPPORTED.md)
79
+
80
+
81
+ 📋 **Apple Home ↔️ Roborock Clean Mode Mapping:**
82
+ For a detailed table of how Apple Home clean modes map to Roborock settings, see 👉 [Apple Home ↔️ Roborock Clean Mode Mapping](./README_CLEANMODE.md)
83
+
84
+ ---
82
85
 
83
86
  ### 📦 Prerequisites
84
87
 
@@ -19,8 +19,8 @@ export function getDefaultSupportedRunModes() {
19
19
  },
20
20
  ];
21
21
  }
22
- export function getDefaultSupportedCleanModes() {
23
- return [
22
+ export function getDefaultSupportedCleanModes(enableExperimentalFeature) {
23
+ const result = [
24
24
  {
25
25
  label: RvcCleanModeDisplayMap[5],
26
26
  mode: 5,
@@ -96,12 +96,18 @@ export function getDefaultSupportedCleanModes() {
96
96
  mode: 69,
97
97
  modeTags: [{ value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Quick }],
98
98
  },
99
- {
100
- label: RvcCleanModeDisplayMap[99],
101
- mode: 99,
102
- modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Vacation }],
103
- },
104
99
  ];
100
+ if (enableExperimentalFeature?.advancedFeature?.useVacationModeToSendVacuumToDock ?? false) {
101
+ return [
102
+ ...result,
103
+ {
104
+ label: RvcCleanModeDisplayMap[99],
105
+ mode: 99,
106
+ modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Vacation }],
107
+ },
108
+ ];
109
+ }
110
+ return result;
105
111
  }
106
112
  export function getDefaultOperationalStates() {
107
113
  return [
@@ -1,7 +1,7 @@
1
1
  import { RvcCleanMode } from 'matterbridge/matter/clusters';
2
2
  import { RvcCleanMode as RvcCleanModeDisplayMap } from './smart.js';
3
3
  import { getDefaultSupportedCleanModes } from '../default/initalData.js';
4
- export function getSupportedCleanModesSmart() {
4
+ export function getSupportedCleanModesSmart(enableExperimentalFeature) {
5
5
  return [
6
6
  {
7
7
  label: RvcCleanModeDisplayMap[4],
@@ -13,6 +13,6 @@ export function getSupportedCleanModesSmart() {
13
13
  mode: 5,
14
14
  modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Day }],
15
15
  },
16
- ...getDefaultSupportedCleanModes().filter((x) => x.mode !== 4 && x.mode !== 5),
16
+ ...getDefaultSupportedCleanModes(enableExperimentalFeature).filter((x) => x.mode !== 4 && x.mode !== 5),
17
17
  ];
18
18
  }
@@ -51,7 +51,7 @@ export function setCommandHandlerSmart(duid, handler, logger, roborockService, c
51
51
  break;
52
52
  }
53
53
  case 'Go Vacation': {
54
- logger.notice('DefaultBehavior-GoHome');
54
+ logger.notice('BehaviorSmart-GoHome');
55
55
  await roborockService.stopAndGoHome(duid);
56
56
  break;
57
57
  }
@@ -1,17 +1,17 @@
1
1
  import { getSupportedCleanModesSmart } from '../behaviors/roborock.vacuum/smart/initalData.js';
2
2
  import { getDefaultSupportedCleanModes } from '../behaviors/roborock.vacuum/default/initalData.js';
3
3
  import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
4
- export function getSupportedCleanModes(model, forceRunAtDefault) {
5
- if (forceRunAtDefault) {
6
- return getDefaultSupportedCleanModes();
4
+ export function getSupportedCleanModes(model, enableExperimentalFeature) {
5
+ if (enableExperimentalFeature?.advancedFeature?.forceRunAtDefault ?? false) {
6
+ return getDefaultSupportedCleanModes(enableExperimentalFeature);
7
7
  }
8
8
  switch (model) {
9
9
  case DeviceModel.QREVO_EDGE_5V1:
10
- return getSupportedCleanModesSmart();
10
+ return getSupportedCleanModesSmart(enableExperimentalFeature);
11
11
  case DeviceModel.S7_MAXV:
12
12
  case DeviceModel.S8_PRO_ULTRA:
13
13
  case DeviceModel.S6_PURE:
14
14
  default:
15
- return getDefaultSupportedCleanModes();
15
+ return getDefaultSupportedCleanModes(enableExperimentalFeature);
16
16
  }
17
17
  }
@@ -15,6 +15,9 @@ export function parseDockingStationStatus(dss) {
15
15
  };
16
16
  }
17
17
  export function hasDockingStationError(status) {
18
+ if (!status) {
19
+ return false;
20
+ }
18
21
  return (status.cleanFluidStatus === DockingStationStatusType.Error ||
19
22
  status.waterBoxFilterStatus === DockingStationStatusType.Error ||
20
23
  status.dustBagStatus === DockingStationStatusType.Error ||
package/dist/platform.js CHANGED
@@ -113,7 +113,7 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
113
113
  routineAsRoom = getSupportedScenes(vacuum.scenes, this.log);
114
114
  this.roborockService.setSupportedScenes(vacuum.duid, routineAsRoom);
115
115
  }
116
- this.robot = new RoborockVacuumCleaner(username, vacuum, roomMap, routineAsRoom, this.enableExperimentalFeature?.advancedFeature?.forceRunAtDefault ?? false, this.log);
116
+ this.robot = new RoborockVacuumCleaner(username, vacuum, roomMap, routineAsRoom, this.enableExperimentalFeature, this.log);
117
117
  this.robot.configurateHandler(behaviorHandler);
118
118
  this.log.info('vacuum:', debugStringify(vacuum));
119
119
  this.setSelectDevice(this.robot.serialNumber ?? '', this.robot.deviceName ?? '', undefined, 'hub');
@@ -159,7 +159,10 @@ export class PlatformRunner {
159
159
  }
160
160
  const operationalStateId = state_to_matter_operational_status(status);
161
161
  if (operationalStateId) {
162
- platform.robot?.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
162
+ const dssHasError = hasDockingStationError(platform.robot?.dockStationStatus);
163
+ if (!(dssHasError && self.triggerDssError())) {
164
+ platform.robot?.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
165
+ }
163
166
  }
164
167
  break;
165
168
  }
@@ -211,18 +214,27 @@ export class PlatformRunner {
211
214
  });
212
215
  }
213
216
  async processAdditionalProps(robot, message) {
217
+ const dssStatus = this.getDssStatus(message);
218
+ if (dssStatus) {
219
+ this.triggerDssError();
220
+ }
221
+ }
222
+ getDssStatus(message) {
214
223
  const platform = this.platform;
224
+ const robot = platform.robot;
215
225
  if (platform.enableExperimentalFeature &&
216
226
  platform.enableExperimentalFeature.enableExperimentalFeature &&
217
227
  platform.enableExperimentalFeature.advancedFeature.includeDockStationStatus &&
218
228
  message.dss !== undefined) {
219
229
  const dss = parseDockingStationStatus(message.dss);
220
- this.platform.log.debug('DockingStationStatus:', debugStringify(dss));
221
- const currentOperationState = robot.getAttribute(RvcOperationalState.Cluster.id, 'operationalState');
222
- if (dss && hasDockingStationError(dss) && currentOperationState !== RvcOperationalState.OperationalState.Running) {
223
- robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', RvcOperationalState.OperationalState.Error, platform.log);
230
+ if (dss && robot) {
231
+ robot.dockStationStatus = dss;
232
+ }
233
+ if (dss && hasDockingStationError(dss)) {
234
+ return RvcOperationalState.OperationalState.Error;
224
235
  }
225
236
  }
237
+ return undefined;
226
238
  }
227
239
  isStatusUpdate(result) {
228
240
  return (Array.isArray(result) &&
@@ -262,11 +274,27 @@ export class PlatformRunner {
262
274
  }
263
275
  const operationalStateId = state_to_matter_operational_status(state);
264
276
  if (operationalStateId) {
265
- this.platform.log.debug(`updateFromHomeData-OperationalState: ${RvcOperationalState.OperationalState[operationalStateId]}`);
266
- platform.robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
277
+ const dssHasError = hasDockingStationError(platform.robot?.dockStationStatus);
278
+ this.platform.log.debug(`dssHasError: ${dssHasError}, dockStationStatus: ${debugStringify(platform.robot?.dockStationStatus ?? {})}`);
279
+ if (!(dssHasError && this.triggerDssError())) {
280
+ this.platform.log.debug(`updateFromHomeData-OperationalState: ${RvcOperationalState.OperationalState[operationalStateId]}`);
281
+ platform.robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
282
+ }
267
283
  }
268
284
  if (batteryLevel) {
269
285
  platform.robot.updateAttribute(PowerSource.Cluster.id, 'batChargeState', getBatteryState(state, batteryLevel), platform.log);
270
286
  }
271
287
  }
288
+ triggerDssError() {
289
+ const platform = this.platform;
290
+ const currentOperationState = platform?.robot?.getAttribute(RvcOperationalState.Cluster.id, 'operationalState');
291
+ if (currentOperationState === RvcOperationalState.OperationalState.Error) {
292
+ return true;
293
+ }
294
+ if (currentOperationState === RvcOperationalState.OperationalState.Docked) {
295
+ platform.robot?.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', RvcOperationalState.OperationalState.Error, platform.log);
296
+ return true;
297
+ }
298
+ return false;
299
+ }
272
300
  }
package/dist/rvc.js CHANGED
@@ -6,12 +6,13 @@ export class RoborockVacuumCleaner extends RoboticVacuumCleaner {
6
6
  device;
7
7
  rrHomeId;
8
8
  roomInfo;
9
- constructor(username, device, roomMap, routineAsRoom, forceRunAtDefault, log) {
10
- const cleanModes = getSupportedCleanModes(device.data.model, forceRunAtDefault);
9
+ dockStationStatus;
10
+ constructor(username, device, roomMap, routineAsRoom, enableExperimentalFeature, log) {
11
+ const cleanModes = getSupportedCleanModes(device.data.model, enableExperimentalFeature);
11
12
  const supportedRunModes = getSupportedRunModes();
12
13
  const supportedAreas = [...getSupportedAreas(device.rooms, roomMap, log), ...routineAsRoom];
13
14
  const deviceName = `${device.name}-${device.duid}`.replace(/\s+/g, '');
14
- log.debug(`Creating RoborockVacuumCleaner for device: ${deviceName}, model: ${device.data.model}, forceRunAtDefault: ${forceRunAtDefault}`);
15
+ log.debug(`Creating RoborockVacuumCleaner for device: ${deviceName}, model: ${device.data.model}, forceRunAtDefault: ${enableExperimentalFeature?.advancedFeature?.forceRunAtDefault}`);
15
16
  log.debug(`Supported Clean Modes: ${JSON.stringify(cleanModes)}`);
16
17
  log.debug(`Supported Run Modes: ${JSON.stringify(supportedRunModes)}`);
17
18
  super(deviceName, device.duid, supportedRunModes[0].mode, supportedRunModes, cleanModes[0].mode, cleanModes, undefined, undefined, RvcOperationalState.OperationalState.Docked, getOperationalStates(), supportedAreas, undefined, supportedAreas[0].areaId);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "matterbridge-roborock-vacuum-plugin",
3
3
  "type": "DynamicPlatform",
4
- "version": "1.0.8-rc06",
4
+ "version": "1.0.8-rc07",
5
5
  "whiteList": [],
6
6
  "blackList": [],
7
7
  "useInterval": true,
@@ -10,7 +10,8 @@
10
10
  "advancedFeature": {
11
11
  "showRoutinesAsRooms": false,
12
12
  "includeDockStationStatus": false,
13
- "forceRunAtDefault": false
13
+ "forceRunAtDefault": false,
14
+ "useVacationModeToSendVacuumToDock": false
14
15
  },
15
16
  "cleanModeSettings": {
16
17
  "enableCleanModeMapping": false,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "title": "Matterbridge Roborock Vacuum Plugin",
3
- "description": "matterbridge-roborock-vacuum-plugin v. 1.0.8-rc06 by https://github.com/RinDevJunior",
3
+ "description": "matterbridge-roborock-vacuum-plugin v. 1.0.8-rc07 by https://github.com/RinDevJunior",
4
4
  "type": "object",
5
5
  "required": ["username", "password"],
6
6
  "properties": {
@@ -79,6 +79,11 @@
79
79
  "title": "Force Run At Default Implementation",
80
80
  "type": "boolean",
81
81
  "default": false
82
+ },
83
+ "useVacationModeToSendVacuumToDock": {
84
+ "title": "Use Vacation Mode To Send Vacuum To Dock",
85
+ "type": "boolean",
86
+ "default": false
82
87
  }
83
88
  }
84
89
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge-roborock-vacuum-plugin",
3
- "version": "1.0.8-rc06",
3
+ "version": "1.0.8-rc07",
4
4
  "description": "Matterbridge Roborock Vacuum Plugin",
5
5
  "author": "https://github.com/RinDevJunior",
6
6
  "license": "MIT",
@@ -1,5 +1,6 @@
1
1
  import { RvcCleanMode, RvcOperationalState, RvcRunMode } from 'matterbridge/matter/clusters';
2
2
  import { RvcCleanMode as RvcCleanModeDisplayMap } from './default.js';
3
+ import { ExperimentalFeatureSetting } from '../../../model/ExperimentalFeatureSetting.js';
3
4
 
4
5
  export function getDefaultSupportedRunModes(): RvcRunMode.ModeOption[] {
5
6
  return [
@@ -21,8 +22,8 @@ export function getDefaultSupportedRunModes(): RvcRunMode.ModeOption[] {
21
22
  ];
22
23
  }
23
24
 
24
- export function getDefaultSupportedCleanModes(): RvcCleanMode.ModeOption[] {
25
- return [
25
+ export function getDefaultSupportedCleanModes(enableExperimentalFeature: ExperimentalFeatureSetting | undefined): RvcCleanMode.ModeOption[] {
26
+ const result = [
26
27
  {
27
28
  label: RvcCleanModeDisplayMap[5],
28
29
  mode: 5,
@@ -101,13 +102,20 @@ export function getDefaultSupportedCleanModes(): RvcCleanMode.ModeOption[] {
101
102
  mode: 69,
102
103
  modeTags: [{ value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Quick }],
103
104
  },
104
-
105
- {
106
- label: RvcCleanModeDisplayMap[99],
107
- mode: 99,
108
- modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Vacation }],
109
- },
110
105
  ];
106
+
107
+ if (enableExperimentalFeature?.advancedFeature?.useVacationModeToSendVacuumToDock ?? false) {
108
+ return [
109
+ ...result,
110
+ {
111
+ label: RvcCleanModeDisplayMap[99],
112
+ mode: 99,
113
+ modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Vacation }],
114
+ },
115
+ ];
116
+ }
117
+
118
+ return result;
111
119
  }
112
120
 
113
121
  export function getDefaultOperationalStates(): RvcOperationalState.OperationalStateStruct[] {
@@ -1,8 +1,9 @@
1
1
  import { RvcCleanMode } from 'matterbridge/matter/clusters';
2
2
  import { RvcCleanMode as RvcCleanModeDisplayMap } from './smart.js';
3
3
  import { getDefaultSupportedCleanModes } from '../default/initalData.js';
4
+ import { ExperimentalFeatureSetting } from '../../../model/ExperimentalFeatureSetting.js';
4
5
 
5
- export function getSupportedCleanModesSmart(): RvcCleanMode.ModeOption[] {
6
+ export function getSupportedCleanModesSmart(enableExperimentalFeature: ExperimentalFeatureSetting | undefined): RvcCleanMode.ModeOption[] {
6
7
  return [
7
8
  {
8
9
  label: RvcCleanModeDisplayMap[4],
@@ -14,6 +15,6 @@ export function getSupportedCleanModesSmart(): RvcCleanMode.ModeOption[] {
14
15
  mode: 5,
15
16
  modeTags: [{ value: RvcCleanMode.ModeTag.Mop }, { value: RvcCleanMode.ModeTag.Vacuum }, { value: RvcCleanMode.ModeTag.Day }],
16
17
  },
17
- ...getDefaultSupportedCleanModes().filter((x) => x.mode !== 4 && x.mode !== 5), // Exclude modes 4 and 5 which are already defined
18
+ ...getDefaultSupportedCleanModes(enableExperimentalFeature).filter((x) => x.mode !== 4 && x.mode !== 5), // Exclude modes 4 and 5 which are already defined
18
19
  ];
19
20
  }
@@ -83,7 +83,7 @@ export function setCommandHandlerSmart(
83
83
  }
84
84
 
85
85
  case 'Go Vacation': {
86
- logger.notice('DefaultBehavior-GoHome');
86
+ logger.notice('BehaviorSmart-GoHome');
87
87
  await roborockService.stopAndGoHome(duid);
88
88
  break;
89
89
  }
@@ -2,20 +2,21 @@ import { RvcCleanMode } from 'matterbridge/matter/clusters';
2
2
  import { getSupportedCleanModesSmart } from '../behaviors/roborock.vacuum/smart/initalData.js';
3
3
  import { getDefaultSupportedCleanModes } from '../behaviors/roborock.vacuum/default/initalData.js';
4
4
  import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
5
+ import { ExperimentalFeatureSetting } from '../model/ExperimentalFeatureSetting.js';
5
6
 
6
- export function getSupportedCleanModes(model: string, forceRunAtDefault: boolean): RvcCleanMode.ModeOption[] {
7
- if (forceRunAtDefault) {
8
- return getDefaultSupportedCleanModes();
7
+ export function getSupportedCleanModes(model: string, enableExperimentalFeature: ExperimentalFeatureSetting | undefined): RvcCleanMode.ModeOption[] {
8
+ if (enableExperimentalFeature?.advancedFeature?.forceRunAtDefault ?? false) {
9
+ return getDefaultSupportedCleanModes(enableExperimentalFeature);
9
10
  }
10
11
 
11
12
  switch (model) {
12
13
  case DeviceModel.QREVO_EDGE_5V1:
13
- return getSupportedCleanModesSmart();
14
+ return getSupportedCleanModesSmart(enableExperimentalFeature);
14
15
 
15
16
  case DeviceModel.S7_MAXV:
16
17
  case DeviceModel.S8_PRO_ULTRA:
17
18
  case DeviceModel.S6_PURE:
18
19
  default:
19
- return getDefaultSupportedCleanModes();
20
+ return getDefaultSupportedCleanModes(enableExperimentalFeature);
20
21
  }
21
22
  }
@@ -25,7 +25,11 @@ export function parseDockingStationStatus(dss: number): DockingStationStatus {
25
25
  };
26
26
  }
27
27
 
28
- export function hasDockingStationError(status: DockingStationStatus): boolean {
28
+ export function hasDockingStationError(status: DockingStationStatus | undefined): boolean {
29
+ if (!status) {
30
+ return false;
31
+ }
32
+
29
33
  return (
30
34
  status.cleanFluidStatus === DockingStationStatusType.Error ||
31
35
  status.waterBoxFilterStatus === DockingStationStatusType.Error ||
@@ -4,6 +4,7 @@ export interface ExperimentalFeatureSetting {
4
4
  showRoutinesAsRoom: boolean;
5
5
  includeDockStationStatus: boolean;
6
6
  forceRunAtDefault: boolean;
7
+ useVacationModeToSendVacuumToDock: boolean;
7
8
  };
8
9
  cleanModeSettings: CleanModeSettings;
9
10
  }
package/src/platform.ts CHANGED
@@ -162,7 +162,7 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
162
162
  this.roborockService.setSupportedScenes(vacuum.duid, routineAsRoom);
163
163
  }
164
164
 
165
- this.robot = new RoborockVacuumCleaner(username, vacuum, roomMap, routineAsRoom, this.enableExperimentalFeature?.advancedFeature?.forceRunAtDefault ?? false, this.log);
165
+ this.robot = new RoborockVacuumCleaner(username, vacuum, roomMap, routineAsRoom, this.enableExperimentalFeature, this.log);
166
166
  this.robot.configurateHandler(behaviorHandler);
167
167
 
168
168
  this.log.info('vacuum:', debugStringify(vacuum));
@@ -192,7 +192,10 @@ export class PlatformRunner {
192
192
 
193
193
  const operationalStateId = state_to_matter_operational_status(status);
194
194
  if (operationalStateId) {
195
- platform.robot?.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
195
+ const dssHasError = hasDockingStationError(platform.robot?.dockStationStatus);
196
+ if (!(dssHasError && self.triggerDssError())) {
197
+ platform.robot?.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
198
+ }
196
199
  }
197
200
  break;
198
201
  }
@@ -254,7 +257,15 @@ export class PlatformRunner {
254
257
 
255
258
  private async processAdditionalProps(robot: RoborockVacuumCleaner, message: CloudMessageResult): Promise<void> {
256
259
  // dss -> DockingStationStatus
260
+ const dssStatus = this.getDssStatus(message);
261
+ if (dssStatus) {
262
+ this.triggerDssError();
263
+ }
264
+ }
265
+
266
+ private getDssStatus(message: CloudMessageResult): RvcOperationalState.OperationalState | undefined {
257
267
  const platform = this.platform;
268
+ const robot = platform.robot;
258
269
  if (
259
270
  platform.enableExperimentalFeature &&
260
271
  platform.enableExperimentalFeature.enableExperimentalFeature &&
@@ -262,15 +273,15 @@ export class PlatformRunner {
262
273
  message.dss !== undefined
263
274
  ) {
264
275
  const dss = parseDockingStationStatus(message.dss);
265
- this.platform.log.debug('DockingStationStatus:', debugStringify(dss));
266
-
267
- const currentOperationState = robot.getAttribute(RvcOperationalState.Cluster.id, 'operationalState') as RvcOperationalState.OperationalState;
276
+ if (dss && robot) {
277
+ robot.dockStationStatus = dss;
278
+ }
268
279
 
269
- // Only update docking station status if it is not running
270
- if (dss && hasDockingStationError(dss) && currentOperationState !== RvcOperationalState.OperationalState.Running) {
271
- robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', RvcOperationalState.OperationalState.Error, platform.log);
280
+ if (dss && hasDockingStationError(dss)) {
281
+ return RvcOperationalState.OperationalState.Error;
272
282
  }
273
283
  }
284
+ return undefined;
274
285
  }
275
286
 
276
287
  private isStatusUpdate(result: unknown): boolean {
@@ -317,13 +328,33 @@ export class PlatformRunner {
317
328
  }
318
329
 
319
330
  const operationalStateId = state_to_matter_operational_status(state);
331
+
320
332
  if (operationalStateId) {
321
- this.platform.log.debug(`updateFromHomeData-OperationalState: ${RvcOperationalState.OperationalState[operationalStateId]}`);
322
- platform.robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
333
+ const dssHasError = hasDockingStationError(platform.robot?.dockStationStatus);
334
+ this.platform.log.debug(`dssHasError: ${dssHasError}, dockStationStatus: ${debugStringify(platform.robot?.dockStationStatus ?? {})}`);
335
+ if (!(dssHasError && this.triggerDssError())) {
336
+ this.platform.log.debug(`updateFromHomeData-OperationalState: ${RvcOperationalState.OperationalState[operationalStateId]}`);
337
+ platform.robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
338
+ }
323
339
  }
324
340
 
325
341
  if (batteryLevel) {
326
342
  platform.robot.updateAttribute(PowerSource.Cluster.id, 'batChargeState', getBatteryState(state, batteryLevel), platform.log);
327
343
  }
328
344
  }
345
+
346
+ private triggerDssError(): boolean {
347
+ const platform = this.platform;
348
+ const currentOperationState = platform?.robot?.getAttribute(RvcOperationalState.Cluster.id, 'operationalState') as RvcOperationalState.OperationalState;
349
+ if (currentOperationState === RvcOperationalState.OperationalState.Error) {
350
+ return true;
351
+ }
352
+
353
+ if (currentOperationState === RvcOperationalState.OperationalState.Docked) {
354
+ platform.robot?.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', RvcOperationalState.OperationalState.Error, platform.log);
355
+ return true;
356
+ }
357
+
358
+ return false;
359
+ }
329
360
  }
package/src/rvc.ts CHANGED
@@ -5,20 +5,32 @@ import { getOperationalStates, getSupportedAreas, getSupportedCleanModes, getSup
5
5
  import { AnsiLogger } from 'matterbridge/logger';
6
6
  import { BehaviorFactoryResult } from './behaviorFactory.js';
7
7
  import { ModeBase, RvcOperationalState, ServiceArea } from 'matterbridge/matter/clusters';
8
+ import { ExperimentalFeatureSetting } from './model/ExperimentalFeatureSetting.js';
9
+ import { DockingStationStatus } from './model/DockingStationStatus.js';
8
10
 
9
11
  export class RoborockVacuumCleaner extends RoboticVacuumCleaner {
10
12
  username: string | undefined;
11
13
  device: Device;
12
14
  rrHomeId: number;
13
15
  roomInfo: RoomMap | undefined;
16
+ dockStationStatus: DockingStationStatus | undefined;
14
17
 
15
- constructor(username: string, device: Device, roomMap: RoomMap, routineAsRoom: ServiceArea.Area[], forceRunAtDefault: boolean, log: AnsiLogger) {
16
- const cleanModes = getSupportedCleanModes(device.data.model, forceRunAtDefault);
18
+ constructor(
19
+ username: string,
20
+ device: Device,
21
+ roomMap: RoomMap,
22
+ routineAsRoom: ServiceArea.Area[],
23
+ enableExperimentalFeature: ExperimentalFeatureSetting | undefined,
24
+ log: AnsiLogger,
25
+ ) {
26
+ const cleanModes = getSupportedCleanModes(device.data.model, enableExperimentalFeature);
17
27
  const supportedRunModes = getSupportedRunModes();
18
28
  const supportedAreas = [...getSupportedAreas(device.rooms, roomMap, log), ...routineAsRoom];
19
29
  const deviceName = `${device.name}-${device.duid}`.replace(/\s+/g, '');
20
30
 
21
- log.debug(`Creating RoborockVacuumCleaner for device: ${deviceName}, model: ${device.data.model}, forceRunAtDefault: ${forceRunAtDefault}`);
31
+ log.debug(
32
+ `Creating RoborockVacuumCleaner for device: ${deviceName}, model: ${device.data.model}, forceRunAtDefault: ${enableExperimentalFeature?.advancedFeature?.forceRunAtDefault}`,
33
+ );
22
34
  log.debug(`Supported Clean Modes: ${JSON.stringify(cleanModes)}`);
23
35
  log.debug(`Supported Run Modes: ${JSON.stringify(supportedRunModes)}`);
24
36