matterbridge-roborock-vacuum-plugin 1.1.0-rc14 → 1.1.0-rc15
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 +62 -0
- package/dist/model/RoomMap.js +1 -1
- package/dist/platform.js +2 -2
- package/dist/platformRunner.js +3 -66
- package/dist/roborockCommunication/broadcast/client/LocalNetworkClient.js +2 -2
- package/dist/roborockCommunication/broadcast/listener/implementation/syncMessageListener.js +0 -4
- package/dist/roborockCommunication/broadcast/messageProcessor.js +1 -1
- package/matterbridge-roborock-vacuum-plugin.config.json +1 -1
- package/matterbridge-roborock-vacuum-plugin.schema.json +1 -1
- package/package.json +1 -1
- package/src/helper.ts +83 -0
- package/src/initialData/getSupportedAreas.ts +1 -1
- package/src/model/RoomMap.ts +1 -1
- package/src/platform.ts +2 -2
- package/src/platformRunner.ts +3 -86
- package/src/roborockCommunication/broadcast/client/LocalNetworkClient.ts +2 -3
- package/src/roborockCommunication/broadcast/listener/implementation/syncMessageListener.ts +4 -4
- package/src/roborockCommunication/broadcast/messageProcessor.ts +2 -2
- package/src/rvc.ts +1 -1
- package/src/tests/platformRunner2.test.ts +4 -7
- package/src/tests/roborockCommunication/broadcast/listener/implementation/syncMessageListener.test.ts +3 -3
- package/src/tests/roborockCommunication/broadcast/messageProcessor.test.ts +1 -1
package/dist/helper.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { debugStringify } from 'matterbridge/logger';
|
|
2
|
+
import { RoomMap } from './model/RoomMap.js';
|
|
1
3
|
export function getVacuumProperty(device, property) {
|
|
2
4
|
if (device) {
|
|
3
5
|
const schemas = device.schema;
|
|
@@ -14,3 +16,63 @@ export function getVacuumProperty(device, property) {
|
|
|
14
16
|
export function isSupportedDevice(model) {
|
|
15
17
|
return model.startsWith('roborock.vacuum.');
|
|
16
18
|
}
|
|
19
|
+
export function isStatusUpdate(result) {
|
|
20
|
+
return (Array.isArray(result) &&
|
|
21
|
+
result.length > 0 &&
|
|
22
|
+
typeof result[0] === 'object' &&
|
|
23
|
+
result[0] !== null &&
|
|
24
|
+
'msg_ver' in result[0] &&
|
|
25
|
+
result[0].msg_ver !== undefined &&
|
|
26
|
+
result[0].msg_ver !== null);
|
|
27
|
+
}
|
|
28
|
+
export async function getRoomMap(duid, platform) {
|
|
29
|
+
const robot = platform.robots.get(duid);
|
|
30
|
+
if (robot === undefined) {
|
|
31
|
+
platform.log.error(`Error6: Robot with DUID ${duid} not found`);
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
if (platform.roborockService === undefined)
|
|
35
|
+
return undefined;
|
|
36
|
+
const rooms = robot.device.rooms ?? [];
|
|
37
|
+
if (robot.roomInfo === undefined) {
|
|
38
|
+
const roomData = await platform.roborockService.getRoomMappings(robot.device.duid);
|
|
39
|
+
if (roomData !== undefined && roomData.length > 0) {
|
|
40
|
+
robot.roomInfo = new RoomMap(roomData ?? [], rooms);
|
|
41
|
+
return robot.roomInfo;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (robot.roomInfo === undefined) {
|
|
45
|
+
const mapInfo = await platform.roborockService.getMapInformation(robot.device.duid);
|
|
46
|
+
if (mapInfo && mapInfo.maps && mapInfo.maps.length > 0) {
|
|
47
|
+
platform.log.error(`getRoomMap - mapInfo: ${debugStringify(mapInfo.maps)}`);
|
|
48
|
+
const roomDataMap = mapInfo.maps[0].rooms.map((r) => [r.id, parseInt(r.iot_name_id), r.tag]);
|
|
49
|
+
robot.roomInfo = new RoomMap(roomDataMap, rooms);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return robot.roomInfo;
|
|
53
|
+
}
|
|
54
|
+
export async function getRoomMapFromDevice(device, platform) {
|
|
55
|
+
const rooms = device?.rooms ?? [];
|
|
56
|
+
platform.log.notice('-------------------------------------------0--------------------------------------------------------');
|
|
57
|
+
platform.log.notice(`getRoomMapFromDevice: ${debugStringify(rooms)}`);
|
|
58
|
+
if (device && platform.roborockService) {
|
|
59
|
+
const roomData = await platform.roborockService.getRoomMappings(device.duid);
|
|
60
|
+
if (roomData !== undefined && roomData.length > 0) {
|
|
61
|
+
platform.log.notice(`getRoomMapFromDevice - roomData: ${debugStringify(roomData ?? [])}`);
|
|
62
|
+
const roomMap = new RoomMap(roomData ?? [], rooms);
|
|
63
|
+
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
64
|
+
platform.log.notice('-------------------------------------------1--------------------------------------------------------');
|
|
65
|
+
return roomMap;
|
|
66
|
+
}
|
|
67
|
+
const mapInfo = await platform.roborockService.getMapInformation(device.duid);
|
|
68
|
+
platform.log.notice(`getRoomMapFromDevice - mapInfo: ${mapInfo ? debugStringify(mapInfo) : 'undefined'}`);
|
|
69
|
+
if (mapInfo && mapInfo.maps && mapInfo.maps.length > 0) {
|
|
70
|
+
const roomDataMap = mapInfo.maps[0].rooms.map((r) => [r.id, parseInt(r.iot_name_id), r.tag]);
|
|
71
|
+
const roomMap = new RoomMap(roomDataMap, rooms);
|
|
72
|
+
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
73
|
+
platform.log.notice('-------------------------------------------2--------------------------------------------------------');
|
|
74
|
+
return roomMap;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return new RoomMap([], rooms);
|
|
78
|
+
}
|
package/dist/model/RoomMap.js
CHANGED
package/dist/platform.js
CHANGED
|
@@ -4,7 +4,7 @@ import { debugStringify } from 'matterbridge/logger';
|
|
|
4
4
|
import RoborockService from './roborockService.js';
|
|
5
5
|
import { PLUGIN_NAME } from './settings.js';
|
|
6
6
|
import ClientManager from './clientManager.js';
|
|
7
|
-
import { isSupportedDevice } from './helper.js';
|
|
7
|
+
import { getRoomMapFromDevice, isSupportedDevice } from './helper.js';
|
|
8
8
|
import { PlatformRunner } from './platformRunner.js';
|
|
9
9
|
import { RoborockVacuumCleaner } from './rvc.js';
|
|
10
10
|
import { configurateBehavior } from './behaviorFactory.js';
|
|
@@ -162,7 +162,7 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
162
162
|
const rooms = map_info?.maps?.[0]?.rooms ?? [];
|
|
163
163
|
vacuum.rooms = rooms.map((room) => ({ id: room.id, name: room.displayName }));
|
|
164
164
|
}
|
|
165
|
-
const roomMap = await
|
|
165
|
+
const roomMap = await getRoomMapFromDevice(vacuum, this);
|
|
166
166
|
this.log.debug('Initializing - roomMap: ', debugStringify(roomMap));
|
|
167
167
|
const behaviorHandler = configurateBehavior(vacuum.data.model, vacuum.duid, this.roborockService, this.cleanModeSettings, this.enableExperimentalFeature?.advancedFeature?.forceRunAtDefault ?? false, this.log);
|
|
168
168
|
const supportedAreas = getSupportedAreas(vacuum.rooms, roomMap, this.log);
|
package/dist/platformRunner.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { RvcRunMode, PowerSource, ServiceArea, RvcOperationalState, RvcCleanMode } from 'matterbridge/matter/clusters';
|
|
2
|
-
import { getVacuumProperty } from './helper.js';
|
|
2
|
+
import { getRoomMap, getVacuumProperty, isStatusUpdate } from './helper.js';
|
|
3
3
|
import { getRunningMode } from './initialData/getSupportedRunModes.js';
|
|
4
4
|
import { state_to_matter_operational_status, state_to_matter_state } from './share/function.js';
|
|
5
|
-
import RoomMap from './model/RoomMap.js';
|
|
6
5
|
import { getBatteryState, getBatteryStatus, getOperationalErrorState } from './initialData/index.js';
|
|
7
6
|
import { NotifyMessageTypes } from './notifyMessageTypes.js';
|
|
8
7
|
import { Protocol } from './roborockCommunication/broadcast/model/protocol.js';
|
|
@@ -32,59 +31,6 @@ export class PlatformRunner {
|
|
|
32
31
|
const homeData = await platform.roborockService.getHomeDataForUpdating(platform.rrHomeId);
|
|
33
32
|
await this.updateRobot(NotifyMessageTypes.HomeData, homeData);
|
|
34
33
|
}
|
|
35
|
-
async getRoomMapFromDevice(device) {
|
|
36
|
-
const platform = this.platform;
|
|
37
|
-
const rooms = device?.rooms ?? [];
|
|
38
|
-
platform.log.notice('-------------------------------------------0--------------------------------------------------------');
|
|
39
|
-
platform.log.notice(`getRoomMapFromDevice: ${debugStringify(rooms)}`);
|
|
40
|
-
if (device && platform.roborockService) {
|
|
41
|
-
const roomData = await platform.roborockService.getRoomMappings(device.duid);
|
|
42
|
-
if (roomData !== undefined && roomData.length > 0) {
|
|
43
|
-
platform.log.notice(`getRoomMapFromDevice - roomData: ${debugStringify(roomData ?? [])}`);
|
|
44
|
-
const roomMap = new RoomMap(roomData ?? [], rooms);
|
|
45
|
-
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
46
|
-
platform.log.notice('-------------------------------------------1--------------------------------------------------------');
|
|
47
|
-
return roomMap;
|
|
48
|
-
}
|
|
49
|
-
const mapInfo = await platform.roborockService.getMapInformation(device.duid);
|
|
50
|
-
platform.log.notice(`getRoomMapFromDevice - mapInfo: ${mapInfo ? debugStringify(mapInfo) : 'undefined'}`);
|
|
51
|
-
if (mapInfo && mapInfo.maps && mapInfo.maps.length > 0) {
|
|
52
|
-
const roomDataMap = mapInfo.maps[0].rooms.map((r) => [r.id, parseInt(r.iot_name_id), r.tag]);
|
|
53
|
-
const roomMap = new RoomMap(roomDataMap, rooms);
|
|
54
|
-
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
55
|
-
platform.log.notice('-------------------------------------------2--------------------------------------------------------');
|
|
56
|
-
return roomMap;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return new RoomMap([], rooms);
|
|
60
|
-
}
|
|
61
|
-
async getRoomMap(duid) {
|
|
62
|
-
const platform = this.platform;
|
|
63
|
-
const robot = platform.robots.get(duid);
|
|
64
|
-
if (robot === undefined) {
|
|
65
|
-
platform.log.error(`Error6: Robot with DUID ${duid} not found`);
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
if (platform.roborockService === undefined)
|
|
69
|
-
return undefined;
|
|
70
|
-
const rooms = robot.device.rooms ?? [];
|
|
71
|
-
if (robot.roomInfo === undefined) {
|
|
72
|
-
const roomData = await platform.roborockService.getRoomMappings(robot.device.duid);
|
|
73
|
-
if (roomData !== undefined && roomData.length > 0) {
|
|
74
|
-
robot.roomInfo = new RoomMap(roomData ?? [], rooms);
|
|
75
|
-
return robot.roomInfo;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
if (robot.roomInfo === undefined) {
|
|
79
|
-
const mapInfo = await platform.roborockService.getMapInformation(robot.device.duid);
|
|
80
|
-
if (mapInfo && mapInfo.maps && mapInfo.maps.length > 0) {
|
|
81
|
-
platform.log.error(`getRoomMap - mapInfo: ${debugStringify(mapInfo.maps)}`);
|
|
82
|
-
const roomDataMap = mapInfo.maps[0].rooms.map((r) => [r.id, parseInt(r.iot_name_id), r.tag]);
|
|
83
|
-
robot.roomInfo = new RoomMap(roomDataMap, rooms);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return robot.roomInfo;
|
|
87
|
-
}
|
|
88
34
|
async updateFromMQTTMessage(messageSource, messageData, duid = '', tracked = false) {
|
|
89
35
|
const platform = this.platform;
|
|
90
36
|
duid = duid || messageData?.duid || '';
|
|
@@ -146,7 +92,7 @@ export class PlatformRunner {
|
|
|
146
92
|
}
|
|
147
93
|
else {
|
|
148
94
|
const currentMappedAreas = this.platform.roborockService?.getSupportedAreas(duid);
|
|
149
|
-
const roomMap = await
|
|
95
|
+
const roomMap = await getRoomMap(duid, this.platform);
|
|
150
96
|
const segment_id = data.cleaning_info?.segment_id ?? -1;
|
|
151
97
|
const target_segment_id = data.cleaning_info?.target_segment_id ?? -1;
|
|
152
98
|
let target_room_id = roomMap?.rooms.find((x) => x.id === segment_id || x.alternativeId === segment_id.toString())?.id ?? -1;
|
|
@@ -237,7 +183,7 @@ export class PlatformRunner {
|
|
|
237
183
|
}
|
|
238
184
|
case Protocol.rpc_response: {
|
|
239
185
|
const response = data.dps[messageType];
|
|
240
|
-
if (!
|
|
186
|
+
if (!isStatusUpdate(response.result)) {
|
|
241
187
|
platform.log.debug('Ignore message:', debugStringify(data));
|
|
242
188
|
return;
|
|
243
189
|
}
|
|
@@ -309,15 +255,6 @@ export class PlatformRunner {
|
|
|
309
255
|
}
|
|
310
256
|
return undefined;
|
|
311
257
|
}
|
|
312
|
-
isStatusUpdate(result) {
|
|
313
|
-
return (Array.isArray(result) &&
|
|
314
|
-
result.length > 0 &&
|
|
315
|
-
typeof result[0] === 'object' &&
|
|
316
|
-
result[0] !== null &&
|
|
317
|
-
'msg_ver' in result[0] &&
|
|
318
|
-
result[0].msg_ver !== undefined &&
|
|
319
|
-
result[0].msg_ver !== null);
|
|
320
|
-
}
|
|
321
258
|
updateFromHomeData(homeData) {
|
|
322
259
|
const platform = this.platform;
|
|
323
260
|
if (platform.robots.size === 0)
|
|
@@ -61,10 +61,10 @@ export class LocalNetworkClient extends AbstractClient {
|
|
|
61
61
|
async onConnect() {
|
|
62
62
|
this.logger.debug(` [LocalNetworkClient]: ${this.duid} connected to ${this.ip}`);
|
|
63
63
|
this.logger.debug(` [LocalNetworkClient]: ${this.duid} socket writable: ${this.socket?.writable}, readable: ${this.socket?.readable}`);
|
|
64
|
-
await this.sendHelloMessage();
|
|
65
|
-
this.pingInterval = setInterval(this.sendPingRequest.bind(this), 5000);
|
|
66
64
|
this.connected = true;
|
|
67
65
|
this.retryCount = 0;
|
|
66
|
+
await this.sendHelloMessage();
|
|
67
|
+
this.pingInterval = setInterval(this.sendPingRequest.bind(this), 5000);
|
|
68
68
|
await this.connectionListeners.onConnected(this.duid);
|
|
69
69
|
}
|
|
70
70
|
async onDisconnect(hadError) {
|
|
@@ -18,10 +18,6 @@ export class SyncMessageListener {
|
|
|
18
18
|
const dps = message.get(Protocol.rpc_response);
|
|
19
19
|
const messageId = dps.id;
|
|
20
20
|
const responseHandler = this.pending.get(messageId);
|
|
21
|
-
const result = dps.result;
|
|
22
|
-
if (result && result.length == 1 && result[0] == 'ok') {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
21
|
if (responseHandler) {
|
|
26
22
|
responseHandler(dps.result);
|
|
27
23
|
}
|
|
@@ -80,7 +80,7 @@ export class MessageProcessor {
|
|
|
80
80
|
}
|
|
81
81
|
async findMyRobot(duid) {
|
|
82
82
|
const request = new RequestMessage({ method: 'find_me' });
|
|
83
|
-
return this.client.
|
|
83
|
+
return this.client.get(duid, request);
|
|
84
84
|
}
|
|
85
85
|
async getCleanModeData(duid) {
|
|
86
86
|
const currentMopMode = await this.getCustomMessage(duid, new RequestMessage({ method: 'get_mop_mode' }));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "Matterbridge Roborock Vacuum Plugin",
|
|
3
|
-
"description": "matterbridge-roborock-vacuum-plugin v. 1.1.0-
|
|
3
|
+
"description": "matterbridge-roborock-vacuum-plugin v. 1.1.0-rc15 by https://github.com/RinDevJunior",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"required": ["username", "password"],
|
|
6
6
|
"properties": {
|
package/package.json
CHANGED
package/src/helper.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { debugStringify } from 'matterbridge/logger';
|
|
2
|
+
import { RoomMap } from './model/RoomMap.js';
|
|
3
|
+
import { RoborockMatterbridgePlatform } from './platform.js';
|
|
1
4
|
import { Device } from './roborockCommunication/index.js';
|
|
5
|
+
import { CloudMessageResult } from './roborockCommunication/Zmodel/messageResult.js';
|
|
2
6
|
|
|
3
7
|
export function getVacuumProperty(device: Device, property: string): number | undefined {
|
|
4
8
|
if (device) {
|
|
@@ -20,3 +24,82 @@ export function getVacuumProperty(device: Device, property: string): number | un
|
|
|
20
24
|
export function isSupportedDevice(model: string): boolean {
|
|
21
25
|
return model.startsWith('roborock.vacuum.');
|
|
22
26
|
}
|
|
27
|
+
|
|
28
|
+
export function isStatusUpdate(result: unknown): boolean {
|
|
29
|
+
return (
|
|
30
|
+
Array.isArray(result) &&
|
|
31
|
+
result.length > 0 &&
|
|
32
|
+
typeof result[0] === 'object' &&
|
|
33
|
+
result[0] !== null &&
|
|
34
|
+
'msg_ver' in result[0] &&
|
|
35
|
+
(result[0] as CloudMessageResult).msg_ver !== undefined &&
|
|
36
|
+
(result[0] as CloudMessageResult).msg_ver !== null
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function getRoomMap(duid: string, platform: RoborockMatterbridgePlatform): Promise<RoomMap | undefined> {
|
|
41
|
+
const robot = platform.robots.get(duid);
|
|
42
|
+
if (robot === undefined) {
|
|
43
|
+
platform.log.error(`Error6: Robot with DUID ${duid} not found`);
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (platform.roborockService === undefined) return undefined;
|
|
48
|
+
|
|
49
|
+
const rooms = robot.device.rooms ?? [];
|
|
50
|
+
// if (platform.robot?.device === undefined || platform.roborockService === undefined) return undefined;
|
|
51
|
+
if (robot.roomInfo === undefined) {
|
|
52
|
+
const roomData = await platform.roborockService.getRoomMappings(robot.device.duid);
|
|
53
|
+
if (roomData !== undefined && roomData.length > 0) {
|
|
54
|
+
robot.roomInfo = new RoomMap(roomData ?? [], rooms);
|
|
55
|
+
return robot.roomInfo;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (robot.roomInfo === undefined) {
|
|
60
|
+
const mapInfo = await platform.roborockService.getMapInformation(robot.device.duid);
|
|
61
|
+
if (mapInfo && mapInfo.maps && mapInfo.maps.length > 0) {
|
|
62
|
+
platform.log.error(`getRoomMap - mapInfo: ${debugStringify(mapInfo.maps)}`);
|
|
63
|
+
|
|
64
|
+
const roomDataMap = mapInfo.maps[0].rooms.map((r) => [r.id, parseInt(r.iot_name_id), r.tag] as [number, number, number]);
|
|
65
|
+
robot.roomInfo = new RoomMap(roomDataMap, rooms);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return robot.roomInfo;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function getRoomMapFromDevice(device: Device, platform: RoborockMatterbridgePlatform): Promise<RoomMap> {
|
|
73
|
+
const rooms = device?.rooms ?? [];
|
|
74
|
+
|
|
75
|
+
platform.log.notice('-------------------------------------------0--------------------------------------------------------');
|
|
76
|
+
platform.log.notice(`getRoomMapFromDevice: ${debugStringify(rooms)}`);
|
|
77
|
+
|
|
78
|
+
if (device && platform.roborockService) {
|
|
79
|
+
const roomData = await platform.roborockService.getRoomMappings(device.duid);
|
|
80
|
+
if (roomData !== undefined && roomData.length > 0) {
|
|
81
|
+
platform.log.notice(`getRoomMapFromDevice - roomData: ${debugStringify(roomData ?? [])}`);
|
|
82
|
+
|
|
83
|
+
const roomMap = new RoomMap(roomData ?? [], rooms);
|
|
84
|
+
|
|
85
|
+
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
86
|
+
platform.log.notice('-------------------------------------------1--------------------------------------------------------');
|
|
87
|
+
return roomMap;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const mapInfo = await platform.roborockService.getMapInformation(device.duid);
|
|
91
|
+
platform.log.notice(`getRoomMapFromDevice - mapInfo: ${mapInfo ? debugStringify(mapInfo) : 'undefined'}`);
|
|
92
|
+
|
|
93
|
+
if (mapInfo && mapInfo.maps && mapInfo.maps.length > 0) {
|
|
94
|
+
const roomDataMap = mapInfo.maps[0].rooms.map((r) => [r.id, parseInt(r.iot_name_id), r.tag] as [number, number, number]);
|
|
95
|
+
|
|
96
|
+
const roomMap = new RoomMap(roomDataMap, rooms);
|
|
97
|
+
|
|
98
|
+
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
99
|
+
platform.log.notice('-------------------------------------------2--------------------------------------------------------');
|
|
100
|
+
return roomMap;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return new RoomMap([], rooms);
|
|
105
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnsiLogger, debugStringify } from 'matterbridge/logger';
|
|
2
2
|
import { ServiceArea } from 'matterbridge/matter/clusters';
|
|
3
|
-
import RoomMap from '../model/RoomMap.js';
|
|
3
|
+
import { RoomMap } from '../model/RoomMap.js';
|
|
4
4
|
import { Room } from '../roborockCommunication/Zmodel/room.js';
|
|
5
5
|
import { randomInt } from 'node:crypto';
|
|
6
6
|
|
package/src/model/RoomMap.ts
CHANGED
package/src/platform.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { AnsiLogger, debugStringify, LogLevel } from 'matterbridge/logger';
|
|
|
4
4
|
import RoborockService from './roborockService.js';
|
|
5
5
|
import { PLUGIN_NAME } from './settings.js';
|
|
6
6
|
import ClientManager from './clientManager.js';
|
|
7
|
-
import { isSupportedDevice } from './helper.js';
|
|
7
|
+
import { getRoomMapFromDevice, isSupportedDevice } from './helper.js';
|
|
8
8
|
import { PlatformRunner } from './platformRunner.js';
|
|
9
9
|
import { RoborockVacuumCleaner } from './rvc.js';
|
|
10
10
|
import { configurateBehavior } from './behaviorFactory.js';
|
|
@@ -231,7 +231,7 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
231
231
|
vacuum.rooms = rooms.map((room) => ({ id: room.id, name: room.displayName }) as Room);
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
const roomMap = await
|
|
234
|
+
const roomMap = await getRoomMapFromDevice(vacuum, this);
|
|
235
235
|
|
|
236
236
|
this.log.debug('Initializing - roomMap: ', debugStringify(roomMap));
|
|
237
237
|
|
package/src/platformRunner.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { RvcRunMode, PowerSource, ServiceArea, RvcOperationalState, RvcCleanMode } from 'matterbridge/matter/clusters';
|
|
2
|
-
import { getVacuumProperty } from './helper.js';
|
|
2
|
+
import { getRoomMap, getVacuumProperty, isStatusUpdate } from './helper.js';
|
|
3
3
|
import { getRunningMode } from './initialData/getSupportedRunModes.js';
|
|
4
4
|
import { CloudMessageModel } from './model/CloudMessageModel.js';
|
|
5
5
|
import { RoborockMatterbridgePlatform } from './platform.js';
|
|
6
6
|
import { state_to_matter_operational_status, state_to_matter_state } from './share/function.js';
|
|
7
|
-
import RoomMap from './model/RoomMap.js';
|
|
8
7
|
import { getBatteryState, getBatteryStatus, getOperationalErrorState } from './initialData/index.js';
|
|
9
8
|
import { NotifyMessageTypes } from './notifyMessageTypes.js';
|
|
10
9
|
import { CloudMessageResult } from './roborockCommunication/Zmodel/messageResult.js';
|
|
@@ -41,76 +40,6 @@ export class PlatformRunner {
|
|
|
41
40
|
await this.updateRobot(NotifyMessageTypes.HomeData, homeData);
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
public async getRoomMapFromDevice(device: Device): Promise<RoomMap> {
|
|
45
|
-
const platform = this.platform;
|
|
46
|
-
const rooms = device?.rooms ?? [];
|
|
47
|
-
|
|
48
|
-
platform.log.notice('-------------------------------------------0--------------------------------------------------------');
|
|
49
|
-
platform.log.notice(`getRoomMapFromDevice: ${debugStringify(rooms)}`);
|
|
50
|
-
|
|
51
|
-
if (device && platform.roborockService) {
|
|
52
|
-
const roomData = await platform.roborockService.getRoomMappings(device.duid);
|
|
53
|
-
if (roomData !== undefined && roomData.length > 0) {
|
|
54
|
-
platform.log.notice(`getRoomMapFromDevice - roomData: ${debugStringify(roomData ?? [])}`);
|
|
55
|
-
|
|
56
|
-
const roomMap = new RoomMap(roomData ?? [], rooms);
|
|
57
|
-
|
|
58
|
-
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
59
|
-
platform.log.notice('-------------------------------------------1--------------------------------------------------------');
|
|
60
|
-
return roomMap;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const mapInfo = await platform.roborockService.getMapInformation(device.duid);
|
|
64
|
-
platform.log.notice(`getRoomMapFromDevice - mapInfo: ${mapInfo ? debugStringify(mapInfo) : 'undefined'}`);
|
|
65
|
-
|
|
66
|
-
if (mapInfo && mapInfo.maps && mapInfo.maps.length > 0) {
|
|
67
|
-
const roomDataMap = mapInfo.maps[0].rooms.map((r) => [r.id, parseInt(r.iot_name_id), r.tag] as [number, number, number]);
|
|
68
|
-
|
|
69
|
-
const roomMap = new RoomMap(roomDataMap, rooms);
|
|
70
|
-
|
|
71
|
-
platform.log.notice(`getRoomMapFromDevice - roomMap: ${debugStringify(roomMap)}`);
|
|
72
|
-
platform.log.notice('-------------------------------------------2--------------------------------------------------------');
|
|
73
|
-
return roomMap;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return new RoomMap([], rooms);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
private async getRoomMap(duid: string): Promise<RoomMap | undefined> {
|
|
81
|
-
const platform = this.platform;
|
|
82
|
-
|
|
83
|
-
const robot = platform.robots.get(duid);
|
|
84
|
-
if (robot === undefined) {
|
|
85
|
-
platform.log.error(`Error6: Robot with DUID ${duid} not found`);
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (platform.roborockService === undefined) return undefined;
|
|
90
|
-
|
|
91
|
-
const rooms = robot.device.rooms ?? [];
|
|
92
|
-
// if (platform.robot?.device === undefined || platform.roborockService === undefined) return undefined;
|
|
93
|
-
if (robot.roomInfo === undefined) {
|
|
94
|
-
const roomData = await platform.roborockService.getRoomMappings(robot.device.duid);
|
|
95
|
-
if (roomData !== undefined && roomData.length > 0) {
|
|
96
|
-
robot.roomInfo = new RoomMap(roomData ?? [], rooms);
|
|
97
|
-
return robot.roomInfo;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (robot.roomInfo === undefined) {
|
|
102
|
-
const mapInfo = await platform.roborockService.getMapInformation(robot.device.duid);
|
|
103
|
-
if (mapInfo && mapInfo.maps && mapInfo.maps.length > 0) {
|
|
104
|
-
platform.log.error(`getRoomMap - mapInfo: ${debugStringify(mapInfo.maps)}`);
|
|
105
|
-
|
|
106
|
-
const roomDataMap = mapInfo.maps[0].rooms.map((r) => [r.id, parseInt(r.iot_name_id), r.tag] as [number, number, number]);
|
|
107
|
-
robot.roomInfo = new RoomMap(roomDataMap, rooms);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return robot.roomInfo;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
43
|
private async updateFromMQTTMessage(messageSource: NotifyMessageTypes, messageData: unknown, duid = '', tracked = false): Promise<void> {
|
|
115
44
|
const platform = this.platform;
|
|
116
45
|
duid = duid || (messageData as DeviceStatusNotify)?.duid || '';
|
|
@@ -191,7 +120,7 @@ export class PlatformRunner {
|
|
|
191
120
|
robot.updateAttribute(ServiceArea.Cluster.id, 'selectedAreas', [], platform.log);
|
|
192
121
|
} else {
|
|
193
122
|
const currentMappedAreas = this.platform.roborockService?.getSupportedAreas(duid);
|
|
194
|
-
const roomMap = await
|
|
123
|
+
const roomMap = await getRoomMap(duid, this.platform);
|
|
195
124
|
|
|
196
125
|
// Get current room from segment_id
|
|
197
126
|
const segment_id = data.cleaning_info?.segment_id ?? -1;
|
|
@@ -311,7 +240,7 @@ export class PlatformRunner {
|
|
|
311
240
|
case Protocol.rpc_response: {
|
|
312
241
|
const response = data.dps[messageType] as DpsPayload;
|
|
313
242
|
// ignore network info
|
|
314
|
-
if (!
|
|
243
|
+
if (!isStatusUpdate(response.result)) {
|
|
315
244
|
platform.log.debug('Ignore message:', debugStringify(data));
|
|
316
245
|
return;
|
|
317
246
|
}
|
|
@@ -398,18 +327,6 @@ export class PlatformRunner {
|
|
|
398
327
|
return undefined;
|
|
399
328
|
}
|
|
400
329
|
|
|
401
|
-
private isStatusUpdate(result: unknown): boolean {
|
|
402
|
-
return (
|
|
403
|
-
Array.isArray(result) &&
|
|
404
|
-
result.length > 0 &&
|
|
405
|
-
typeof result[0] === 'object' &&
|
|
406
|
-
result[0] !== null &&
|
|
407
|
-
'msg_ver' in result[0] &&
|
|
408
|
-
(result[0] as CloudMessageResult).msg_ver !== undefined &&
|
|
409
|
-
(result[0] as CloudMessageResult).msg_ver !== null
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
330
|
private updateFromHomeData(homeData: Home): void {
|
|
414
331
|
const platform = this.platform;
|
|
415
332
|
|
|
@@ -80,12 +80,11 @@ export class LocalNetworkClient extends AbstractClient {
|
|
|
80
80
|
private async onConnect(): Promise<void> {
|
|
81
81
|
this.logger.debug(` [LocalNetworkClient]: ${this.duid} connected to ${this.ip}`);
|
|
82
82
|
this.logger.debug(` [LocalNetworkClient]: ${this.duid} socket writable: ${this.socket?.writable}, readable: ${this.socket?.readable}`);
|
|
83
|
+
this.connected = true;
|
|
84
|
+
this.retryCount = 0;
|
|
83
85
|
|
|
84
86
|
await this.sendHelloMessage();
|
|
85
87
|
this.pingInterval = setInterval(this.sendPingRequest.bind(this), 5000);
|
|
86
|
-
|
|
87
|
-
this.connected = true;
|
|
88
|
-
this.retryCount = 0;
|
|
89
88
|
await this.connectionListeners.onConnected(this.duid);
|
|
90
89
|
}
|
|
91
90
|
|
|
@@ -28,10 +28,10 @@ export class SyncMessageListener implements AbstractMessageListener {
|
|
|
28
28
|
const messageId = dps.id;
|
|
29
29
|
|
|
30
30
|
const responseHandler = this.pending.get(messageId);
|
|
31
|
-
const result = dps.result as Record<string, unknown>;
|
|
32
|
-
if (result && result.length == 1 && result[0] == 'ok') {
|
|
33
|
-
|
|
34
|
-
}
|
|
31
|
+
// const result = dps.result as Record<string, unknown>;
|
|
32
|
+
// if (result && result.length == 1 && result[0] == 'ok') {
|
|
33
|
+
// return;
|
|
34
|
+
// }
|
|
35
35
|
|
|
36
36
|
if (responseHandler) {
|
|
37
37
|
responseHandler(dps.result as ResponseMessage);
|
|
@@ -105,9 +105,9 @@ export class MessageProcessor {
|
|
|
105
105
|
return this.client.get(duid, def);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
public async findMyRobot(duid: string): Promise<
|
|
108
|
+
public async findMyRobot(duid: string): Promise<unknown> {
|
|
109
109
|
const request = new RequestMessage({ method: 'find_me' });
|
|
110
|
-
return this.client.
|
|
110
|
+
return this.client.get(duid, request);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
public async getCleanModeData(duid: string): Promise<{ suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number }> {
|
package/src/rvc.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RoboticVacuumCleaner } from 'matterbridge/devices';
|
|
2
|
-
import RoomMap from './model/RoomMap.js';
|
|
2
|
+
import { RoomMap } from './model/RoomMap.js';
|
|
3
3
|
import { Device } from './roborockCommunication/index.js';
|
|
4
4
|
import { getOperationalStates, getSupportedAreas, getSupportedCleanModes, getSupportedRunModes } from './initialData/index.js';
|
|
5
5
|
import { AnsiLogger } from 'matterbridge/logger';
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { PlatformRunner } from '../platformRunner';
|
|
1
|
+
import { getRoomMapFromDevice } from '../helper';
|
|
2
|
+
import { RoomMap } from '../model/RoomMap';
|
|
4
3
|
import { MapInfo } from '../roborockCommunication';
|
|
5
4
|
|
|
6
5
|
describe('PlatformRunner.getRoomMapFromDevice', () => {
|
|
7
6
|
let platform: any;
|
|
8
|
-
let runner: PlatformRunner;
|
|
9
7
|
|
|
10
8
|
beforeEach(() => {
|
|
11
9
|
platform = {
|
|
@@ -19,7 +17,6 @@ describe('PlatformRunner.getRoomMapFromDevice', () => {
|
|
|
19
17
|
getMapInformation: jest.fn(),
|
|
20
18
|
},
|
|
21
19
|
};
|
|
22
|
-
runner = new PlatformRunner(platform as RoborockMatterbridgePlatform);
|
|
23
20
|
});
|
|
24
21
|
|
|
25
22
|
it('returns RoomMap with roomData from getRoomMappings if available', async () => {
|
|
@@ -42,7 +39,7 @@ describe('PlatformRunner.getRoomMapFromDevice', () => {
|
|
|
42
39
|
platform.roborockService.getRoomMappings.mockResolvedValue(roomData);
|
|
43
40
|
platform.roborockService.getMapInformation.mockResolvedValue(undefined);
|
|
44
41
|
|
|
45
|
-
const result = await
|
|
42
|
+
const result = await getRoomMapFromDevice(device as any, platform);
|
|
46
43
|
|
|
47
44
|
expect(result).toBeInstanceOf(RoomMap);
|
|
48
45
|
expect(result.rooms.length).toEqual(4);
|
|
@@ -83,7 +80,7 @@ describe('PlatformRunner.getRoomMapFromDevice', () => {
|
|
|
83
80
|
platform.roborockService.getRoomMappings.mockResolvedValue(undefined);
|
|
84
81
|
platform.roborockService.getMapInformation.mockResolvedValue(mapInfo);
|
|
85
82
|
|
|
86
|
-
const result = await
|
|
83
|
+
const result = await getRoomMapFromDevice(device as any, platform);
|
|
87
84
|
|
|
88
85
|
expect(result).toBeInstanceOf(RoomMap);
|
|
89
86
|
expect(result.rooms.length).toEqual(4);
|
|
@@ -35,7 +35,7 @@ describe('SyncMessageListener', () => {
|
|
|
35
35
|
expect(listener['pending'].has(messageId)).toBe(false);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
it('should
|
|
38
|
+
it('should call resolve if result is ["ok"]', async () => {
|
|
39
39
|
const resolve = jest.fn();
|
|
40
40
|
const reject = jest.fn();
|
|
41
41
|
const messageId = 456;
|
|
@@ -49,8 +49,8 @@ describe('SyncMessageListener', () => {
|
|
|
49
49
|
|
|
50
50
|
await listener.onMessage(message);
|
|
51
51
|
|
|
52
|
-
expect(resolve).
|
|
53
|
-
expect(listener['pending'].has(messageId)).toBe(
|
|
52
|
+
expect(resolve).toHaveBeenCalled();
|
|
53
|
+
expect(listener['pending'].has(messageId)).toBe(false);
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
it('should remove pending on map_response', async () => {
|
|
@@ -104,7 +104,7 @@ describe('MessageProcessor', () => {
|
|
|
104
104
|
|
|
105
105
|
it('findMyRobot should call client.send', async () => {
|
|
106
106
|
await processor.findMyRobot('duid');
|
|
107
|
-
expect(mockClient.
|
|
107
|
+
expect(mockClient.get).toHaveBeenCalledWith('duid', expect.any(Object));
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
it('getCleanModeData should parse and return correct values', async () => {
|