matterbridge-roborock-vacuum-plugin 1.0.5

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 (170) hide show
  1. package/.github/workflows/publish.yml +34 -0
  2. package/.tarignore +5 -0
  3. package/LICENSE +202 -0
  4. package/README.md +34 -0
  5. package/README_DEV.md +69 -0
  6. package/bmc-button.svg +22 -0
  7. package/dist/appliances.js +6 -0
  8. package/dist/behaviorFactory.js +18 -0
  9. package/dist/behaviors/BehaviorDeviceGeneric.js +31 -0
  10. package/dist/behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.js +94 -0
  11. package/dist/behaviors/roborock.vacuum/QREVO_EDGE_5V1/initalData.js +81 -0
  12. package/dist/behaviors/roborock.vacuum/QREVO_EDGE_5V1/runtimes.js +39 -0
  13. package/dist/behaviors/roborock.vacuum/default/default.js +58 -0
  14. package/dist/behaviors/roborock.vacuum/default/initalData.js +66 -0
  15. package/dist/clientManager.js +17 -0
  16. package/dist/extensions/AxiosStaticExtensions.js +22 -0
  17. package/dist/extensions/index.js +1 -0
  18. package/dist/helper.js +16 -0
  19. package/dist/index.js +4 -0
  20. package/dist/initialData/getBatteryStatus.js +24 -0
  21. package/dist/initialData/getOperationalStates.js +22 -0
  22. package/dist/initialData/getSupportedAreas.js +69 -0
  23. package/dist/initialData/getSupportedCleanModes.js +11 -0
  24. package/dist/initialData/getSupportedRunModes.js +18 -0
  25. package/dist/initialData/index.js +5 -0
  26. package/dist/model/CloudMessageModel.js +1 -0
  27. package/dist/model/DockingStationStatus.js +24 -0
  28. package/dist/model/RoomMap.js +18 -0
  29. package/dist/notifyMessageTypes.js +9 -0
  30. package/dist/platform.js +146 -0
  31. package/dist/platformRunner.js +249 -0
  32. package/dist/roborockCommunication/RESTAPI/roborockAuthenticateApi.js +73 -0
  33. package/dist/roborockCommunication/RESTAPI/roborockIoTApi.js +61 -0
  34. package/dist/roborockCommunication/Zenum/dockType.js +4 -0
  35. package/dist/roborockCommunication/Zenum/operationStatusCode.js +44 -0
  36. package/dist/roborockCommunication/Zenum/vacuumAndDockErrorCode.js +68 -0
  37. package/dist/roborockCommunication/Zmodel/apiResponse.js +1 -0
  38. package/dist/roborockCommunication/Zmodel/authenticateResponse.js +1 -0
  39. package/dist/roborockCommunication/Zmodel/baseURL.js +1 -0
  40. package/dist/roborockCommunication/Zmodel/device.js +1 -0
  41. package/dist/roborockCommunication/Zmodel/deviceModel.js +28 -0
  42. package/dist/roborockCommunication/Zmodel/deviceSchema.js +1 -0
  43. package/dist/roborockCommunication/Zmodel/deviceStatus.js +22 -0
  44. package/dist/roborockCommunication/Zmodel/dockInfo.js +6 -0
  45. package/dist/roborockCommunication/Zmodel/home.js +1 -0
  46. package/dist/roborockCommunication/Zmodel/homeInfo.js +1 -0
  47. package/dist/roborockCommunication/Zmodel/messageResult.js +7 -0
  48. package/dist/roborockCommunication/Zmodel/networkInfo.js +1 -0
  49. package/dist/roborockCommunication/Zmodel/product.js +1 -0
  50. package/dist/roborockCommunication/Zmodel/room.js +1 -0
  51. package/dist/roborockCommunication/Zmodel/roomInfo.js +22 -0
  52. package/dist/roborockCommunication/Zmodel/userData.js +1 -0
  53. package/dist/roborockCommunication/Zmodel/vacuumError.js +27 -0
  54. package/dist/roborockCommunication/broadcast/abstractClient.js +41 -0
  55. package/dist/roborockCommunication/broadcast/client/LocalNetworkClient.js +148 -0
  56. package/dist/roborockCommunication/broadcast/client/MQTTClient.js +101 -0
  57. package/dist/roborockCommunication/broadcast/client.js +1 -0
  58. package/dist/roborockCommunication/broadcast/clientRouter.js +79 -0
  59. package/dist/roborockCommunication/broadcast/listener/abstractConnectionListener.js +1 -0
  60. package/dist/roborockCommunication/broadcast/listener/abstractMessageHandler.js +1 -0
  61. package/dist/roborockCommunication/broadcast/listener/abstractMessageListener.js +1 -0
  62. package/dist/roborockCommunication/broadcast/listener/implementation/chainedConnectionListener.js +21 -0
  63. package/dist/roborockCommunication/broadcast/listener/implementation/chainedMessageListener.js +11 -0
  64. package/dist/roborockCommunication/broadcast/listener/implementation/simpleMessageListener.js +27 -0
  65. package/dist/roborockCommunication/broadcast/listener/implementation/syncMessageListener.js +35 -0
  66. package/dist/roborockCommunication/broadcast/listener/index.js +1 -0
  67. package/dist/roborockCommunication/broadcast/messageProcessor.js +79 -0
  68. package/dist/roborockCommunication/broadcast/model/dps.js +1 -0
  69. package/dist/roborockCommunication/broadcast/model/messageContext.js +26 -0
  70. package/dist/roborockCommunication/broadcast/model/protocol.js +19 -0
  71. package/dist/roborockCommunication/broadcast/model/requestMessage.js +33 -0
  72. package/dist/roborockCommunication/broadcast/model/responseMessage.js +14 -0
  73. package/dist/roborockCommunication/helper/chunkBuffer.js +17 -0
  74. package/dist/roborockCommunication/helper/cryptoHelper.js +27 -0
  75. package/dist/roborockCommunication/helper/messageDeserializer.js +74 -0
  76. package/dist/roborockCommunication/helper/messageSerializer.js +70 -0
  77. package/dist/roborockCommunication/helper/nameDecoder.js +66 -0
  78. package/dist/roborockCommunication/helper/sequence.js +16 -0
  79. package/dist/roborockCommunication/index.js +9 -0
  80. package/dist/roborockService.js +300 -0
  81. package/dist/rvc.js +39 -0
  82. package/dist/settings.js +1 -0
  83. package/dist/share/function.js +96 -0
  84. package/dist/share/runtimeHelper.js +29 -0
  85. package/eslint.config.js +76 -0
  86. package/matterbridge-roborock-vacuum-plugin.config.json +11 -0
  87. package/matterbridge-roborock-vacuum-plugin.schema.json +57 -0
  88. package/package.json +43 -0
  89. package/prettier.config.js +49 -0
  90. package/src/appliances.ts +15 -0
  91. package/src/behaviorFactory.ts +24 -0
  92. package/src/behaviors/BehaviorDeviceGeneric.ts +39 -0
  93. package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.ts +117 -0
  94. package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/initalData.ts +85 -0
  95. package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/runtimes.ts +29 -0
  96. package/src/behaviors/roborock.vacuum/default/default.ts +78 -0
  97. package/src/behaviors/roborock.vacuum/default/initalData.ts +69 -0
  98. package/src/clientManager.ts +23 -0
  99. package/src/extensions/AxiosStaticExtensions.ts +35 -0
  100. package/src/extensions/index.ts +1 -0
  101. package/src/helper.ts +22 -0
  102. package/src/index.ts +16 -0
  103. package/src/initialData/getBatteryStatus.ts +26 -0
  104. package/src/initialData/getOperationalStates.ts +24 -0
  105. package/src/initialData/getSupportedAreas.ts +95 -0
  106. package/src/initialData/getSupportedCleanModes.ts +13 -0
  107. package/src/initialData/getSupportedRunModes.ts +21 -0
  108. package/src/initialData/index.ts +5 -0
  109. package/src/model/CloudMessageModel.ts +13 -0
  110. package/src/model/DockingStationStatus.ts +37 -0
  111. package/src/model/RoomMap.ts +44 -0
  112. package/src/notifyMessageTypes.ts +8 -0
  113. package/src/platform.ts +192 -0
  114. package/src/platformRunner.ts +292 -0
  115. package/src/roborockCommunication/RESTAPI/roborockAuthenticateApi.ts +98 -0
  116. package/src/roborockCommunication/RESTAPI/roborockIoTApi.ts +70 -0
  117. package/src/roborockCommunication/Zenum/dockType.ts +3 -0
  118. package/src/roborockCommunication/Zenum/operationStatusCode.ts +43 -0
  119. package/src/roborockCommunication/Zenum/vacuumAndDockErrorCode.ts +68 -0
  120. package/src/roborockCommunication/Zmodel/apiResponse.ts +3 -0
  121. package/src/roborockCommunication/Zmodel/authenticateResponse.ts +5 -0
  122. package/src/roborockCommunication/Zmodel/baseURL.ts +5 -0
  123. package/src/roborockCommunication/Zmodel/device.ts +39 -0
  124. package/src/roborockCommunication/Zmodel/deviceModel.ts +27 -0
  125. package/src/roborockCommunication/Zmodel/deviceSchema.ts +8 -0
  126. package/src/roborockCommunication/Zmodel/deviceStatus.ts +30 -0
  127. package/src/roborockCommunication/Zmodel/dockInfo.ts +9 -0
  128. package/src/roborockCommunication/Zmodel/home.ts +13 -0
  129. package/src/roborockCommunication/Zmodel/homeInfo.ts +5 -0
  130. package/src/roborockCommunication/Zmodel/messageResult.ts +72 -0
  131. package/src/roborockCommunication/Zmodel/networkInfo.ts +7 -0
  132. package/src/roborockCommunication/Zmodel/product.ts +9 -0
  133. package/src/roborockCommunication/Zmodel/room.ts +4 -0
  134. package/src/roborockCommunication/Zmodel/roomInfo.ts +25 -0
  135. package/src/roborockCommunication/Zmodel/userData.ts +23 -0
  136. package/src/roborockCommunication/Zmodel/vacuumError.ts +35 -0
  137. package/src/roborockCommunication/broadcast/abstractClient.ts +61 -0
  138. package/src/roborockCommunication/broadcast/client/LocalNetworkClient.ts +177 -0
  139. package/src/roborockCommunication/broadcast/client/MQTTClient.ts +129 -0
  140. package/src/roborockCommunication/broadcast/client.ts +19 -0
  141. package/src/roborockCommunication/broadcast/clientRouter.ts +100 -0
  142. package/src/roborockCommunication/broadcast/listener/abstractConnectionListener.ts +5 -0
  143. package/src/roborockCommunication/broadcast/listener/abstractMessageHandler.ts +11 -0
  144. package/src/roborockCommunication/broadcast/listener/abstractMessageListener.ts +5 -0
  145. package/src/roborockCommunication/broadcast/listener/implementation/chainedConnectionListener.ts +26 -0
  146. package/src/roborockCommunication/broadcast/listener/implementation/chainedMessageListener.ts +16 -0
  147. package/src/roborockCommunication/broadcast/listener/implementation/simpleMessageListener.ts +37 -0
  148. package/src/roborockCommunication/broadcast/listener/implementation/syncMessageListener.ts +48 -0
  149. package/src/roborockCommunication/broadcast/listener/index.ts +3 -0
  150. package/src/roborockCommunication/broadcast/messageProcessor.ts +110 -0
  151. package/src/roborockCommunication/broadcast/model/dps.ts +17 -0
  152. package/src/roborockCommunication/broadcast/model/messageContext.ts +34 -0
  153. package/src/roborockCommunication/broadcast/model/protocol.ts +19 -0
  154. package/src/roborockCommunication/broadcast/model/requestMessage.ts +44 -0
  155. package/src/roborockCommunication/broadcast/model/responseMessage.ts +19 -0
  156. package/src/roborockCommunication/helper/chunkBuffer.ts +18 -0
  157. package/src/roborockCommunication/helper/cryptoHelper.ts +34 -0
  158. package/src/roborockCommunication/helper/messageDeserializer.ts +99 -0
  159. package/src/roborockCommunication/helper/messageSerializer.ts +82 -0
  160. package/src/roborockCommunication/helper/nameDecoder.ts +78 -0
  161. package/src/roborockCommunication/helper/sequence.ts +18 -0
  162. package/src/roborockCommunication/index.ts +15 -0
  163. package/src/roborockService.ts +379 -0
  164. package/src/rvc.ts +66 -0
  165. package/src/settings.ts +1 -0
  166. package/src/share/function.ts +106 -0
  167. package/src/share/runtimeHelper.ts +35 -0
  168. package/tsconfig.json +37 -0
  169. package/tsconfig.production.json +19 -0
  170. package/tslint.json +9 -0
