matterbridge-roborock-vacuum-plugin 1.1.0-rc15 → 1.1.0-rc17
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/build.yml +5 -1
- package/.github/workflows/coverage.yml +5 -1
- package/CHANGELOG.md +62 -0
- package/dist/helper.js +24 -21
- package/dist/initialData/getSupportedAreas.js +91 -48
- package/dist/model/ExperimentalFeatureSetting.js +1 -0
- package/dist/model/RoomMap.js +13 -7
- package/dist/model/roomIndexMap.js +17 -0
- package/dist/platform.js +7 -5
- package/dist/platformRunner.js +32 -5
- package/dist/roborockCommunication/Zenum/additionalPropCode.js +4 -0
- package/dist/roborockCommunication/Zmodel/mapInfo.js +17 -16
- package/dist/roborockCommunication/broadcast/messageProcessor.js +2 -3
- package/dist/roborockCommunication/index.js +1 -0
- package/dist/roborockService.js +11 -2
- package/dist/rvc.js +5 -2
- package/matterbridge-roborock-vacuum-plugin.config.json +4 -3
- package/matterbridge-roborock-vacuum-plugin.schema.json +42 -10
- package/package.json +1 -1
- package/src/helper.ts +28 -26
- package/src/initialData/getSupportedAreas.ts +115 -45
- package/src/model/ExperimentalFeatureSetting.ts +2 -0
- package/src/model/RoomMap.ts +33 -15
- package/src/model/roomIndexMap.ts +20 -0
- package/src/platform.ts +8 -5
- package/src/platformRunner.ts +41 -6
- package/src/roborockCommunication/Zenum/additionalPropCode.ts +3 -0
- package/src/roborockCommunication/Zmodel/map.ts +2 -2
- package/src/roborockCommunication/Zmodel/mapInfo.ts +37 -18
- package/src/roborockCommunication/Zmodel/multipleMap.ts +2 -2
- package/src/roborockCommunication/broadcast/messageProcessor.ts +2 -4
- package/src/roborockCommunication/index.ts +1 -0
- package/src/roborockService.ts +20 -2
- package/src/rvc.ts +7 -2
- package/src/tests/helper.test.ts +113 -0
- package/src/tests/initialData/getSupportedAreas.test.ts +80 -7
- package/src/tests/platformRunner2.test.ts +145 -5
- package/src/tests/platformRunner3.test.ts +54 -0
- package/src/tests/roborockCommunication/broadcast/messageProcessor.test.ts +2 -7
- package/src/tests/roborockService.test.ts +22 -1
- package/web-for-testing/package-lock.json +14 -12
- package/web-for-testing/package.json +1 -1
- package/web-for-testing/src/accountStore.ts +0 -10
|
@@ -63,17 +63,50 @@ describe('PlatformRunner.getRoomMapFromDevice', () => {
|
|
|
63
63
|
map_info: [
|
|
64
64
|
{
|
|
65
65
|
mapFlag: 0,
|
|
66
|
-
add_time:
|
|
67
|
-
length:
|
|
68
|
-
name: '',
|
|
69
|
-
bak_maps: [{ mapFlag: 4, add_time:
|
|
66
|
+
add_time: 1753511673,
|
|
67
|
+
length: 9,
|
|
68
|
+
name: 'First Map',
|
|
69
|
+
bak_maps: [{ mapFlag: 4, add_time: 1753578164 }],
|
|
70
70
|
rooms: [
|
|
71
71
|
{ id: 1, tag: 14, iot_name_id: '11100845', iot_name: 'Kitchen' },
|
|
72
72
|
{ id: 2, tag: 9, iot_name_id: '11100849', iot_name: 'Study' },
|
|
73
|
-
{
|
|
73
|
+
{
|
|
74
|
+
id: 3,
|
|
75
|
+
tag: 6,
|
|
76
|
+
iot_name_id: '11100842',
|
|
77
|
+
iot_name: 'Living room',
|
|
78
|
+
},
|
|
74
79
|
{ id: 4, tag: 1, iot_name_id: '11100847', iot_name: 'Bedroom' },
|
|
75
80
|
],
|
|
76
81
|
},
|
|
82
|
+
{
|
|
83
|
+
mapFlag: 1,
|
|
84
|
+
add_time: 1753579596,
|
|
85
|
+
length: 10,
|
|
86
|
+
name: 'Second Map',
|
|
87
|
+
bak_maps: [{ mapFlag: 5, add_time: 1753578579 }],
|
|
88
|
+
rooms: [
|
|
89
|
+
{
|
|
90
|
+
id: 1,
|
|
91
|
+
tag: 6,
|
|
92
|
+
iot_name_id: '11100842',
|
|
93
|
+
iot_name: 'Living room',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 2,
|
|
97
|
+
tag: 3,
|
|
98
|
+
iot_name_id: '12461114',
|
|
99
|
+
iot_name: 'Guest bedroom',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 3,
|
|
103
|
+
tag: 2,
|
|
104
|
+
iot_name_id: '12461109',
|
|
105
|
+
iot_name: 'Master bedroom',
|
|
106
|
+
},
|
|
107
|
+
{ id: 4, tag: 7, iot_name_id: '12461111', iot_name: 'Balcony' },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
77
110
|
],
|
|
78
111
|
});
|
|
79
112
|
|
|
@@ -81,8 +114,115 @@ describe('PlatformRunner.getRoomMapFromDevice', () => {
|
|
|
81
114
|
platform.roborockService.getMapInformation.mockResolvedValue(mapInfo);
|
|
82
115
|
|
|
83
116
|
const result = await getRoomMapFromDevice(device as any, platform);
|
|
117
|
+
expect(result).toBeInstanceOf(RoomMap);
|
|
118
|
+
expect(result.rooms.length).toEqual(4);
|
|
119
|
+
|
|
120
|
+
platform.enableExperimentalFeature = {
|
|
121
|
+
enableExperimentalFeature: true,
|
|
122
|
+
advancedFeature: {
|
|
123
|
+
enableMultipleMap: true,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const result1 = await getRoomMapFromDevice(device as any, platform);
|
|
128
|
+
expect(result1).toBeInstanceOf(RoomMap);
|
|
129
|
+
expect(result1.rooms.length).toEqual(8);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('returns RoomMap with empty roomData from getMapInformation if available', async () => {
|
|
133
|
+
const device = {
|
|
134
|
+
duid: 'duid1',
|
|
135
|
+
rooms: [
|
|
136
|
+
{ id: 1, name: 'Kitchen' },
|
|
137
|
+
{ id: 2, name: 'Study' },
|
|
138
|
+
{ id: 3, name: 'Living room' },
|
|
139
|
+
{ id: 4, name: 'Bedroom' },
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const mapInfo = new MapInfo({
|
|
144
|
+
max_multi_map: 4,
|
|
145
|
+
max_bak_map: 0,
|
|
146
|
+
multi_map_count: 1,
|
|
147
|
+
map_info: [
|
|
148
|
+
{
|
|
149
|
+
mapFlag: 0,
|
|
150
|
+
add_time: 1753731408,
|
|
151
|
+
length: 0,
|
|
152
|
+
name: '',
|
|
153
|
+
bak_maps: [],
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
platform.roborockService.getRoomMappings.mockResolvedValue(undefined);
|
|
159
|
+
platform.roborockService.getMapInformation.mockResolvedValue(mapInfo);
|
|
160
|
+
|
|
161
|
+
const result = await getRoomMapFromDevice(device as any, platform);
|
|
162
|
+
expect(result).toBeInstanceOf(RoomMap);
|
|
163
|
+
expect(result.rooms.length).toEqual(0);
|
|
164
|
+
|
|
165
|
+
platform.enableExperimentalFeature = {
|
|
166
|
+
enableExperimentalFeature: true,
|
|
167
|
+
advancedFeature: {
|
|
168
|
+
enableMultipleMap: true,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const result1 = await getRoomMapFromDevice(device as any, platform);
|
|
173
|
+
expect(result1).toBeInstanceOf(RoomMap);
|
|
174
|
+
expect(result1.rooms.length).toEqual(0);
|
|
175
|
+
});
|
|
84
176
|
|
|
177
|
+
it('returns RoomMap with roomData from getMapInformation if available', async () => {
|
|
178
|
+
const device = {
|
|
179
|
+
duid: 'duid1',
|
|
180
|
+
rooms: [
|
|
181
|
+
{ id: 1, name: 'Kitchen' },
|
|
182
|
+
{ id: 2, name: 'Study' },
|
|
183
|
+
{ id: 3, name: 'Living room' },
|
|
184
|
+
{ id: 4, name: 'Bedroom' },
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const mapInfo = new MapInfo({
|
|
189
|
+
max_multi_map: 4,
|
|
190
|
+
max_bak_map: 0,
|
|
191
|
+
multi_map_count: 1,
|
|
192
|
+
map_info: [
|
|
193
|
+
{
|
|
194
|
+
mapFlag: 0,
|
|
195
|
+
add_time: 1753731408,
|
|
196
|
+
length: 0,
|
|
197
|
+
name: '',
|
|
198
|
+
bak_maps: [],
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const roomData = [
|
|
204
|
+
[1, '11100845', 14],
|
|
205
|
+
[2, '11100849', 9],
|
|
206
|
+
[3, '11100842', 6],
|
|
207
|
+
[4, '11100847', 1],
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
platform.roborockService.getRoomMappings.mockResolvedValue(roomData);
|
|
211
|
+
platform.roborockService.getMapInformation.mockResolvedValue(mapInfo);
|
|
212
|
+
|
|
213
|
+
const result = await getRoomMapFromDevice(device as any, platform);
|
|
85
214
|
expect(result).toBeInstanceOf(RoomMap);
|
|
86
215
|
expect(result.rooms.length).toEqual(4);
|
|
216
|
+
|
|
217
|
+
platform.enableExperimentalFeature = {
|
|
218
|
+
enableExperimentalFeature: true,
|
|
219
|
+
advancedFeature: {
|
|
220
|
+
enableMultipleMap: true,
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const result1 = await getRoomMapFromDevice(device as any, platform);
|
|
225
|
+
expect(result1).toBeInstanceOf(RoomMap);
|
|
226
|
+
expect(result1.rooms.length).toEqual(4);
|
|
87
227
|
});
|
|
88
228
|
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { PlatformRunner } from '../platformRunner';
|
|
2
|
+
import { NotifyMessageTypes } from '../notifyMessageTypes';
|
|
3
|
+
import { RoborockMatterbridgePlatform } from '../platform';
|
|
4
|
+
import { RoborockVacuumCleaner } from '../rvc';
|
|
5
|
+
import * as initialDataIndex from '../initialData/index';
|
|
6
|
+
|
|
7
|
+
const getOperationalErrorState = jest.fn().mockReturnValue(2);
|
|
8
|
+
|
|
9
|
+
jest.mock('./src/initialData/index', () => ({
|
|
10
|
+
...initialDataIndex,
|
|
11
|
+
getOperationalErrorState,
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
describe('PlatformRunner.updateRobot', () => {
|
|
15
|
+
let platform: RoborockMatterbridgePlatform;
|
|
16
|
+
let runner: PlatformRunner;
|
|
17
|
+
let robotMock: any;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
robotMock = {
|
|
21
|
+
updateAttribute: jest.fn(),
|
|
22
|
+
getAttribute: jest.fn(),
|
|
23
|
+
device: {
|
|
24
|
+
data: { model: 'test-model' },
|
|
25
|
+
duid: '123456',
|
|
26
|
+
rooms: [],
|
|
27
|
+
},
|
|
28
|
+
serialNumber: '123456',
|
|
29
|
+
dockStationStatus: undefined,
|
|
30
|
+
roomInfo: undefined,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const robots = new Map<string, RoborockVacuumCleaner>();
|
|
34
|
+
robots.set('123456', robotMock);
|
|
35
|
+
|
|
36
|
+
platform = {
|
|
37
|
+
robots: robots,
|
|
38
|
+
log: {
|
|
39
|
+
error: jest.fn(),
|
|
40
|
+
debug: jest.fn(),
|
|
41
|
+
notice: jest.fn(),
|
|
42
|
+
},
|
|
43
|
+
enableExperimentalFeature: undefined,
|
|
44
|
+
} as unknown as RoborockMatterbridgePlatform;
|
|
45
|
+
|
|
46
|
+
runner = new PlatformRunner(platform);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should handle unknown message types gracefully', async () => {
|
|
50
|
+
const mapUpdated = { duid: '123456', dps: { 128: 4 } };
|
|
51
|
+
await runner['updateFromMQTTMessage'](NotifyMessageTypes.CloudMessage, mapUpdated, '123456');
|
|
52
|
+
expect(platform.log.notice).toHaveBeenCalled();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { MessageProcessor } from '../../../roborockCommunication/broadcast/messageProcessor';
|
|
2
2
|
import { DeviceStatus } from '../../../roborockCommunication/Zmodel/deviceStatus';
|
|
3
|
-
import { RoomInfo } from '../../../roborockCommunication/Zmodel/roomInfo';
|
|
4
3
|
|
|
5
4
|
describe('MessageProcessor', () => {
|
|
6
5
|
let mockClient: any;
|
|
@@ -51,13 +50,9 @@ describe('MessageProcessor', () => {
|
|
|
51
50
|
});
|
|
52
51
|
|
|
53
52
|
it('getRooms should return RoomInfo', async () => {
|
|
54
|
-
const rooms = [
|
|
55
|
-
{ id: 1, name: 'Room1' },
|
|
56
|
-
{ id: 2, name: 'Room2' },
|
|
57
|
-
];
|
|
58
53
|
mockClient.get.mockResolvedValue([[1, 2]]);
|
|
59
|
-
const result = await processor.getRooms('duid'
|
|
60
|
-
expect(result).
|
|
54
|
+
const result = await processor.getRooms('duid');
|
|
55
|
+
expect(result).not.toBeUndefined();
|
|
61
56
|
});
|
|
62
57
|
|
|
63
58
|
it('gotoDock should call client.send', async () => {
|
|
@@ -3,6 +3,7 @@ import { ServiceArea } from 'matterbridge/matter/clusters';
|
|
|
3
3
|
import RoborockService from '../roborockService';
|
|
4
4
|
import { MessageProcessor } from '../roborockCommunication/broadcast/messageProcessor';
|
|
5
5
|
import { Device, MultipleMap, RequestMessage } from '../roborockCommunication';
|
|
6
|
+
import { RoomIndexMap } from '../model/roomIndexMap';
|
|
6
7
|
|
|
7
8
|
describe('RoborockService - startClean', () => {
|
|
8
9
|
let roborockService: RoborockService;
|
|
@@ -55,7 +56,17 @@ describe('RoborockService - startClean', () => {
|
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
it('should return MapInfo if response contains maps', async () => {
|
|
58
|
-
const mapData = [
|
|
59
|
+
const mapData = [
|
|
60
|
+
{
|
|
61
|
+
map_info: [
|
|
62
|
+
{
|
|
63
|
+
rooms: [{ id: 1, iot_name_id: 'room1', tag: 0, iot_name: 'Living Room' }],
|
|
64
|
+
mapFlag: 1,
|
|
65
|
+
name: 'Living Room Map',
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
] as MultipleMap[];
|
|
59
70
|
mockMessageClient = {
|
|
60
71
|
get: jest.fn(),
|
|
61
72
|
};
|
|
@@ -272,7 +283,17 @@ describe('RoborockService - basic setters/getters', () => {
|
|
|
272
283
|
});
|
|
273
284
|
|
|
274
285
|
it('setSelectedAreas should set selected areas', () => {
|
|
286
|
+
roborockService.setSupportedAreaIndexMap(
|
|
287
|
+
'duid',
|
|
288
|
+
new RoomIndexMap(
|
|
289
|
+
new Map([
|
|
290
|
+
[1, { roomId: 1, mapId: 0 }],
|
|
291
|
+
[2, { roomId: 2, mapId: 1 }],
|
|
292
|
+
]),
|
|
293
|
+
),
|
|
294
|
+
);
|
|
275
295
|
roborockService.setSelectedAreas('duid', [1, 2]);
|
|
296
|
+
|
|
276
297
|
expect(roborockService['selectedAreas'].get('duid')).toEqual([1, 2]);
|
|
277
298
|
expect(mockLogger.debug).toHaveBeenCalledWith('RoborockService - setSelectedAreas', [1, 2]);
|
|
278
299
|
});
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"binary-parser": "^2.2.1",
|
|
13
13
|
"ejs": "^3.1.10",
|
|
14
14
|
"express": "^5.1.0",
|
|
15
|
-
"matterbridge": "^3.1.
|
|
15
|
+
"matterbridge": "^3.1.8",
|
|
16
16
|
"node-ansi-logger": "^3.0.1"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
@@ -2351,9 +2351,9 @@
|
|
|
2351
2351
|
"license": "MIT"
|
|
2352
2352
|
},
|
|
2353
2353
|
"node_modules/matterbridge": {
|
|
2354
|
-
"version": "3.1.
|
|
2355
|
-
"resolved": "https://registry.npmjs.org/matterbridge/-/matterbridge-3.1.
|
|
2356
|
-
"integrity": "sha512-
|
|
2354
|
+
"version": "3.1.8",
|
|
2355
|
+
"resolved": "https://registry.npmjs.org/matterbridge/-/matterbridge-3.1.8.tgz",
|
|
2356
|
+
"integrity": "sha512-KYGSw088++v8UBr2+iCewrfuNGbZpr9AzhbNbVpaXGzGkxaonUQ7397ZQ4MRMTmdpsEteOJb4Hcx4IJtXUuZdA==",
|
|
2357
2357
|
"hasShrinkwrap": true,
|
|
2358
2358
|
"license": "Apache-2.0",
|
|
2359
2359
|
"dependencies": {
|
|
@@ -2361,13 +2361,15 @@
|
|
|
2361
2361
|
"archiver": "7.0.1",
|
|
2362
2362
|
"express": "5.1.0",
|
|
2363
2363
|
"glob": "11.0.3",
|
|
2364
|
-
"multer": "2.0.
|
|
2364
|
+
"multer": "2.0.2",
|
|
2365
2365
|
"node-ansi-logger": "3.1.1",
|
|
2366
2366
|
"node-persist-manager": "2.0.0",
|
|
2367
2367
|
"ws": "8.18.3"
|
|
2368
2368
|
},
|
|
2369
2369
|
"bin": {
|
|
2370
|
-
"matterbridge": "bin/matterbridge.js"
|
|
2370
|
+
"matterbridge": "bin/matterbridge.js",
|
|
2371
|
+
"mb_coap": "bin/mb_coap.js",
|
|
2372
|
+
"mb_mdns": "bin/mb_mdns.js"
|
|
2371
2373
|
},
|
|
2372
2374
|
"engines": {
|
|
2373
2375
|
"node": ">=18.0.0 <19.0.0 || >=20.0.0 <21.0.0 || >=22.0.0 <23.0.0 || >=24.0.0 <25.0.0"
|
|
@@ -2499,9 +2501,9 @@
|
|
|
2499
2501
|
}
|
|
2500
2502
|
},
|
|
2501
2503
|
"node_modules/matterbridge/node_modules/@noble/curves": {
|
|
2502
|
-
"version": "1.9.
|
|
2503
|
-
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.
|
|
2504
|
-
"integrity": "sha512-
|
|
2504
|
+
"version": "1.9.4",
|
|
2505
|
+
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.4.tgz",
|
|
2506
|
+
"integrity": "sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==",
|
|
2505
2507
|
"license": "MIT",
|
|
2506
2508
|
"dependencies": {
|
|
2507
2509
|
"@noble/hashes": "1.8.0"
|
|
@@ -3627,9 +3629,9 @@
|
|
|
3627
3629
|
"license": "MIT"
|
|
3628
3630
|
},
|
|
3629
3631
|
"node_modules/matterbridge/node_modules/multer": {
|
|
3630
|
-
"version": "2.0.
|
|
3631
|
-
"resolved": "https://registry.npmjs.org/multer/-/multer-2.0.
|
|
3632
|
-
"integrity": "sha512-
|
|
3632
|
+
"version": "2.0.2",
|
|
3633
|
+
"resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz",
|
|
3634
|
+
"integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==",
|
|
3633
3635
|
"license": "MIT",
|
|
3634
3636
|
"dependencies": {
|
|
3635
3637
|
"append-field": "^1.0.0",
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { UserData } from './ext/roborockCommunication/index.js';
|
|
2
|
-
|
|
3
|
-
export function getAccountStore(): Map<string, UserData> {
|
|
4
|
-
const accountStore = new Map<string, UserData>();
|
|
5
|
-
|
|
6
|
-
// Initialize with a default user data if needed
|
|
7
|
-
// accountStore.set('defaultUser', new UserData());
|
|
8
|
-
|
|
9
|
-
return accountStore;
|
|
10
|
-
}
|