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.
- package/.github/workflows/publish.yml +34 -0
- package/.tarignore +5 -0
- package/LICENSE +202 -0
- package/README.md +34 -0
- package/README_DEV.md +69 -0
- package/bmc-button.svg +22 -0
- package/dist/appliances.js +6 -0
- package/dist/behaviorFactory.js +18 -0
- package/dist/behaviors/BehaviorDeviceGeneric.js +31 -0
- package/dist/behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.js +94 -0
- package/dist/behaviors/roborock.vacuum/QREVO_EDGE_5V1/initalData.js +81 -0
- package/dist/behaviors/roborock.vacuum/QREVO_EDGE_5V1/runtimes.js +39 -0
- package/dist/behaviors/roborock.vacuum/default/default.js +58 -0
- package/dist/behaviors/roborock.vacuum/default/initalData.js +66 -0
- package/dist/clientManager.js +17 -0
- package/dist/extensions/AxiosStaticExtensions.js +22 -0
- package/dist/extensions/index.js +1 -0
- package/dist/helper.js +16 -0
- package/dist/index.js +4 -0
- package/dist/initialData/getBatteryStatus.js +24 -0
- package/dist/initialData/getOperationalStates.js +22 -0
- package/dist/initialData/getSupportedAreas.js +69 -0
- package/dist/initialData/getSupportedCleanModes.js +11 -0
- package/dist/initialData/getSupportedRunModes.js +18 -0
- package/dist/initialData/index.js +5 -0
- package/dist/model/CloudMessageModel.js +1 -0
- package/dist/model/DockingStationStatus.js +24 -0
- package/dist/model/RoomMap.js +18 -0
- package/dist/notifyMessageTypes.js +9 -0
- package/dist/platform.js +146 -0
- package/dist/platformRunner.js +249 -0
- package/dist/roborockCommunication/RESTAPI/roborockAuthenticateApi.js +73 -0
- package/dist/roborockCommunication/RESTAPI/roborockIoTApi.js +61 -0
- package/dist/roborockCommunication/Zenum/dockType.js +4 -0
- package/dist/roborockCommunication/Zenum/operationStatusCode.js +44 -0
- package/dist/roborockCommunication/Zenum/vacuumAndDockErrorCode.js +68 -0
- package/dist/roborockCommunication/Zmodel/apiResponse.js +1 -0
- package/dist/roborockCommunication/Zmodel/authenticateResponse.js +1 -0
- package/dist/roborockCommunication/Zmodel/baseURL.js +1 -0
- package/dist/roborockCommunication/Zmodel/device.js +1 -0
- package/dist/roborockCommunication/Zmodel/deviceModel.js +28 -0
- package/dist/roborockCommunication/Zmodel/deviceSchema.js +1 -0
- package/dist/roborockCommunication/Zmodel/deviceStatus.js +22 -0
- package/dist/roborockCommunication/Zmodel/dockInfo.js +6 -0
- package/dist/roborockCommunication/Zmodel/home.js +1 -0
- package/dist/roborockCommunication/Zmodel/homeInfo.js +1 -0
- package/dist/roborockCommunication/Zmodel/messageResult.js +7 -0
- package/dist/roborockCommunication/Zmodel/networkInfo.js +1 -0
- package/dist/roborockCommunication/Zmodel/product.js +1 -0
- package/dist/roborockCommunication/Zmodel/room.js +1 -0
- package/dist/roborockCommunication/Zmodel/roomInfo.js +22 -0
- package/dist/roborockCommunication/Zmodel/userData.js +1 -0
- package/dist/roborockCommunication/Zmodel/vacuumError.js +27 -0
- package/dist/roborockCommunication/broadcast/abstractClient.js +41 -0
- package/dist/roborockCommunication/broadcast/client/LocalNetworkClient.js +148 -0
- package/dist/roborockCommunication/broadcast/client/MQTTClient.js +101 -0
- package/dist/roborockCommunication/broadcast/client.js +1 -0
- package/dist/roborockCommunication/broadcast/clientRouter.js +79 -0
- package/dist/roborockCommunication/broadcast/listener/abstractConnectionListener.js +1 -0
- package/dist/roborockCommunication/broadcast/listener/abstractMessageHandler.js +1 -0
- package/dist/roborockCommunication/broadcast/listener/abstractMessageListener.js +1 -0
- package/dist/roborockCommunication/broadcast/listener/implementation/chainedConnectionListener.js +21 -0
- package/dist/roborockCommunication/broadcast/listener/implementation/chainedMessageListener.js +11 -0
- package/dist/roborockCommunication/broadcast/listener/implementation/simpleMessageListener.js +27 -0
- package/dist/roborockCommunication/broadcast/listener/implementation/syncMessageListener.js +35 -0
- package/dist/roborockCommunication/broadcast/listener/index.js +1 -0
- package/dist/roborockCommunication/broadcast/messageProcessor.js +79 -0
- package/dist/roborockCommunication/broadcast/model/dps.js +1 -0
- package/dist/roborockCommunication/broadcast/model/messageContext.js +26 -0
- package/dist/roborockCommunication/broadcast/model/protocol.js +19 -0
- package/dist/roborockCommunication/broadcast/model/requestMessage.js +33 -0
- package/dist/roborockCommunication/broadcast/model/responseMessage.js +14 -0
- package/dist/roborockCommunication/helper/chunkBuffer.js +17 -0
- package/dist/roborockCommunication/helper/cryptoHelper.js +27 -0
- package/dist/roborockCommunication/helper/messageDeserializer.js +74 -0
- package/dist/roborockCommunication/helper/messageSerializer.js +70 -0
- package/dist/roborockCommunication/helper/nameDecoder.js +66 -0
- package/dist/roborockCommunication/helper/sequence.js +16 -0
- package/dist/roborockCommunication/index.js +9 -0
- package/dist/roborockService.js +300 -0
- package/dist/rvc.js +39 -0
- package/dist/settings.js +1 -0
- package/dist/share/function.js +96 -0
- package/dist/share/runtimeHelper.js +29 -0
- package/eslint.config.js +76 -0
- package/matterbridge-roborock-vacuum-plugin.config.json +11 -0
- package/matterbridge-roborock-vacuum-plugin.schema.json +57 -0
- package/package.json +43 -0
- package/prettier.config.js +49 -0
- package/src/appliances.ts +15 -0
- package/src/behaviorFactory.ts +24 -0
- package/src/behaviors/BehaviorDeviceGeneric.ts +39 -0
- package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/a187.ts +117 -0
- package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/initalData.ts +85 -0
- package/src/behaviors/roborock.vacuum/QREVO_EDGE_5V1/runtimes.ts +29 -0
- package/src/behaviors/roborock.vacuum/default/default.ts +78 -0
- package/src/behaviors/roborock.vacuum/default/initalData.ts +69 -0
- package/src/clientManager.ts +23 -0
- package/src/extensions/AxiosStaticExtensions.ts +35 -0
- package/src/extensions/index.ts +1 -0
- package/src/helper.ts +22 -0
- package/src/index.ts +16 -0
- package/src/initialData/getBatteryStatus.ts +26 -0
- package/src/initialData/getOperationalStates.ts +24 -0
- package/src/initialData/getSupportedAreas.ts +95 -0
- package/src/initialData/getSupportedCleanModes.ts +13 -0
- package/src/initialData/getSupportedRunModes.ts +21 -0
- package/src/initialData/index.ts +5 -0
- package/src/model/CloudMessageModel.ts +13 -0
- package/src/model/DockingStationStatus.ts +37 -0
- package/src/model/RoomMap.ts +44 -0
- package/src/notifyMessageTypes.ts +8 -0
- package/src/platform.ts +192 -0
- package/src/platformRunner.ts +292 -0
- package/src/roborockCommunication/RESTAPI/roborockAuthenticateApi.ts +98 -0
- package/src/roborockCommunication/RESTAPI/roborockIoTApi.ts +70 -0
- package/src/roborockCommunication/Zenum/dockType.ts +3 -0
- package/src/roborockCommunication/Zenum/operationStatusCode.ts +43 -0
- package/src/roborockCommunication/Zenum/vacuumAndDockErrorCode.ts +68 -0
- package/src/roborockCommunication/Zmodel/apiResponse.ts +3 -0
- package/src/roborockCommunication/Zmodel/authenticateResponse.ts +5 -0
- package/src/roborockCommunication/Zmodel/baseURL.ts +5 -0
- package/src/roborockCommunication/Zmodel/device.ts +39 -0
- package/src/roborockCommunication/Zmodel/deviceModel.ts +27 -0
- package/src/roborockCommunication/Zmodel/deviceSchema.ts +8 -0
- package/src/roborockCommunication/Zmodel/deviceStatus.ts +30 -0
- package/src/roborockCommunication/Zmodel/dockInfo.ts +9 -0
- package/src/roborockCommunication/Zmodel/home.ts +13 -0
- package/src/roborockCommunication/Zmodel/homeInfo.ts +5 -0
- package/src/roborockCommunication/Zmodel/messageResult.ts +72 -0
- package/src/roborockCommunication/Zmodel/networkInfo.ts +7 -0
- package/src/roborockCommunication/Zmodel/product.ts +9 -0
- package/src/roborockCommunication/Zmodel/room.ts +4 -0
- package/src/roborockCommunication/Zmodel/roomInfo.ts +25 -0
- package/src/roborockCommunication/Zmodel/userData.ts +23 -0
- package/src/roborockCommunication/Zmodel/vacuumError.ts +35 -0
- package/src/roborockCommunication/broadcast/abstractClient.ts +61 -0
- package/src/roborockCommunication/broadcast/client/LocalNetworkClient.ts +177 -0
- package/src/roborockCommunication/broadcast/client/MQTTClient.ts +129 -0
- package/src/roborockCommunication/broadcast/client.ts +19 -0
- package/src/roborockCommunication/broadcast/clientRouter.ts +100 -0
- package/src/roborockCommunication/broadcast/listener/abstractConnectionListener.ts +5 -0
- package/src/roborockCommunication/broadcast/listener/abstractMessageHandler.ts +11 -0
- package/src/roborockCommunication/broadcast/listener/abstractMessageListener.ts +5 -0
- package/src/roborockCommunication/broadcast/listener/implementation/chainedConnectionListener.ts +26 -0
- package/src/roborockCommunication/broadcast/listener/implementation/chainedMessageListener.ts +16 -0
- package/src/roborockCommunication/broadcast/listener/implementation/simpleMessageListener.ts +37 -0
- package/src/roborockCommunication/broadcast/listener/implementation/syncMessageListener.ts +48 -0
- package/src/roborockCommunication/broadcast/listener/index.ts +3 -0
- package/src/roborockCommunication/broadcast/messageProcessor.ts +110 -0
- package/src/roborockCommunication/broadcast/model/dps.ts +17 -0
- package/src/roborockCommunication/broadcast/model/messageContext.ts +34 -0
- package/src/roborockCommunication/broadcast/model/protocol.ts +19 -0
- package/src/roborockCommunication/broadcast/model/requestMessage.ts +44 -0
- package/src/roborockCommunication/broadcast/model/responseMessage.ts +19 -0
- package/src/roborockCommunication/helper/chunkBuffer.ts +18 -0
- package/src/roborockCommunication/helper/cryptoHelper.ts +34 -0
- package/src/roborockCommunication/helper/messageDeserializer.ts +99 -0
- package/src/roborockCommunication/helper/messageSerializer.ts +82 -0
- package/src/roborockCommunication/helper/nameDecoder.ts +78 -0
- package/src/roborockCommunication/helper/sequence.ts +18 -0
- package/src/roborockCommunication/index.ts +15 -0
- package/src/roborockService.ts +379 -0
- package/src/rvc.ts +66 -0
- package/src/settings.ts +1 -0
- package/src/share/function.ts +106 -0
- package/src/share/runtimeHelper.ts +35 -0
- package/tsconfig.json +37 -0
- package/tsconfig.production.json +19 -0
- package/tslint.json +9 -0
package/dist/platform.js
ADDED
|
@@ -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,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 {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|