@@ -0,0 +1,146 @@
1
+ import './extensions/index.js';
2
+ import { MatterbridgeDynamicPlatform } from 'matterbridge';
3
+ import * as axios from 'axios';
4
+ import RoborockService from './roborockService.js';
5
+ import { PLUGIN_NAME } from './settings.js';
6
+ import ClientManager from './clientManager.js';
7
+ import { isSupportedDevice } from './helper.js';
8
+ import { PlatformRunner } from './platformRunner.js';
9
+ import { RoborockVacuumCleaner } from './rvc.js';
10
+ import { configurateBehavior } from './behaviorFactory.js';
11
+ import { RoborockAuthenticateApi, RoborockIoTApi } from './roborockCommunication/index.js';
12
+ import { getSupportedAreas } from './initialData/index.js';
13
+ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
14
+ robot;
15
+ rvcInterval;
16
+ roborockService;
17
+ clientManager;
18
+ platformRunner;
19
+ devices;
20
+ serialNumber;
21
+ constructor(matterbridge, log, config) {
22
+ super(matterbridge, log, config);
23
+ if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.0.4')) {
24
+ throw new Error(`This plugin requires Matterbridge version >= "3.0.4". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
25
+ }
26
+ this.log.info('Initializing platform:', this.config.name);
27
+ if (config.whiteList === undefined)
28
+ config.whiteList = [];
29
+ if (config.blackList === undefined)
30
+ config.blackList = [];
31
+ if (config.enableExperimentalFeature === undefined)
32
+ config.enableExperimentalFeature = false;
33
+ this.clientManager = new ClientManager(this.log);
34
+ this.devices = new Map();
35
+ }
36
+ async onStart(reason) {
37
+ this.log.notice('onStart called with reason:', reason ?? 'none');
38
+ const self = this;
39
+ await this.ready;
40
+ await this.clearSelect();
41
+ if (this.config.username === undefined || this.config.password === undefined) {
42
+ this.log.error('"username" and "password" are required in the config');
43
+ return;
44
+ }
45
+ const axiosInstance = axios.default ?? axios;
46
+ axiosInstance.interceptors.request.use((request) => {
47
+ self.log.debug('Axios Request:', {
48
+ method: request.method,
49
+ url: request.url,
50
+ data: request.data,
51
+ headers: request.headers,
52
+ });
53
+ return request;
54
+ });
55
+ axiosInstance.interceptors.response.use((response) => {
56
+ self.log.debug('Axios Response:', {
57
+ status: response.status,
58
+ data: response.data,
59
+ headers: response.headers,
60
+ url: response.config.url,
61
+ });
62
+ return response;
63
+ });
64
+ this.platformRunner = new PlatformRunner(this);
65
+ this.roborockService = new RoborockService(() => new RoborockAuthenticateApi(this.log, axiosInstance), (logger, ud) => new RoborockIoTApi(ud, logger), this.config.refreshInterval ?? 60, this.clientManager, this.log);
66
+ const username = this.config.username;
67
+ const password = this.config.password;
68
+ const userData = await this.roborockService.loginWithPassword(username, password);
69
+ this.log.debug('Initializing - userData:', JSON.stringify(userData));
70
+ const devices = await this.roborockService.listDevices(username);
71
+ this.log.notice('Initializing - devices: ', JSON.stringify(devices));
72
+ let vacuum = undefined;
73
+ if (this.config.whiteList.length > 0) {
74
+ const firstDUID = this.config.whiteList[0];
75
+ vacuum = devices.find((d) => d.duid == firstDUID);
76
+ }
77
+ else {
78
+ vacuum = devices.find((d) => isSupportedDevice(d.data.model));
79
+ }
80
+ if (!vacuum) {
81
+ this.log.error('Initializing: No supported devices found');
82
+ return;
83
+ }
84
+ await this.roborockService.initializeMessageClient(username, vacuum, userData);
85
+ this.devices.set(vacuum.serialNumber, vacuum);
86
+ this.serialNumber = vacuum.serialNumber;
87
+ await this.onConfigurateDevice();
88
+ this.log.notice('onStart finished');
89
+ }
90
+ async onConfigure() {
91
+ await super.onConfigure();
92
+ const self = this;
93
+ this.rvcInterval = setInterval(async () => {
94
+ self.platformRunner?.requestHomeData();
95
+ }, (this.config.refreshInterval ?? 60) * 1000 + 100);
96
+ }
97
+ async onConfigurateDevice() {
98
+ this.log.info('onConfigurateDevice start');
99
+ if (this.platformRunner === undefined || this.roborockService === undefined) {
100
+ this.log.error('Initializing: PlatformRunner or RoborockService is undefined');
101
+ return;
102
+ }
103
+ const vacuum = this.devices.get(this.serialNumber);
104
+ const username = this.config.username;
105
+ if (!vacuum || !username) {
106
+ this.log.error('Initializing: No supported devices found');
107
+ return;
108
+ }
109
+ const self = this;
110
+ await this.roborockService.initializeMessageClientForLocal(vacuum);
111
+ const roomMap = await this.platformRunner.getRoomMapFromDevice(vacuum);
112
+ this.log.debug('Initializing - roomMap: ', JSON.stringify(roomMap));
113
+ const behaviorHandler = configurateBehavior(vacuum.data.model, vacuum.duid, this.roborockService, this.log);
114
+ this.roborockService.setSupportedAreas(vacuum.duid, getSupportedAreas(vacuum.rooms, roomMap, this.log));
115
+ this.robot = new RoborockVacuumCleaner(username, vacuum, roomMap, this.log);
116
+ this.robot.configurateHandler(behaviorHandler);
117
+ this.log.info('vacuum:', JSON.stringify(vacuum));
118
+ this.setSelectDevice(this.robot.serialNumber ?? '', this.robot.deviceName ?? '', undefined, 'hub');
119
+ if (this.validateDevice(this.robot.deviceName ?? '')) {
120
+ await this.registerDevice(this.robot);
121
+ }
122
+ this.roborockService.setDeviceNotify(async function (messageSource, homeData) {
123
+ await self.platformRunner?.updateRobot(messageSource, homeData);
124
+ });
125
+ await this.roborockService.activateDeviceNotify(this.robot.device);
126
+ await self.platformRunner?.requestHomeData();
127
+ this.log.info('onConfigurateDevice finished');
128
+ }
129
+ async onShutdown(reason) {
130
+ await super.onShutdown(reason);
131
+ this.log.notice('onShutdown called with reason:', reason ?? 'none');
132
+ this.rvcInterval && clearInterval(this.rvcInterval);
133
+ if (this.roborockService)
134
+ this.roborockService.stopService();
135
+ if (this.config.unregisterOnShutdown === true)
136
+ await this.unregisterAllDevices(500);
137
+ }
138
+ async onChangeLoggerLevel(logLevel) {
139
+ this.log.notice(`Change ${PLUGIN_NAME} log level: ${logLevel} (was ${this.log.logLevel})`);
140
+ this.log.logLevel = logLevel;
141
+ return Promise.resolve();
142
+ }
143
+ sleep(ms) {
144
+ return new Promise((resolve) => setTimeout(resolve, ms));
145
+ }
146
+ }
@@ -0,0 +1,249 @@
1
+ import { RvcRunMode, PowerSource, ServiceArea, RvcOperationalState, RvcCleanMode } from 'matterbridge/matter/clusters';
2
+ import { getVacuumProperty } from './helper.js';
3
+ import { getRunningMode } from './initialData/getSupportedRunModes.js';
4
+ import { state_to_matter_operational_status, state_to_matter_state } from './share/function.js';
5
+ import RoomMap from './model/RoomMap.js';
6
+ import { getBatteryState, getBatteryStatus, getOperationalErrorState } from './initialData/index.js';
7
+ import { NotifyMessageTypes } from './notifyMessageTypes.js';
8
+ import { Protocol } from './roborockCommunication/broadcast/model/protocol.js';
9
+ import { hasDockingStationError, parseDockingStationStatus } from './model/DockingStationStatus.js';
10
+ import { OperationStatusCode } from './roborockCommunication/Zenum/operationStatusCode.js';
11
+ import { getCurrentCleanModeFromFanPowerFunc, getCurrentCleanModeFromWaterBoxModeFunc, getCurrentCleanModeFunc } from './share/runtimeHelper.js';
12
+ export class PlatformRunner {
13
+ platform;
14
+ constructor(platform) {
15
+ this.platform = platform;
16
+ }
17
+ async updateRobot(messageSource, homeData) {
18
+ if (messageSource === NotifyMessageTypes.HomeData) {
19
+ this.updateFromHomeData(homeData);
20
+ }
21
+ else {
22
+ await this.updateFromMQTTMessage(messageSource, homeData);
23
+ }
24
+ }
25
+ async requestHomeData() {
26
+ const platform = this.platform;
27
+ if (!platform.robot || !platform.robot.rrHomeId)
28
+ return;
29
+ if (platform.roborockService === undefined)
30
+ return;
31
+ const homeData = await platform.roborockService.getHomeDataForUpdating(platform.robot.rrHomeId);
32
+ await platform.platformRunner?.updateRobot(NotifyMessageTypes.HomeData, homeData);
33
+ }
34
+ async getRoomMapFromDevice(device) {
35
+ const platform = this.platform;
36
+ const rooms = device?.rooms ?? [];
37
+ if (device && platform.roborockService) {
38
+ const roomData = await platform.roborockService.getRoomMappings(device.duid);
39
+ return new RoomMap(roomData ?? [], rooms);
40
+ }
41
+ return new RoomMap([], rooms);
42
+ }
43
+ async getRoomMap() {
44
+ const platform = this.platform;
45
+ const rooms = platform.robot?.device.rooms ?? [];
46
+ if (platform.robot?.device === undefined || platform.roborockService === undefined)
47
+ return undefined;
48
+ if (platform.robot.roomInfo === undefined) {
49
+ const roomData = await platform.roborockService.getRoomMappings(platform.robot.device.duid);
50
+ platform.robot.roomInfo = new RoomMap(roomData ?? [], rooms);
51
+ return platform.robot.roomInfo;
52
+ }
53
+ return platform.robot.roomInfo;
54
+ }
55
+ async updateFromMQTTMessage(messageSource, messageData, tracked = false) {
56
+ const platform = this.platform;
57
+ const deviceData = platform.robot?.device.data;
58
+ if (deviceData === undefined) {
59
+ platform.log.error('Device data is undefined');
60
+ return;
61
+ }
62
+ if (!tracked) {
63
+ platform.log.debug(`${messageSource} updateFromMQTTMessage: ${JSON.stringify(messageData)}`);
64
+ }
65
+ const duid = messageData.duid;
66
+ if (platform.robot === undefined)
67
+ return;
68
+ if (!platform.robot.serialNumber) {
69
+ platform.log.error('Robot serial number is undefined');
70
+ return;
71
+ }
72
+ if (platform.robot.serialNumber !== duid) {
73
+ platform.log.notice(`DUID mismatch: ${duid}, device serial number: ${platform.robot.serialNumber}`);
74
+ return;
75
+ }
76
+ switch (messageSource) {
77
+ case NotifyMessageTypes.ErrorOccurred: {
78
+ const errorCode = messageData.errorCode;
79
+ const operationalStateId = getOperationalErrorState(errorCode);
80
+ if (operationalStateId) {
81
+ platform.log.error(`Error occurred: ${errorCode}`);
82
+ platform.robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
83
+ }
84
+ break;
85
+ }
86
+ case NotifyMessageTypes.BatteryUpdate: {
87
+ const batteryLevel = messageData.percentage;
88
+ if (messageData.percentage && batteryLevel) {
89
+ platform.robot.updateAttribute(PowerSource.Cluster.id, 'batPercentRemaining', batteryLevel * 2, platform.log);
90
+ platform.robot.updateAttribute(PowerSource.Cluster.id, 'batChargeLevel', getBatteryStatus(batteryLevel), platform.log);
91
+ }
92
+ break;
93
+ }
94
+ case NotifyMessageTypes.LocalMessage: {
95
+ const data = messageData.statusType;
96
+ if (data) {
97
+ const state = state_to_matter_state(data.state);
98
+ if (state) {
99
+ platform.robot.updateAttribute(RvcRunMode.Cluster.id, 'currentMode', getRunningMode(deviceData.model, state), platform.log);
100
+ }
101
+ const currentRoom = data.cleaning_info?.segment_id ?? -1;
102
+ const currentMappedAreas = this.platform.roborockService?.getSupportedAreas(duid);
103
+ const isMappedArea = currentMappedAreas?.some((x) => x.areaId == currentRoom);
104
+ if (currentRoom !== -1 && isMappedArea) {
105
+ const roomMap = await this.getRoomMap();
106
+ this.platform.log.debug('RoomMap:', JSON.stringify(roomMap));
107
+ this.platform.log.debug('CurrentRoom:', currentRoom);
108
+ platform.robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', currentRoom, platform.log);
109
+ }
110
+ if (data.battery) {
111
+ const batteryLevel = data.battery;
112
+ platform.robot.updateAttribute(PowerSource.Cluster.id, 'batPercentRemaining', batteryLevel * 2, platform.log);
113
+ platform.robot.updateAttribute(PowerSource.Cluster.id, 'batChargeState', getBatteryState(data.state, data.battery), platform.log);
114
+ platform.robot.updateAttribute(PowerSource.Cluster.id, 'batChargeLevel', getBatteryStatus(batteryLevel), platform.log);
115
+ }
116
+ const currentCleanMode = getCurrentCleanModeFunc(deviceData.model)(data.fan_power, data.water_box_mode);
117
+ if (currentCleanMode) {
118
+ platform.robot.updateAttribute(RvcCleanMode.Cluster.id, 'currentMode', currentCleanMode, platform.log);
119
+ }
120
+ this.processAdditionalProps(platform.robot, data);
121
+ }
122
+ break;
123
+ }
124
+ case NotifyMessageTypes.CloudMessage: {
125
+ var data = messageData.data;
126
+ if (!data) {
127
+ data = messageData;
128
+ }
129
+ if (!data)
130
+ return;
131
+ this.handlerCloudMessage(data, duid, deviceData.model);
132
+ break;
133
+ }
134
+ default:
135
+ break;
136
+ }
137
+ }
138
+ handlerCloudMessage(data, duid, model) {
139
+ const platform = this.platform;
140
+ const messageTypes = Object.keys(data.dps).map(Number);
141
+ const self = this;
142
+ messageTypes.forEach(async (messageType) => {
143
+ switch (messageType) {
144
+ case Protocol.status_update: {
145
+ const status = Number(data.dps[messageType]);
146
+ const matterState = state_to_matter_state(status);
147
+ if (matterState) {
148
+ platform.robot.updateAttribute(RvcRunMode.Cluster.id, 'currentMode', getRunningMode(model, matterState), platform.log);
149
+ }
150
+ const operationalStateId = state_to_matter_operational_status(status);
151
+ if (operationalStateId) {
152
+ platform.robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
153
+ }
154
+ break;
155
+ }
156
+ case Protocol.rpc_response: {
157
+ const response = data.dps[messageType];
158
+ if (!self.isStatusUpdate(response.result)) {
159
+ platform.log.notice('Ignore message:', JSON.stringify(data));
160
+ return;
161
+ }
162
+ const roboStatus = response.result[0];
163
+ if (roboStatus) {
164
+ const message = { duid: duid, statusType: { ...roboStatus } };
165
+ platform.log.debug('rpc_response:', JSON.stringify(message));
166
+ await self.updateFromMQTTMessage(NotifyMessageTypes.LocalMessage, message, true);
167
+ }
168
+ break;
169
+ }
170
+ case Protocol.suction_power: {
171
+ const fanPower = data.dps[messageType];
172
+ const currentCleanMode = getCurrentCleanModeFromFanPowerFunc(model)(fanPower);
173
+ if (currentCleanMode) {
174
+ platform.robot.updateAttribute(RvcCleanMode.Cluster.id, 'currentMode', currentCleanMode, platform.log);
175
+ }
176
+ break;
177
+ }
178
+ case Protocol.water_box_mode: {
179
+ const water_box_mode = data.dps[messageType];
180
+ const currentCleanMode = getCurrentCleanModeFromWaterBoxModeFunc(model)(water_box_mode);
181
+ if (currentCleanMode) {
182
+ platform.robot.updateAttribute(RvcCleanMode.Cluster.id, 'currentMode', currentCleanMode, platform.log);
183
+ }
184
+ break;
185
+ }
186
+ case Protocol.additional_props:
187
+ case Protocol.back_type: {
188
+ break;
189
+ }
190
+ default: {
191
+ platform.log.notice(`Unknown message type: ${Protocol[messageType] ?? messageType} ,`, JSON.stringify(data));
192
+ break;
193
+ }
194
+ }
195
+ });
196
+ }
197
+ async processAdditionalProps(robot, message) {
198
+ const platform = this.platform;
199
+ if (platform.config.enableExperimentalFeature && message.dss !== undefined) {
200
+ const dss = parseDockingStationStatus(message.dss);
201
+ this.platform.log.debug('DockingStationStatus:', JSON.stringify(dss));
202
+ if (dss && hasDockingStationError(dss)) {
203
+ platform.robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', RvcOperationalState.OperationalState.Error, platform.log);
204
+ }
205
+ }
206
+ if (message.fan_power !== undefined) {
207
+ const fanPower = message.fan_power;
208
+ }
209
+ }
210
+ isStatusUpdate(result) {
211
+ return result && Array.isArray(result) && result.length > 0 && result[0].msg_ver !== undefined && result[0].msg_ver !== null;
212
+ }
213
+ updateFromHomeData(homeData) {
214
+ const platform = this.platform;
215
+ if (platform.robot === undefined)
216
+ return;
217
+ const device = homeData.devices.find((d) => d.duid === platform.robot?.serialNumber);
218
+ const deviceData = platform.robot?.device.data;
219
+ if (!device || deviceData === undefined) {
220
+ platform.log.error('Device not found in home data');
221
+ return;
222
+ }
223
+ device.schema = homeData.products.find((prd) => prd.id == device.productId || prd.model == device.data.model)?.schema ?? [];
224
+ this.platform.log.debug('updateFromHomeData-homeData:', JSON.stringify(homeData));
225
+ this.platform.log.debug('updateFromHomeData-device:', JSON.stringify(device));
226
+ const batteryLevel = getVacuumProperty(device, 'battery');
227
+ if (batteryLevel) {
228
+ platform.robot.updateAttribute(PowerSource.Cluster.id, 'batPercentRemaining', batteryLevel ? batteryLevel * 2 : 200, platform.log);
229
+ platform.robot.updateAttribute(PowerSource.Cluster.id, 'batChargeLevel', getBatteryStatus(batteryLevel), platform.log);
230
+ }
231
+ const state = getVacuumProperty(device, 'state');
232
+ const matterState = state_to_matter_state(state);
233
+ if (!state || !matterState) {
234
+ return;
235
+ }
236
+ this.platform.log.debug(`updateFromHomeData-RvcRunMode code: ${state} name: ${OperationStatusCode[state]}, matterState: ${RvcRunMode.ModeTag[matterState]}`);
237
+ if (matterState) {
238
+ platform.robot.updateAttribute(RvcRunMode.Cluster.id, 'currentMode', getRunningMode(deviceData.model, matterState), platform.log);
239
+ }
240
+ const operationalStateId = state_to_matter_operational_status(state);
241
+ if (operationalStateId) {
242
+ this.platform.log.debug(`updateFromHomeData-OperationalState: ${RvcOperationalState.OperationalState[operationalStateId]}`);
243
+ platform.robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
244
+ }
245
+ if (batteryLevel) {
246
+ platform.robot.updateAttribute(PowerSource.Cluster.id, 'batChargeState', getBatteryState(state, batteryLevel), platform.log);
247
+ }
248
+ }
249
+ }
@@ -0,0 +1,73 @@
1
+ import axios from 'axios';
2
+ import crypto from 'crypto';
3
+ import { URLSearchParams } from 'node:url';
4
+ export class RoborockAuthenticateApi {
5
+ logger;
6
+ axiosFactory;
7
+ deviceId;
8
+ username;
9
+ authToken;
10
+ constructor(logger, axiosFactory = axios) {
11
+ this.deviceId = crypto.randomUUID();
12
+ this.axiosFactory = axiosFactory;
13
+ this.logger = logger;
14
+ }
15
+ async loginWithPassword(username, password) {
16
+ const api = await this.getAPIFor(username);
17
+ const response = await api.post('api/v1/login', new URLSearchParams({
18
+ username: username,
19
+ password: password,
20
+ needtwostepauth: 'false',
21
+ }).toString());
22
+ return this.auth(username, response.data);
23
+ }
24
+ async getHomeDetails() {
25
+ if (!this.username || !this.authToken) {
26
+ return undefined;
27
+ }
28
+ const api = await this.getAPIFor(this.username);
29
+ const response = await api.get('api/v1/getHomeDetail');
30
+ const apiResponse = response.data;
31
+ if (!apiResponse.data) {
32
+ throw new Error('Failed to retrieve the home details');
33
+ }
34
+ return apiResponse.data;
35
+ }
36
+ async getAPIFor(username) {
37
+ const baseUrl = await this.getBaseUrl(username);
38
+ return this.apiForUser(username, baseUrl);
39
+ }
40
+ async getBaseUrl(username) {
41
+ const api = await this.apiForUser(username);
42
+ const response = await api.post('api/v1/getUrlByEmail', new URLSearchParams({
43
+ email: username,
44
+ needtwostepauth: 'false',
45
+ }).toString());
46
+ const apiResponse = response.data;
47
+ if (!apiResponse.data) {
48
+ throw new Error('Failed to retrieve base URL: ' + apiResponse.msg);
49
+ }
50
+ return apiResponse.data.url;
51
+ }
52
+ async apiForUser(username, baseUrl = 'https://usiot.roborock.com') {
53
+ return this.axiosFactory.create({
54
+ baseURL: baseUrl,
55
+ headers: {
56
+ header_clientid: crypto.createHash('md5').update(username).update(this.deviceId).digest('base64'),
57
+ Authorization: this.authToken,
58
+ },
59
+ });
60
+ }
61
+ auth(username, response) {
62
+ const userdata = response.data;
63
+ if (!userdata || !userdata.token) {
64
+ throw new Error('Authentication failed: ' + response.msg + ' code: ' + response.code);
65
+ }
66
+ this.loginWithAuthToken(username, userdata.token);
67
+ return userdata;
68
+ }
69
+ loginWithAuthToken(username, token) {
70
+ this.username = username;
71
+ this.authToken = token;
72
+ }
73
+ }
@@ -0,0 +1,61 @@
1
+ import axios from 'axios';
2
+ import crypto from 'crypto';
3
+ export class RoborockIoTApi {
4
+ logger;
5
+ api;
6
+ constructor(userdata, logger) {
7
+ this.logger = logger;
8
+ this.api = axios.create({ baseURL: userdata.rriot.r.a });
9
+ this.api.interceptors.request.use((config) => {
10
+ try {
11
+ const timestamp = Math.floor(Date.now() / 1000);
12
+ const nonce = crypto
13
+ .randomBytes(6)
14
+ .toString('base64')
15
+ .substring(0, 6)
16
+ .replace(/[+/]/g, (m) => (m === '+' ? 'X' : 'Y'));
17
+ const url = this.api ? new URL(this.api.getUri(config)).pathname : '';
18
+ const data = [userdata.rriot.u, userdata.rriot.s, nonce, timestamp, crypto.createHash('md5').update(url).digest('hex'), '', ''].join(':');
19
+ const hmac = crypto.createHmac('sha256', userdata.rriot.h).update(data).digest('base64');
20
+ config.headers['Authorization'] = `Hawk id="${userdata.rriot.u}", s="${userdata.rriot.s}", ts="${timestamp}", nonce="${nonce}", mac="${hmac}"`;
21
+ }
22
+ catch (error) {
23
+ this.logger.error('Failed to initialize RESTAPI' + JSON.stringify(error));
24
+ }
25
+ return config;
26
+ });
27
+ }
28
+ async getHome(homeId) {
29
+ const result = await this.api.get(`user/homes/${homeId}`);
30
+ const apiResponse = result.data;
31
+ if (apiResponse.result) {
32
+ return apiResponse.result;
33
+ }
34
+ else {
35
+ this.logger.error('Failed to retrieve the home data');
36
+ return undefined;
37
+ }
38
+ }
39
+ async getHomev2(homeId) {
40
+ const result = await this.api.get('v2/user/homes/' + homeId);
41
+ const apiResponse = result.data;
42
+ if (apiResponse.result) {
43
+ return apiResponse.result;
44
+ }
45
+ else {
46
+ this.logger.error('Failed to retrieve the home data');
47
+ return undefined;
48
+ }
49
+ }
50
+ async getHomev3(homeId) {
51
+ const result = await this.api.get('v3/user/homes/' + homeId);
52
+ const apiResponse = result.data;
53
+ if (apiResponse.result) {
54
+ return apiResponse.result;
55
+ }
56
+ else {
57
+ this.logger.error('Failed to retrieve the home data');
58
+ return undefined;
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,4 @@
1
+ export var DockType;
2
+ (function (DockType) {
3
+ DockType[DockType["qrevo_curv_dock"] = 17] = "qrevo_curv_dock";
4
+ })(DockType || (DockType = {}));
@@ -0,0 +1,44 @@
1
+ export var OperationStatusCode;
2
+ (function (OperationStatusCode) {
3
+ OperationStatusCode[OperationStatusCode["Unknown"] = 0] = "Unknown";
4
+ OperationStatusCode[OperationStatusCode["Initiating"] = 1] = "Initiating";
5
+ OperationStatusCode[OperationStatusCode["Sleeping"] = 2] = "Sleeping";
6
+ OperationStatusCode[OperationStatusCode["Idle"] = 3] = "Idle";
7
+ OperationStatusCode[OperationStatusCode["RemoteControl"] = 4] = "RemoteControl";
8
+ OperationStatusCode[OperationStatusCode["Cleaning"] = 5] = "Cleaning";
9
+ OperationStatusCode[OperationStatusCode["ReturningDock"] = 6] = "ReturningDock";
10
+ OperationStatusCode[OperationStatusCode["ManualMode"] = 7] = "ManualMode";
11
+ OperationStatusCode[OperationStatusCode["Charging"] = 8] = "Charging";
12
+ OperationStatusCode[OperationStatusCode["ChargingError"] = 9] = "ChargingError";
13
+ OperationStatusCode[OperationStatusCode["Paused"] = 10] = "Paused";
14
+ OperationStatusCode[OperationStatusCode["SpotCleaning"] = 11] = "SpotCleaning";
15
+ OperationStatusCode[OperationStatusCode["InError"] = 12] = "InError";
16
+ OperationStatusCode[OperationStatusCode["ShuttingDown"] = 13] = "ShuttingDown";
17
+ OperationStatusCode[OperationStatusCode["Updating"] = 14] = "Updating";
18
+ OperationStatusCode[OperationStatusCode["Docking"] = 15] = "Docking";
19
+ OperationStatusCode[OperationStatusCode["GoTo"] = 16] = "GoTo";
20
+ OperationStatusCode[OperationStatusCode["ZoneClean"] = 17] = "ZoneClean";
21
+ OperationStatusCode[OperationStatusCode["RoomClean"] = 18] = "RoomClean";
22
+ OperationStatusCode[OperationStatusCode["EmptyingDustContainer"] = 22] = "EmptyingDustContainer";
23
+ OperationStatusCode[OperationStatusCode["WashingTheMop"] = 23] = "WashingTheMop";
24
+ OperationStatusCode[OperationStatusCode["WashingTheMop2"] = 25] = "WashingTheMop2";
25
+ OperationStatusCode[OperationStatusCode["GoingToWashTheMop"] = 26] = "GoingToWashTheMop";
26
+ OperationStatusCode[OperationStatusCode["InCall"] = 28] = "InCall";
27
+ OperationStatusCode[OperationStatusCode["Mapping"] = 29] = "Mapping";
28
+ OperationStatusCode[OperationStatusCode["SOMETHING_NEED_TO_FIGUREOUT"] = 30] = "SOMETHING_NEED_TO_FIGUREOUT";
29
+ OperationStatusCode[OperationStatusCode["Patrol"] = 32] = "Patrol";
30
+ OperationStatusCode[OperationStatusCode["FullyCharged"] = 100] = "FullyCharged";
31
+ OperationStatusCode[OperationStatusCode["DeviceOffline"] = 101] = "DeviceOffline";
32
+ OperationStatusCode[OperationStatusCode["Locked"] = 103] = "Locked";
33
+ OperationStatusCode[OperationStatusCode["AirDryingStopping"] = 202] = "AirDryingStopping";
34
+ OperationStatusCode[OperationStatusCode["RobotStatusMopping"] = 6301] = "RobotStatusMopping";
35
+ OperationStatusCode[OperationStatusCode["CleanMopCleaning"] = 6302] = "CleanMopCleaning";
36
+ OperationStatusCode[OperationStatusCode["CleanMopMopping"] = 6303] = "CleanMopMopping";
37
+ OperationStatusCode[OperationStatusCode["RoomMopping"] = 6304] = "RoomMopping";
38
+ OperationStatusCode[OperationStatusCode["RoomCleanMopCleaning"] = 6305] = "RoomCleanMopCleaning";
39
+ OperationStatusCode[OperationStatusCode["RoomCleanMopMopping"] = 6306] = "RoomCleanMopMopping";
40
+ OperationStatusCode[OperationStatusCode["ZoneMopping"] = 6307] = "ZoneMopping";
41
+ OperationStatusCode[OperationStatusCode["ZoneCleanMopCleaning"] = 6308] = "ZoneCleanMopCleaning";
42
+ OperationStatusCode[OperationStatusCode["ZoneCleanMopMopping"] = 6309] = "ZoneCleanMopMopping";
43
+ OperationStatusCode[OperationStatusCode["BackToDockWashingDuster"] = 6310] = "BackToDockWashingDuster";
44
+ })(OperationStatusCode || (OperationStatusCode = {}));
@@ -0,0 +1,68 @@
1
+ export var VacuumErrorCode;
2
+ (function (VacuumErrorCode) {
3
+ VacuumErrorCode[VacuumErrorCode["None"] = 0] = "None";
4
+ VacuumErrorCode[VacuumErrorCode["LidarBlocked"] = 1] = "LidarBlocked";
5
+ VacuumErrorCode[VacuumErrorCode["BumperStuck"] = 2] = "BumperStuck";
6
+ VacuumErrorCode[VacuumErrorCode["WheelsSuspended"] = 3] = "WheelsSuspended";
7
+ VacuumErrorCode[VacuumErrorCode["CliffSensorError"] = 4] = "CliffSensorError";
8
+ VacuumErrorCode[VacuumErrorCode["MainBrushJammed"] = 5] = "MainBrushJammed";
9
+ VacuumErrorCode[VacuumErrorCode["SideBrushJammed"] = 6] = "SideBrushJammed";
10
+ VacuumErrorCode[VacuumErrorCode["WheelsJammed"] = 7] = "WheelsJammed";
11
+ VacuumErrorCode[VacuumErrorCode["RobotTrapped"] = 8] = "RobotTrapped";
12
+ VacuumErrorCode[VacuumErrorCode["NoDustbin"] = 9] = "NoDustbin";
13
+ VacuumErrorCode[VacuumErrorCode["StrainerError"] = 10] = "StrainerError";
14
+ VacuumErrorCode[VacuumErrorCode["CompassError"] = 11] = "CompassError";
15
+ VacuumErrorCode[VacuumErrorCode["LowBattery"] = 12] = "LowBattery";
16
+ VacuumErrorCode[VacuumErrorCode["ChargingError"] = 13] = "ChargingError";
17
+ VacuumErrorCode[VacuumErrorCode["BatteryError"] = 14] = "BatteryError";
18
+ VacuumErrorCode[VacuumErrorCode["WallSensorDirty"] = 15] = "WallSensorDirty";
19
+ VacuumErrorCode[VacuumErrorCode["RobotTilted"] = 16] = "RobotTilted";
20
+ VacuumErrorCode[VacuumErrorCode["SideBrushError"] = 17] = "SideBrushError";
21
+ VacuumErrorCode[VacuumErrorCode["FanError"] = 18] = "FanError";
22
+ VacuumErrorCode[VacuumErrorCode["DockNotConnectedToPower"] = 19] = "DockNotConnectedToPower";
23
+ VacuumErrorCode[VacuumErrorCode["OpticalFlowSensorDirt"] = 20] = "OpticalFlowSensorDirt";
24
+ VacuumErrorCode[VacuumErrorCode["VerticalBumperPressed"] = 21] = "VerticalBumperPressed";
25
+ VacuumErrorCode[VacuumErrorCode["DockLocatorError"] = 22] = "DockLocatorError";
26
+ VacuumErrorCode[VacuumErrorCode["ReturnToDockFail"] = 23] = "ReturnToDockFail";
27
+ VacuumErrorCode[VacuumErrorCode["NogoZoneDetected"] = 24] = "NogoZoneDetected";
28
+ VacuumErrorCode[VacuumErrorCode["CameraError"] = 25] = "CameraError";
29
+ VacuumErrorCode[VacuumErrorCode["WallSensorError"] = 26] = "WallSensorError";
30
+ VacuumErrorCode[VacuumErrorCode["VibrariseJammed"] = 27] = "VibrariseJammed";
31
+ VacuumErrorCode[VacuumErrorCode["RobotOnCarpet"] = 28] = "RobotOnCarpet";
32
+ VacuumErrorCode[VacuumErrorCode["FilterBlocked"] = 29] = "FilterBlocked";
33
+ VacuumErrorCode[VacuumErrorCode["InvisibleWallDetected"] = 30] = "InvisibleWallDetected";
34
+ VacuumErrorCode[VacuumErrorCode["CannotCrossCarpet"] = 31] = "CannotCrossCarpet";
35
+ VacuumErrorCode[VacuumErrorCode["InternalError"] = 32] = "InternalError";
36
+ VacuumErrorCode[VacuumErrorCode["CleanAutoEmptyDock"] = 34] = "CleanAutoEmptyDock";
37
+ VacuumErrorCode[VacuumErrorCode["AutoEmptyDockVoltage"] = 35] = "AutoEmptyDockVoltage";
38
+ VacuumErrorCode[VacuumErrorCode["MoppingRollerJammed"] = 36] = "MoppingRollerJammed";
39
+ VacuumErrorCode[VacuumErrorCode["MoppingRollerNotLowered"] = 37] = "MoppingRollerNotLowered";
40
+ VacuumErrorCode[VacuumErrorCode["ClearWaterBoxHoare"] = 38] = "ClearWaterBoxHoare";
41
+ VacuumErrorCode[VacuumErrorCode["DirtyWaterBoxHoare"] = 39] = "DirtyWaterBoxHoare";
42
+ VacuumErrorCode[VacuumErrorCode["SinkStrainerHoare"] = 40] = "SinkStrainerHoare";
43
+ VacuumErrorCode[VacuumErrorCode["ClearWaterTankEmpty"] = 41] = "ClearWaterTankEmpty";
44
+ VacuumErrorCode[VacuumErrorCode["ClearBrushInstalledProperly"] = 42] = "ClearBrushInstalledProperly";
45
+ VacuumErrorCode[VacuumErrorCode["ClearBrushPositioningError"] = 43] = "ClearBrushPositioningError";
46
+ VacuumErrorCode[VacuumErrorCode["FilterScreenException"] = 44] = "FilterScreenException";
47
+ VacuumErrorCode[VacuumErrorCode["MoppingRollerJammed2"] = 45] = "MoppingRollerJammed2";
48
+ VacuumErrorCode[VacuumErrorCode["UpWaterException"] = 48] = "UpWaterException";
49
+ VacuumErrorCode[VacuumErrorCode["DrainWaterException"] = 49] = "DrainWaterException";
50
+ VacuumErrorCode[VacuumErrorCode["TemperatureProtection"] = 51] = "TemperatureProtection";
51
+ VacuumErrorCode[VacuumErrorCode["CleanCarouselException"] = 52] = "CleanCarouselException";
52
+ VacuumErrorCode[VacuumErrorCode["CleanCarouselWaterFull"] = 53] = "CleanCarouselWaterFull";
53
+ VacuumErrorCode[VacuumErrorCode["WaterCarriageDrop"] = 54] = "WaterCarriageDrop";
54
+ VacuumErrorCode[VacuumErrorCode["CheckCleanCarouse"] = 55] = "CheckCleanCarouse";
55
+ VacuumErrorCode[VacuumErrorCode["AudioError"] = 56] = "AudioError";
56
+ })(VacuumErrorCode || (VacuumErrorCode = {}));
57
+ export var DockErrorCode;
58
+ (function (DockErrorCode) {
59
+ DockErrorCode[DockErrorCode["None"] = 0] = "None";
60
+ DockErrorCode[DockErrorCode["DuctBlockage"] = 34] = "DuctBlockage";
61
+ DockErrorCode[DockErrorCode["WaterEmpty"] = 38] = "WaterEmpty";
62
+ DockErrorCode[DockErrorCode["WasteWaterTankFull"] = 39] = "WasteWaterTankFull";
63
+ DockErrorCode[DockErrorCode["MaintenanceBrushJammed"] = 42] = "MaintenanceBrushJammed";
64
+ DockErrorCode[DockErrorCode["DirtyTankLatchOpen"] = 44] = "DirtyTankLatchOpen";
65
+ DockErrorCode[DockErrorCode["NoDustbin"] = 46] = "NoDustbin";
66
+ DockErrorCode[DockErrorCode["CleaningTankFullOrBlocked"] = 53] = "CleaningTankFullOrBlocked";
67
+ })(DockErrorCode || (DockErrorCode = {}));
68
+ export const SUPPORTED_ATTACHMENTS = ['WATERTANK', 'MOP'];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};