matterbridge-roborock-vacuum-plugin 1.1.0-rc18 → 1.1.1-rc01
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/dist/helper.js +2 -7
- package/dist/model/RoomMap.js +1 -1
- package/dist/model/roomIndexMap.js +8 -4
- package/dist/platform.js +4 -3
- package/dist/platformRunner.js +10 -268
- package/dist/runtimes/handleCloudMessage.js +110 -0
- package/dist/runtimes/handleHomeDataMessage.js +57 -0
- package/dist/runtimes/handleLocalMessage.js +169 -0
- package/dist/tests/testData/mockData.js +359 -0
- package/matterbridge-roborock-vacuum-plugin.config.json +2 -2
- package/matterbridge-roborock-vacuum-plugin.schema.json +10 -37
- package/package.json +2 -2
- package/src/behaviors/roborock.vacuum/default/runtimes.ts +1 -1
- package/src/behaviors/roborock.vacuum/smart/runtimes.ts +1 -1
- package/src/helper.ts +2 -12
- package/src/initialData/getSupportedAreas.ts +1 -9
- package/src/model/RoomMap.ts +4 -30
- package/src/model/roomIndexMap.ts +10 -6
- package/src/platform.ts +6 -3
- package/src/platformRunner.ts +12 -350
- package/src/roborockCommunication/Zmodel/device.ts +13 -1
- package/src/roborockCommunication/Zmodel/messageResult.ts +28 -27
- package/src/roborockCommunication/Zmodel/userData.ts +2 -1
- package/src/runtimes/handleCloudMessage.ts +134 -0
- package/src/runtimes/handleHomeDataMessage.ts +67 -0
- package/src/runtimes/handleLocalMessage.ts +209 -0
- package/src/share/runtimeHelper.ts +1 -1
- package/src/tests/helper.test.ts +59 -10
- package/src/tests/roborockService.setSelectedAreas.test.ts +61 -0
- package/src/tests/runtimes/handleCloudMessage.test.ts +200 -0
- package/src/tests/runtimes/handleHomeDataMessage.test.ts +53 -0
- package/src/tests/runtimes/handleLocalMessage.test.ts +222 -0
- package/src/tests/testData/mockData.ts +370 -0
package/dist/helper.js
CHANGED
|
@@ -55,16 +55,13 @@ export async function getRoomMap(duid, platform) {
|
|
|
55
55
|
export async function getRoomMapFromDevice(device, platform) {
|
|
56
56
|
const rooms = device?.rooms ?? [];
|
|
57
57
|
const enableMultipleMap = (platform.enableExperimentalFeature?.enableExperimentalFeature && platform.enableExperimentalFeature?.advancedFeature.enableMultipleMap) ?? false;
|
|
58
|
-
platform.log.notice('-------------------------------------------0--------------------------------------------------------');
|
|
59
|
-
platform.log.notice(`getRoomMapFromDevice - device.rooms: ${debugStringify(rooms)}`);
|
|
60
58
|
if (device && platform.roborockService) {
|
|
61
59
|
const mapInfo = await platform.roborockService.getMapInformation(device.duid);
|
|
62
|
-
platform.log.
|
|
60
|
+
platform.log.debug(`getRoomMapFromDevice - mapInfo: ${mapInfo ? debugStringify(mapInfo) : 'undefined'}`);
|
|
61
|
+
platform.log.debug(`getRoomMapFromDevice - rooms: ${debugStringify(rooms)}`);
|
|
63
62
|
if (mapInfo && mapInfo.allRooms && mapInfo.allRooms.length > 0) {
|
|
64
63
|
const roomDataMap = mapInfo.allRooms;
|
|
65
64
|
const roomMap = new RoomMap(roomDataMap, rooms, mapInfo.maps, enableMultipleMap);
|
|
66
|
-
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
67
|
-
platform.log.notice('-------------------------------------------2--------------------------------------------------------');
|
|
68
65
|
return roomMap;
|
|
69
66
|
}
|
|
70
67
|
const roomData = await platform.roborockService.getRoomMappings(device.duid);
|
|
@@ -72,8 +69,6 @@ export async function getRoomMapFromDevice(device, platform) {
|
|
|
72
69
|
platform.log.notice(`getRoomMapFromDevice - roomData: ${debugStringify(roomData ?? [])}`);
|
|
73
70
|
const roomDataMap = roomData.map((r) => ({ id: r[0], iot_name_id: String(r[1]), globalId: r[1], tag: r[2], mapId: 0, displayName: undefined }));
|
|
74
71
|
const roomMap = new RoomMap(roomDataMap ?? [], rooms, [], enableMultipleMap);
|
|
75
|
-
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
76
|
-
platform.log.notice('-------------------------------------------1--------------------------------------------------------');
|
|
77
72
|
return roomMap;
|
|
78
73
|
}
|
|
79
74
|
}
|
package/dist/model/RoomMap.js
CHANGED
|
@@ -4,12 +4,16 @@ export class RoomIndexMap {
|
|
|
4
4
|
constructor(roomMap) {
|
|
5
5
|
this.indexMap = roomMap;
|
|
6
6
|
this.roomMap = new Map();
|
|
7
|
-
for (const [areaId, { roomId }] of roomMap.entries()) {
|
|
8
|
-
this.roomMap.set(roomId
|
|
7
|
+
for (const [areaId, { roomId, mapId }] of roomMap.entries()) {
|
|
8
|
+
this.roomMap.set(`${roomId}:${mapId}`, areaId);
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
-
getAreaId(roomId) {
|
|
12
|
-
|
|
11
|
+
getAreaId(roomId, mapId) {
|
|
12
|
+
const areaId = this.roomMap.get(`${roomId}:${mapId}`);
|
|
13
|
+
if (areaId === undefined) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
return areaId;
|
|
13
17
|
}
|
|
14
18
|
getRoomId(areaId) {
|
|
15
19
|
return this.indexMap.get(areaId)?.roomId;
|
package/dist/platform.js
CHANGED
|
@@ -26,8 +26,8 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
26
26
|
rrHomeId;
|
|
27
27
|
constructor(matterbridge, log, config) {
|
|
28
28
|
super(matterbridge, log, config);
|
|
29
|
-
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.
|
|
30
|
-
throw new Error(`This plugin requires Matterbridge version >= "3.
|
|
29
|
+
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.2.0')) {
|
|
30
|
+
throw new Error(`This plugin requires Matterbridge version >= "3.2.0". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
|
|
31
31
|
}
|
|
32
32
|
this.log.info('Initializing platform:', this.config.name);
|
|
33
33
|
if (config.whiteList === undefined)
|
|
@@ -52,6 +52,7 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
52
52
|
}
|
|
53
53
|
const axiosInstance = axios.default ?? axios;
|
|
54
54
|
this.enableExperimentalFeature = this.config.enableExperimental;
|
|
55
|
+
this.enableExperimentalFeature.advancedFeature.enableMultipleMap = false;
|
|
55
56
|
if (this.enableExperimentalFeature?.enableExperimentalFeature && this.enableExperimentalFeature?.cleanModeSettings?.enableCleanModeMapping) {
|
|
56
57
|
this.cleanModeSettings = this.enableExperimentalFeature.cleanModeSettings;
|
|
57
58
|
this.log.notice(`Experimental Feature has been enable`);
|
|
@@ -171,7 +172,7 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
171
172
|
this.roborockService.setSupportedAreaIndexMap(vacuum.duid, roomIndexMap);
|
|
172
173
|
let routineAsRoom = [];
|
|
173
174
|
if (this.enableExperimentalFeature?.enableExperimentalFeature && this.enableExperimentalFeature.advancedFeature?.showRoutinesAsRoom) {
|
|
174
|
-
routineAsRoom = getSupportedScenes(vacuum.scenes, this.log);
|
|
175
|
+
routineAsRoom = getSupportedScenes(vacuum.scenes ?? [], this.log);
|
|
175
176
|
this.roborockService.setSupportedScenes(vacuum.duid, routineAsRoom);
|
|
176
177
|
}
|
|
177
178
|
const robot = new RoborockVacuumCleaner(username, vacuum, roomMap, routineAsRoom, this.enableExperimentalFeature, this.log);
|
package/dist/platformRunner.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { getRunningMode } from './initialData/getSupportedRunModes.js';
|
|
4
|
-
import { state_to_matter_operational_status, state_to_matter_state } from './share/function.js';
|
|
5
|
-
import { getBatteryState, getBatteryStatus, getOperationalErrorState, getSupportedAreas } from './initialData/index.js';
|
|
1
|
+
import { PowerSource, RvcOperationalState } from 'matterbridge/matter/clusters';
|
|
2
|
+
import { getBatteryStatus, getOperationalErrorState } from './initialData/index.js';
|
|
6
3
|
import { NotifyMessageTypes } from './notifyMessageTypes.js';
|
|
7
|
-
import { Protocol } from './roborockCommunication/broadcast/model/protocol.js';
|
|
8
|
-
import { hasDockingStationError, parseDockingStationStatus } from './model/DockingStationStatus.js';
|
|
9
|
-
import { AdditionalPropCode } from './roborockCommunication/index.js';
|
|
10
|
-
import { OperationStatusCode } from './roborockCommunication/Zenum/operationStatusCode.js';
|
|
11
|
-
import { getCurrentCleanModeFunc } from './share/runtimeHelper.js';
|
|
12
4
|
import { debugStringify } from 'matterbridge/logger';
|
|
5
|
+
import { handleLocalMessage } from './runtimes/handleLocalMessage.js';
|
|
6
|
+
import { handleCloudMessage } from './runtimes/handleCloudMessage.js';
|
|
7
|
+
import { updateFromHomeData } from './runtimes/handleHomeDataMessage.js';
|
|
13
8
|
export class PlatformRunner {
|
|
14
9
|
platform;
|
|
15
10
|
constructor(platform) {
|
|
@@ -17,7 +12,7 @@ export class PlatformRunner {
|
|
|
17
12
|
}
|
|
18
13
|
async updateRobot(messageSource, homeData) {
|
|
19
14
|
if (messageSource === NotifyMessageTypes.HomeData) {
|
|
20
|
-
|
|
15
|
+
updateFromHomeData(homeData, this.platform);
|
|
21
16
|
}
|
|
22
17
|
else {
|
|
23
18
|
await this.updateFromMQTTMessage(messageSource, homeData);
|
|
@@ -74,275 +69,22 @@ export class PlatformRunner {
|
|
|
74
69
|
case NotifyMessageTypes.LocalMessage: {
|
|
75
70
|
const data = messageData;
|
|
76
71
|
const robot = platform.robots.get(duid);
|
|
77
|
-
if (
|
|
78
|
-
|
|
72
|
+
if (robot && data) {
|
|
73
|
+
await handleLocalMessage(data, platform, duid);
|
|
79
74
|
return;
|
|
80
75
|
}
|
|
81
|
-
|
|
82
|
-
const state = state_to_matter_state(data.state);
|
|
83
|
-
if (state) {
|
|
84
|
-
robot.updateAttribute(RvcRunMode.Cluster.id, 'currentMode', getRunningMode(state), platform.log);
|
|
85
|
-
}
|
|
86
|
-
if (data.state === OperationStatusCode.Idle) {
|
|
87
|
-
const selectedAreas = platform.roborockService?.getSelectedAreas(duid) ?? [];
|
|
88
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'selectedAreas', selectedAreas, platform.log);
|
|
89
|
-
}
|
|
90
|
-
if (state === RvcRunMode.ModeTag.Cleaning && !data.cleaning_info) {
|
|
91
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', null, platform.log);
|
|
92
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'selectedAreas', [], platform.log);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
const currentMappedAreas = this.platform.roborockService?.getSupportedAreas(duid);
|
|
96
|
-
const roomIndexMap = this.platform.roborockService?.getSupportedAreasIndexMap(duid);
|
|
97
|
-
const roomMap = await getRoomMap(duid, this.platform);
|
|
98
|
-
const segment_id = data.cleaning_info?.segment_id ?? -1;
|
|
99
|
-
const target_segment_id = data.cleaning_info?.target_segment_id ?? -1;
|
|
100
|
-
let target_room_id = roomMap?.rooms.find((x) => x.id === segment_id || x.alternativeId === segment_id.toString())?.id ?? -1;
|
|
101
|
-
this.platform.log.debug(`Target segment id: ${segment_id}, targetRoom: ${target_room_id}`);
|
|
102
|
-
const isMappedArea = currentMappedAreas?.some((x) => x.areaId == segment_id);
|
|
103
|
-
if (segment_id !== -1 && isMappedArea) {
|
|
104
|
-
this.platform.log.debug(`RoomMap: ${roomMap ? debugStringify(roomMap) : 'undefined'}`);
|
|
105
|
-
this.platform.log.debug(`Part1: CurrentRoom: ${segment_id}, room name: ${roomMap?.rooms.find((x) => x.id === segment_id || x.alternativeId === segment_id.toString())?.displayName ?? 'unknown'}`);
|
|
106
|
-
const areaId = roomIndexMap?.getAreaId(segment_id) ?? segment_id;
|
|
107
|
-
this.platform.log.notice(`AreaId: ${areaId}, segment_id: ${segment_id}`);
|
|
108
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', areaId, platform.log);
|
|
109
|
-
}
|
|
110
|
-
if (segment_id == -1) {
|
|
111
|
-
const isTargetMappedArea = currentMappedAreas?.some((x) => x.areaId == target_segment_id);
|
|
112
|
-
target_room_id = roomMap?.rooms.find((x) => x.id == target_segment_id || x.alternativeId === target_segment_id.toString())?.id ?? -1;
|
|
113
|
-
this.platform.log.debug(`Target segment id: ${target_segment_id}, targetRoom: ${target_room_id}`);
|
|
114
|
-
if (target_segment_id !== -1 && isTargetMappedArea) {
|
|
115
|
-
this.platform.log.debug(`RoomMap: ${roomMap ? debugStringify(roomMap) : 'undefined'}`);
|
|
116
|
-
this.platform.log.debug(`Part2: TargetRoom: ${target_segment_id}, room name: ${roomMap?.rooms.find((x) => x.id === target_segment_id || x.alternativeId === segment_id.toString())?.displayName ?? 'unknown'}`);
|
|
117
|
-
const areaId = roomIndexMap?.getAreaId(target_segment_id) ?? target_room_id;
|
|
118
|
-
this.platform.log.notice(`AreaId: ${areaId}, target_segment_id: ${target_segment_id}`);
|
|
119
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', areaId, platform.log);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (target_segment_id == -1 && segment_id == -1) {
|
|
123
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', null, platform.log);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (data.battery) {
|
|
127
|
-
const batteryLevel = data.battery;
|
|
128
|
-
robot.updateAttribute(PowerSource.Cluster.id, 'batPercentRemaining', batteryLevel * 2, platform.log);
|
|
129
|
-
robot.updateAttribute(PowerSource.Cluster.id, 'batChargeState', getBatteryState(data.state, data.battery), platform.log);
|
|
130
|
-
robot.updateAttribute(PowerSource.Cluster.id, 'batChargeLevel', getBatteryStatus(batteryLevel), platform.log);
|
|
131
|
-
}
|
|
132
|
-
const currentCleanModeSetting = {
|
|
133
|
-
suctionPower: data.cleaning_info?.fan_power ?? data.fan_power,
|
|
134
|
-
waterFlow: data.cleaning_info?.water_box_status ?? data.water_box_mode,
|
|
135
|
-
distance_off: data.distance_off,
|
|
136
|
-
mopRoute: data.cleaning_info?.mop_mode ?? data.mop_mode,
|
|
137
|
-
segment_id: data.cleaning_info?.segment_id,
|
|
138
|
-
target_segment_id: data.cleaning_info?.target_segment_id,
|
|
139
|
-
};
|
|
140
|
-
this.platform.log.debug(`data: ${debugStringify(data)}`);
|
|
141
|
-
this.platform.log.notice(`currentCleanModeSetting: ${debugStringify(currentCleanModeSetting)}`);
|
|
142
|
-
if (currentCleanModeSetting.mopRoute && currentCleanModeSetting.suctionPower && currentCleanModeSetting.waterFlow) {
|
|
143
|
-
const currentCleanMode = getCurrentCleanModeFunc(deviceData.model, this.platform.enableExperimentalFeature?.advancedFeature?.forceRunAtDefault ?? false)(currentCleanModeSetting);
|
|
144
|
-
this.platform.log.debug(`Current clean mode: ${currentCleanMode}`);
|
|
145
|
-
if (currentCleanMode) {
|
|
146
|
-
robot.updateAttribute(RvcCleanMode.Cluster.id, 'currentMode', currentCleanMode, platform.log);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
this.processAdditionalProps(robot, data, duid);
|
|
150
|
-
}
|
|
76
|
+
platform.log.error(`Error2: Robot with DUID ${duid} not found`);
|
|
151
77
|
break;
|
|
152
78
|
}
|
|
153
79
|
case NotifyMessageTypes.CloudMessage: {
|
|
154
80
|
const data = messageData;
|
|
155
81
|
if (!data)
|
|
156
82
|
return;
|
|
157
|
-
|
|
83
|
+
await handleCloudMessage(data, platform, this, duid);
|
|
158
84
|
break;
|
|
159
85
|
}
|
|
160
86
|
default:
|
|
161
87
|
break;
|
|
162
88
|
}
|
|
163
89
|
}
|
|
164
|
-
handlerCloudMessage(data, duid) {
|
|
165
|
-
const platform = this.platform;
|
|
166
|
-
const messageTypes = Object.keys(data.dps).map(Number);
|
|
167
|
-
const self = this;
|
|
168
|
-
const robot = platform.robots.get(duid);
|
|
169
|
-
if (robot === undefined) {
|
|
170
|
-
platform.log.error(`Error3: Robot with DUID ${duid} not found`);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
messageTypes.forEach(async (messageType) => {
|
|
174
|
-
switch (messageType) {
|
|
175
|
-
case Protocol.status_update: {
|
|
176
|
-
const status = Number(data.dps[messageType]);
|
|
177
|
-
const matterState = state_to_matter_state(status);
|
|
178
|
-
if (matterState) {
|
|
179
|
-
robot.updateAttribute(RvcRunMode.Cluster.id, 'currentMode', getRunningMode(matterState), platform.log);
|
|
180
|
-
}
|
|
181
|
-
const operationalStateId = state_to_matter_operational_status(status);
|
|
182
|
-
if (operationalStateId) {
|
|
183
|
-
const dssHasError = hasDockingStationError(robot.dockStationStatus);
|
|
184
|
-
if (!(dssHasError && self.triggerDssError(robot))) {
|
|
185
|
-
robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
break;
|
|
189
|
-
}
|
|
190
|
-
case Protocol.rpc_response: {
|
|
191
|
-
const response = data.dps[messageType];
|
|
192
|
-
if (!isStatusUpdate(response.result)) {
|
|
193
|
-
platform.log.debug('Ignore message:', debugStringify(data));
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
let roboStatus;
|
|
197
|
-
if (Array.isArray(response.result) && response.result.length > 0) {
|
|
198
|
-
roboStatus = response.result[0];
|
|
199
|
-
}
|
|
200
|
-
if (roboStatus) {
|
|
201
|
-
const message = { ...roboStatus };
|
|
202
|
-
platform.log.debug('rpc_response:', debugStringify(message));
|
|
203
|
-
await self.updateFromMQTTMessage(NotifyMessageTypes.LocalMessage, message, duid, true);
|
|
204
|
-
}
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
case Protocol.suction_power:
|
|
208
|
-
case Protocol.water_box_mode: {
|
|
209
|
-
await platform.roborockService?.getCleanModeData(duid).then((cleanModeData) => {
|
|
210
|
-
if (cleanModeData) {
|
|
211
|
-
const currentCleanMode = getCurrentCleanModeFunc(robot.device.data.model, platform.enableExperimentalFeature?.advancedFeature?.forceRunAtDefault ?? false)({
|
|
212
|
-
suctionPower: cleanModeData.suctionPower,
|
|
213
|
-
waterFlow: cleanModeData.waterFlow,
|
|
214
|
-
distance_off: cleanModeData.distance_off,
|
|
215
|
-
mopRoute: cleanModeData.mopRoute,
|
|
216
|
-
});
|
|
217
|
-
platform.log.debug(`Clean mode data: ${debugStringify(cleanModeData)}`);
|
|
218
|
-
platform.log.debug(`Current clean mode: ${currentCleanMode}`);
|
|
219
|
-
if (currentCleanMode) {
|
|
220
|
-
robot.updateAttribute(RvcCleanMode.Cluster.id, 'currentMode', currentCleanMode, platform.log);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
case Protocol.additional_props: {
|
|
227
|
-
platform.log.notice(`Received additional properties for robot ${duid}: ${debugStringify(data)}`);
|
|
228
|
-
const propCode = data.dps[Protocol.additional_props];
|
|
229
|
-
platform.log.debug(`DPS for additional properties: ${propCode}, AdditionalPropCode: ${AdditionalPropCode[propCode]}`);
|
|
230
|
-
const enableMultipleMap = (platform.enableExperimentalFeature?.enableExperimentalFeature && platform.enableExperimentalFeature?.advancedFeature?.enableMultipleMap) ?? false;
|
|
231
|
-
if (propCode === AdditionalPropCode.map_change) {
|
|
232
|
-
platform.log.notice('------------------------ get roomData ----------------------------');
|
|
233
|
-
const roomMap = await getRoomMapFromDevice(robot.device, platform);
|
|
234
|
-
platform.log.notice('------------------------ Room map updated ------------------------');
|
|
235
|
-
const { supportedAreas, supportedMaps, roomIndexMap } = getSupportedAreas(robot.device.rooms, roomMap, enableMultipleMap, platform.log);
|
|
236
|
-
platform.log.notice(`Supported areas: ${debugStringify(supportedAreas)}`);
|
|
237
|
-
platform.log.notice('------------------------ Supported areas updated ------------------');
|
|
238
|
-
platform.roborockService?.setSupportedAreas(duid, supportedAreas);
|
|
239
|
-
platform.roborockService?.setSelectedAreas(duid, []);
|
|
240
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'supportedAreas', supportedAreas, platform.log);
|
|
241
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'selectedAreas', [], platform.log);
|
|
242
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', null, platform.log);
|
|
243
|
-
if (enableMultipleMap) {
|
|
244
|
-
platform.roborockService?.setSupportedAreaIndexMap(duid, roomIndexMap);
|
|
245
|
-
robot.updateAttribute(ServiceArea.Cluster.id, 'supportedMaps', supportedMaps, platform.log);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
case Protocol.back_type: {
|
|
251
|
-
break;
|
|
252
|
-
}
|
|
253
|
-
default: {
|
|
254
|
-
platform.log.notice(`Unknown message type ${messageType}, protocol: ${Protocol[messageType]}, message: ${debugStringify(data)}`);
|
|
255
|
-
break;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
async processAdditionalProps(robot, message, duid) {
|
|
261
|
-
const dssStatus = this.getDssStatus(message, duid);
|
|
262
|
-
if (dssStatus) {
|
|
263
|
-
this.triggerDssError(robot);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
getDssStatus(message, duid) {
|
|
267
|
-
const platform = this.platform;
|
|
268
|
-
const robot = platform.robots.get(duid);
|
|
269
|
-
if (robot === undefined) {
|
|
270
|
-
platform.log.error(`Error4: Robot with DUID ${duid} not found`);
|
|
271
|
-
return undefined;
|
|
272
|
-
}
|
|
273
|
-
if (platform.enableExperimentalFeature &&
|
|
274
|
-
platform.enableExperimentalFeature.enableExperimentalFeature &&
|
|
275
|
-
platform.enableExperimentalFeature.advancedFeature.includeDockStationStatus &&
|
|
276
|
-
message.dss !== undefined) {
|
|
277
|
-
const dss = parseDockingStationStatus(message.dss);
|
|
278
|
-
if (dss && robot) {
|
|
279
|
-
robot.dockStationStatus = dss;
|
|
280
|
-
}
|
|
281
|
-
if (dss && hasDockingStationError(dss)) {
|
|
282
|
-
return RvcOperationalState.OperationalState.Error;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return undefined;
|
|
286
|
-
}
|
|
287
|
-
updateFromHomeData(homeData) {
|
|
288
|
-
const platform = this.platform;
|
|
289
|
-
if (platform.robots.size === 0)
|
|
290
|
-
return;
|
|
291
|
-
const devices = homeData.devices.filter((d) => platform.robots.has(d.duid));
|
|
292
|
-
for (const device of devices) {
|
|
293
|
-
const robot = platform.robots.get(device.duid);
|
|
294
|
-
if (robot === undefined) {
|
|
295
|
-
platform.log.error(`Error5: Robot with DUID ${device.duid} not found`);
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
const deviceData = robot.device.data;
|
|
299
|
-
if (!device || deviceData === undefined) {
|
|
300
|
-
platform.log.error('Device not found in home data');
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
device.schema = homeData.products.find((prd) => prd.id === device.productId || prd.model === device.data.model)?.schema ?? [];
|
|
304
|
-
this.platform.log.debug('updateFromHomeData-homeData:', debugStringify(homeData));
|
|
305
|
-
this.platform.log.debug('updateFromHomeData-device:', debugStringify(device));
|
|
306
|
-
const batteryLevel = getVacuumProperty(device, 'battery');
|
|
307
|
-
this.platform.log.debug('updateFromHomeData-schema:' + debugStringify(device.schema));
|
|
308
|
-
this.platform.log.debug('updateFromHomeData-battery:' + debugStringify(device.deviceStatus));
|
|
309
|
-
if (batteryLevel) {
|
|
310
|
-
robot.updateAttribute(PowerSource.Cluster.id, 'batPercentRemaining', batteryLevel ? batteryLevel * 2 : 200, platform.log);
|
|
311
|
-
robot.updateAttribute(PowerSource.Cluster.id, 'batChargeLevel', getBatteryStatus(batteryLevel), platform.log);
|
|
312
|
-
}
|
|
313
|
-
const state = getVacuumProperty(device, 'state');
|
|
314
|
-
const matterState = state_to_matter_state(state);
|
|
315
|
-
if (!state || !matterState) {
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
this.platform.log.debug(`updateFromHomeData-RvcRunMode code: ${state} name: ${OperationStatusCode[state]}, matterState: ${RvcRunMode.ModeTag[matterState]}`);
|
|
319
|
-
if (matterState) {
|
|
320
|
-
robot.updateAttribute(RvcRunMode.Cluster.id, 'currentMode', getRunningMode(matterState), platform.log);
|
|
321
|
-
}
|
|
322
|
-
const operationalStateId = state_to_matter_operational_status(state);
|
|
323
|
-
if (operationalStateId) {
|
|
324
|
-
const dssHasError = hasDockingStationError(robot.dockStationStatus);
|
|
325
|
-
this.platform.log.debug(`dssHasError: ${dssHasError}, dockStationStatus: ${debugStringify(robot.dockStationStatus ?? {})}`);
|
|
326
|
-
if (!(dssHasError && this.triggerDssError(robot))) {
|
|
327
|
-
this.platform.log.debug(`updateFromHomeData-OperationalState: ${RvcOperationalState.OperationalState[operationalStateId]}`);
|
|
328
|
-
robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
if (batteryLevel) {
|
|
332
|
-
robot.updateAttribute(PowerSource.Cluster.id, 'batChargeState', getBatteryState(state, batteryLevel), platform.log);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
triggerDssError(robot) {
|
|
337
|
-
const platform = this.platform;
|
|
338
|
-
const currentOperationState = robot.getAttribute(RvcOperationalState.Cluster.id, 'operationalState');
|
|
339
|
-
if (currentOperationState === RvcOperationalState.OperationalState.Error) {
|
|
340
|
-
return true;
|
|
341
|
-
}
|
|
342
|
-
if (currentOperationState === RvcOperationalState.OperationalState.Docked) {
|
|
343
|
-
robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', RvcOperationalState.OperationalState.Error, platform.log);
|
|
344
|
-
return true;
|
|
345
|
-
}
|
|
346
|
-
return false;
|
|
347
|
-
}
|
|
348
90
|
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { getRunningMode } from '../initialData/getSupportedRunModes.js';
|
|
2
|
+
import { hasDockingStationError } from '../model/DockingStationStatus.js';
|
|
3
|
+
import { AdditionalPropCode, Protocol } from '../roborockCommunication/index.js';
|
|
4
|
+
import { state_to_matter_operational_status, state_to_matter_state } from '../share/function.js';
|
|
5
|
+
import { RvcCleanMode, RvcOperationalState, RvcRunMode, ServiceArea } from 'matterbridge/matter/clusters';
|
|
6
|
+
import { triggerDssError } from './handleLocalMessage.js';
|
|
7
|
+
import { getRoomMapFromDevice, isStatusUpdate } from '../helper.js';
|
|
8
|
+
import { debugStringify } from 'matterbridge/logger';
|
|
9
|
+
import { NotifyMessageTypes } from '../notifyMessageTypes.js';
|
|
10
|
+
import { getCurrentCleanModeFunc } from '../share/runtimeHelper.js';
|
|
11
|
+
import { getSupportedAreas } from '../initialData/getSupportedAreas.js';
|
|
12
|
+
export async function handleCloudMessage(data, platform, runner, duid) {
|
|
13
|
+
const messageTypes = Object.keys(data.dps).map(Number);
|
|
14
|
+
const robot = platform.robots.get(duid);
|
|
15
|
+
if (robot === undefined) {
|
|
16
|
+
platform.log.error(`Error3: Robot with DUID ${duid} not found`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
messageTypes.forEach(async (messageType) => {
|
|
20
|
+
switch (messageType) {
|
|
21
|
+
case Protocol.status_update: {
|
|
22
|
+
const status = Number(data.dps[messageType]);
|
|
23
|
+
const matterState = state_to_matter_state(status);
|
|
24
|
+
if (matterState) {
|
|
25
|
+
robot.updateAttribute(RvcRunMode.Cluster.id, 'currentMode', getRunningMode(matterState), platform.log);
|
|
26
|
+
}
|
|
27
|
+
const operationalStateId = state_to_matter_operational_status(status);
|
|
28
|
+
if (operationalStateId) {
|
|
29
|
+
const dssHasError = hasDockingStationError(robot.dockStationStatus);
|
|
30
|
+
if (!(dssHasError && triggerDssError(robot, platform))) {
|
|
31
|
+
robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
case Protocol.rpc_response: {
|
|
37
|
+
const response = data.dps[messageType];
|
|
38
|
+
if (!isStatusUpdate(response.result)) {
|
|
39
|
+
platform.log.debug('Ignore message:', debugStringify(data));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
let roboStatus;
|
|
43
|
+
if (Array.isArray(response.result) && response.result.length > 0) {
|
|
44
|
+
roboStatus = response.result[0];
|
|
45
|
+
}
|
|
46
|
+
if (roboStatus) {
|
|
47
|
+
const message = { ...roboStatus };
|
|
48
|
+
platform.log.debug('rpc_response:', debugStringify(message));
|
|
49
|
+
await runner.updateFromMQTTMessage(NotifyMessageTypes.LocalMessage, message, duid, true);
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case Protocol.suction_power:
|
|
54
|
+
case Protocol.water_box_mode: {
|
|
55
|
+
await platform.roborockService?.getCleanModeData(duid).then((cleanModeData) => {
|
|
56
|
+
if (cleanModeData) {
|
|
57
|
+
const currentCleanMode = getCurrentCleanModeFunc(robot.device.data.model, platform.enableExperimentalFeature?.advancedFeature?.forceRunAtDefault ?? false)({
|
|
58
|
+
suctionPower: cleanModeData.suctionPower,
|
|
59
|
+
waterFlow: cleanModeData.waterFlow,
|
|
60
|
+
distance_off: cleanModeData.distance_off,
|
|
61
|
+
mopRoute: cleanModeData.mopRoute,
|
|
62
|
+
});
|
|
63
|
+
platform.log.debug(`Clean mode data: ${debugStringify(cleanModeData)}`);
|
|
64
|
+
platform.log.debug(`Current clean mode: ${currentCleanMode}`);
|
|
65
|
+
if (currentCleanMode) {
|
|
66
|
+
robot.updateAttribute(RvcCleanMode.Cluster.id, 'currentMode', currentCleanMode, platform.log);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case Protocol.additional_props: {
|
|
73
|
+
platform.log.notice(`Received additional properties for robot ${duid}: ${debugStringify(data)}`);
|
|
74
|
+
const propCode = data.dps[Protocol.additional_props];
|
|
75
|
+
platform.log.debug(`DPS for additional properties: ${propCode}, AdditionalPropCode: ${AdditionalPropCode[propCode]}`);
|
|
76
|
+
if (propCode === AdditionalPropCode.map_change) {
|
|
77
|
+
await handleMapChange(robot, platform, duid);
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case Protocol.back_type: {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
default: {
|
|
85
|
+
platform.log.notice(`Unknown message type ${messageType}, protocol: ${Protocol[messageType]}, message: ${debugStringify(data)}`);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
export async function handleMapChange(robot, platform, duid) {
|
|
92
|
+
const enableMultipleMap = (platform.enableExperimentalFeature?.enableExperimentalFeature && platform.enableExperimentalFeature?.advancedFeature?.enableMultipleMap) ?? false;
|
|
93
|
+
if (!enableMultipleMap)
|
|
94
|
+
return;
|
|
95
|
+
await getRoomMapFromDevice(robot.device, platform).then((roomMap) => {
|
|
96
|
+
const { supportedAreas, supportedMaps, roomIndexMap } = getSupportedAreas(robot.device.rooms, roomMap, enableMultipleMap, platform.log);
|
|
97
|
+
platform.log.debug(`handleMapChange - supportedAreas: ${debugStringify(supportedAreas)}`);
|
|
98
|
+
platform.log.debug(`handleMapChange - supportedMaps: ${debugStringify(supportedMaps)}`);
|
|
99
|
+
platform.log.debug(`handleMapChange - roomIndexMap: `, roomIndexMap);
|
|
100
|
+
platform.roborockService?.setSupportedAreas(duid, supportedAreas);
|
|
101
|
+
platform.roborockService?.setSelectedAreas(duid, []);
|
|
102
|
+
robot.updateAttribute(ServiceArea.Cluster.id, 'supportedAreas', supportedAreas, platform.log);
|
|
103
|
+
robot.updateAttribute(ServiceArea.Cluster.id, 'selectedAreas', [], platform.log);
|
|
104
|
+
robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', null, platform.log);
|
|
105
|
+
if (enableMultipleMap) {
|
|
106
|
+
platform.roborockService?.setSupportedAreaIndexMap(duid, roomIndexMap);
|
|
107
|
+
robot.updateAttribute(ServiceArea.Cluster.id, 'supportedMaps', supportedMaps, platform.log);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PowerSource, RvcOperationalState, RvcRunMode } from 'matterbridge/matter/clusters';
|
|
2
|
+
import { getVacuumProperty } from '../helper.js';
|
|
3
|
+
import { debugStringify } from 'matterbridge/logger';
|
|
4
|
+
import { getBatteryState, getBatteryStatus } from '../initialData/index.js';
|
|
5
|
+
import { state_to_matter_operational_status, state_to_matter_state } from '../share/function.js';
|
|
6
|
+
import { OperationStatusCode } from '../roborockCommunication/Zenum/operationStatusCode.js';
|
|
7
|
+
import { getRunningMode } from '../initialData/getSupportedRunModes.js';
|
|
8
|
+
import { hasDockingStationError } from '../model/DockingStationStatus.js';
|
|
9
|
+
import { triggerDssError } from './handleLocalMessage.js';
|
|
10
|
+
export async function updateFromHomeData(homeData, platform) {
|
|
11
|
+
if (platform.robots.size === 0)
|
|
12
|
+
return;
|
|
13
|
+
const devices = homeData.devices.filter((d) => platform.robots.has(d.duid));
|
|
14
|
+
for (const device of devices) {
|
|
15
|
+
const robot = platform.robots.get(device.duid);
|
|
16
|
+
if (robot === undefined) {
|
|
17
|
+
platform.log.error(`Error5: Robot with DUID ${device.duid} not found`);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const deviceData = robot.device.data;
|
|
21
|
+
if (!device || deviceData === undefined) {
|
|
22
|
+
platform.log.error('Device not found in home data');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
device.schema = homeData.products.find((prd) => prd.id === device.productId || prd.model === device.data.model)?.schema ?? [];
|
|
26
|
+
platform.log.debug('updateFromHomeData-homeData:', debugStringify(homeData));
|
|
27
|
+
platform.log.debug('updateFromHomeData-device:', debugStringify(device));
|
|
28
|
+
platform.log.debug('updateFromHomeData-schema:' + debugStringify(device.schema));
|
|
29
|
+
platform.log.debug('updateFromHomeData-battery:' + debugStringify(device.deviceStatus));
|
|
30
|
+
const batteryLevel = getVacuumProperty(device, 'battery');
|
|
31
|
+
if (batteryLevel) {
|
|
32
|
+
robot.updateAttribute(PowerSource.Cluster.id, 'batPercentRemaining', batteryLevel ? batteryLevel * 2 : 200, platform.log);
|
|
33
|
+
robot.updateAttribute(PowerSource.Cluster.id, 'batChargeLevel', getBatteryStatus(batteryLevel), platform.log);
|
|
34
|
+
}
|
|
35
|
+
const state = getVacuumProperty(device, 'state');
|
|
36
|
+
const matterState = state_to_matter_state(state);
|
|
37
|
+
if (!state || !matterState) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
platform.log.debug(`updateFromHomeData-RvcRunMode code: ${state} name: ${OperationStatusCode[state]}, matterState: ${RvcRunMode.ModeTag[matterState]}`);
|
|
41
|
+
if (matterState) {
|
|
42
|
+
robot.updateAttribute(RvcRunMode.Cluster.id, 'currentMode', getRunningMode(matterState), platform.log);
|
|
43
|
+
}
|
|
44
|
+
if (batteryLevel) {
|
|
45
|
+
robot.updateAttribute(PowerSource.Cluster.id, 'batChargeState', getBatteryState(state, batteryLevel), platform.log);
|
|
46
|
+
}
|
|
47
|
+
const operationalStateId = state_to_matter_operational_status(state);
|
|
48
|
+
if (operationalStateId) {
|
|
49
|
+
const dssHasError = hasDockingStationError(robot.dockStationStatus);
|
|
50
|
+
platform.log.debug(`dssHasError: ${dssHasError}, dockStationStatus: ${debugStringify(robot.dockStationStatus ?? {})}`);
|
|
51
|
+
if (!(dssHasError && triggerDssError(robot, platform))) {
|
|
52
|
+
platform.log.debug(`updateFromHomeData-OperationalState: ${RvcOperationalState.OperationalState[operationalStateId]}`);
|
|
53
|
+
robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', operationalStateId, platform.log);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|