matterbridge-roborock-vacuum-plugin 1.1.0-rc17 → 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.
Files changed (34) hide show
  1. package/dist/helper.js +2 -7
  2. package/dist/initialData/getSupportedAreas.js +1 -1
  3. package/dist/model/RoomMap.js +1 -1
  4. package/dist/model/roomIndexMap.js +8 -4
  5. package/dist/platform.js +4 -3
  6. package/dist/platformRunner.js +10 -266
  7. package/dist/runtimes/handleCloudMessage.js +110 -0
  8. package/dist/runtimes/handleHomeDataMessage.js +57 -0
  9. package/dist/runtimes/handleLocalMessage.js +169 -0
  10. package/dist/tests/testData/mockData.js +359 -0
  11. package/matterbridge-roborock-vacuum-plugin.config.json +2 -2
  12. package/matterbridge-roborock-vacuum-plugin.schema.json +10 -37
  13. package/package.json +2 -2
  14. package/src/behaviors/roborock.vacuum/default/runtimes.ts +1 -1
  15. package/src/behaviors/roborock.vacuum/smart/runtimes.ts +1 -1
  16. package/src/helper.ts +2 -12
  17. package/src/initialData/getSupportedAreas.ts +2 -10
  18. package/src/model/RoomMap.ts +4 -30
  19. package/src/model/roomIndexMap.ts +10 -6
  20. package/src/platform.ts +6 -3
  21. package/src/platformRunner.ts +12 -349
  22. package/src/roborockCommunication/Zmodel/device.ts +13 -1
  23. package/src/roborockCommunication/Zmodel/messageResult.ts +28 -27
  24. package/src/roborockCommunication/Zmodel/userData.ts +2 -1
  25. package/src/runtimes/handleCloudMessage.ts +134 -0
  26. package/src/runtimes/handleHomeDataMessage.ts +67 -0
  27. package/src/runtimes/handleLocalMessage.ts +209 -0
  28. package/src/share/runtimeHelper.ts +1 -1
  29. package/src/tests/helper.test.ts +59 -10
  30. package/src/tests/roborockService.setSelectedAreas.test.ts +61 -0
  31. package/src/tests/runtimes/handleCloudMessage.test.ts +200 -0
  32. package/src/tests/runtimes/handleHomeDataMessage.test.ts +53 -0
  33. package/src/tests/runtimes/handleLocalMessage.test.ts +222 -0
  34. package/src/tests/testData/mockData.ts +370 -0
@@ -0,0 +1,169 @@
1
+ import { PowerSource, RvcCleanMode, RvcOperationalState, RvcRunMode, ServiceArea } from 'matterbridge/matter/clusters';
2
+ import { getRunningMode } from '../initialData/getSupportedRunModes.js';
3
+ import { state_to_matter_state } from '../share/function.js';
4
+ import { OperationStatusCode } from '../roborockCommunication/Zenum/operationStatusCode.js';
5
+ import { getRoomMap } from '../helper.js';
6
+ import { debugStringify } from 'matterbridge/logger';
7
+ import { getBatteryState, getBatteryStatus } from '../initialData/index.js';
8
+ import { getCurrentCleanModeFunc } from '../share/runtimeHelper.js';
9
+ import { hasDockingStationError, parseDockingStationStatus } from '../model/DockingStationStatus.js';
10
+ export async function handleLocalMessage(data, platform, duid = '') {
11
+ const robot = platform.robots.get(duid);
12
+ if (!robot) {
13
+ platform.log.error(`Robot with DUID ${duid} not found.`);
14
+ return;
15
+ }
16
+ const currentMappedAreas = platform.roborockService?.getSupportedAreas(duid);
17
+ const roomIndexMap = platform.roborockService?.getSupportedAreasIndexMap(duid);
18
+ const roomMap = await getRoomMap(duid, platform);
19
+ platform.log.debug(`RoomMap: ${roomMap ? debugStringify(roomMap) : 'undefined'}`);
20
+ platform.log.debug(`Current mapped areas: ${currentMappedAreas ? debugStringify(currentMappedAreas) : 'undefined'}`);
21
+ platform.log.debug(`RoomIndexMap:
22
+ `, roomIndexMap);
23
+ const deviceData = robot.device.data;
24
+ const state = state_to_matter_state(data.state);
25
+ if (state) {
26
+ robot.updateAttribute(RvcRunMode.Cluster.id, 'currentMode', getRunningMode(state), platform.log);
27
+ }
28
+ if (data.state === OperationStatusCode.Idle) {
29
+ const selectedAreas = platform.roborockService?.getSelectedAreas(duid) ?? [];
30
+ robot.updateAttribute(ServiceArea.Cluster.id, 'selectedAreas', selectedAreas, platform.log);
31
+ }
32
+ if (state === RvcRunMode.ModeTag.Cleaning && !data.cleaning_info) {
33
+ platform.log.debug('No cleaning_info, setting currentArea to null');
34
+ robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', null, platform.log);
35
+ robot.updateAttribute(ServiceArea.Cluster.id, 'selectedAreas', [], platform.log);
36
+ }
37
+ else {
38
+ const isMultipleMapEnable = platform.enableExperimentalFeature?.enableExperimentalFeature && platform.enableExperimentalFeature?.advancedFeature?.enableMultipleMap;
39
+ if (isMultipleMapEnable) {
40
+ await mapRoomsToAreasFeatureOn(platform, duid, data);
41
+ }
42
+ else {
43
+ await mapRoomsToAreasFeatureOff(platform, duid, data);
44
+ }
45
+ }
46
+ if (data.battery) {
47
+ const batteryLevel = data.battery;
48
+ robot.updateAttribute(PowerSource.Cluster.id, 'batPercentRemaining', batteryLevel * 2, platform.log);
49
+ robot.updateAttribute(PowerSource.Cluster.id, 'batChargeState', getBatteryState(data.state, data.battery), platform.log);
50
+ robot.updateAttribute(PowerSource.Cluster.id, 'batChargeLevel', getBatteryStatus(batteryLevel), platform.log);
51
+ }
52
+ const currentCleanModeSetting = {
53
+ suctionPower: data.cleaning_info?.fan_power ?? data.fan_power,
54
+ waterFlow: data.cleaning_info?.water_box_status ?? data.water_box_mode,
55
+ distance_off: data.distance_off,
56
+ mopRoute: data.cleaning_info?.mop_mode ?? data.mop_mode,
57
+ segment_id: data.cleaning_info?.segment_id,
58
+ target_segment_id: data.cleaning_info?.target_segment_id,
59
+ };
60
+ platform.log.debug(`data: ${debugStringify(data)}`);
61
+ platform.log.notice(`currentCleanModeSetting: ${debugStringify(currentCleanModeSetting)}`);
62
+ if (currentCleanModeSetting.mopRoute && currentCleanModeSetting.suctionPower && currentCleanModeSetting.waterFlow) {
63
+ const currentCleanMode = getCurrentCleanModeFunc(deviceData.model, platform.enableExperimentalFeature?.advancedFeature?.forceRunAtDefault ?? false)(currentCleanModeSetting);
64
+ platform.log.debug(`Current clean mode: ${currentCleanMode}`);
65
+ if (currentCleanMode) {
66
+ robot.updateAttribute(RvcCleanMode.Cluster.id, 'currentMode', currentCleanMode, platform.log);
67
+ }
68
+ }
69
+ processAdditionalProps(robot, data, duid, platform);
70
+ }
71
+ export function triggerDssError(robot, platform) {
72
+ const currentOperationState = robot.getAttribute(RvcOperationalState.Cluster.id, 'operationalState');
73
+ if (currentOperationState === RvcOperationalState.OperationalState.Error) {
74
+ return true;
75
+ }
76
+ if (currentOperationState === RvcOperationalState.OperationalState.Docked) {
77
+ robot.updateAttribute(RvcOperationalState.Cluster.id, 'operationalState', RvcOperationalState.OperationalState.Error, platform.log);
78
+ return true;
79
+ }
80
+ return false;
81
+ }
82
+ async function processAdditionalProps(robot, message, duid, platform) {
83
+ const dssStatus = getDssStatus(message, duid, platform);
84
+ if (dssStatus) {
85
+ triggerDssError(robot, platform);
86
+ }
87
+ }
88
+ function getDssStatus(message, duid, platform) {
89
+ const robot = platform.robots.get(duid);
90
+ if (robot === undefined) {
91
+ platform.log.error(`Error4: Robot with DUID ${duid} not found`);
92
+ return undefined;
93
+ }
94
+ if (platform.enableExperimentalFeature &&
95
+ platform.enableExperimentalFeature.enableExperimentalFeature &&
96
+ platform.enableExperimentalFeature.advancedFeature.includeDockStationStatus &&
97
+ message.dss !== undefined) {
98
+ const dss = parseDockingStationStatus(message.dss);
99
+ if (dss && robot) {
100
+ robot.dockStationStatus = dss;
101
+ }
102
+ if (dss && hasDockingStationError(dss)) {
103
+ return RvcOperationalState.OperationalState.Error;
104
+ }
105
+ }
106
+ return undefined;
107
+ }
108
+ async function mapRoomsToAreasFeatureOff(platform, duid, data) {
109
+ const currentMappedAreas = platform.roborockService?.getSupportedAreas(duid);
110
+ const robot = platform.robots.get(duid);
111
+ if (!robot) {
112
+ platform.log.error(`Robot with DUID ${duid} not found.`);
113
+ return;
114
+ }
115
+ if (!data.cleaning_info) {
116
+ return;
117
+ }
118
+ const source_segment_id = data.cleaning_info.segment_id ?? -1;
119
+ const source_target_segment_id = data.cleaning_info.target_segment_id ?? -1;
120
+ const segment_id = source_segment_id !== -1 ? source_segment_id : source_target_segment_id;
121
+ const mappedArea = currentMappedAreas?.find((x) => x.areaId == segment_id);
122
+ platform.log.debug(`mappedArea:
123
+ source_segment_id: ${source_segment_id},
124
+ source_target_segment_id: ${source_target_segment_id},
125
+ segment_id: ${segment_id},
126
+ result: ${mappedArea ? debugStringify(mappedArea) : 'undefined'}
127
+ `);
128
+ if (segment_id !== -1 && mappedArea) {
129
+ robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', segment_id, platform.log);
130
+ }
131
+ if (segment_id == -1) {
132
+ robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', null, platform.log);
133
+ }
134
+ }
135
+ async function mapRoomsToAreasFeatureOn(platform, duid, data) {
136
+ const robot = platform.robots.get(duid);
137
+ if (!robot) {
138
+ platform.log.error(`Robot with DUID ${duid} not found.`);
139
+ return;
140
+ }
141
+ if (!data.cleaning_info) {
142
+ return;
143
+ }
144
+ const currentMappedAreas = platform.roborockService?.getSupportedAreas(duid);
145
+ const roomIndexMap = platform.roborockService?.getSupportedAreasIndexMap(duid);
146
+ const source_segment_id = data.cleaning_info.segment_id ?? -1;
147
+ const source_target_segment_id = data.cleaning_info.target_segment_id ?? -1;
148
+ const segment_id = source_segment_id !== -1 ? source_segment_id : source_target_segment_id;
149
+ const areaId = roomIndexMap?.getAreaId(segment_id, 0);
150
+ if (!areaId) {
151
+ platform.log.debug(`
152
+ source_segment_id: ${source_segment_id},
153
+ source_target_segment_id: ${source_target_segment_id},
154
+ segment_id: ${segment_id},
155
+ areaId: ${areaId}`);
156
+ return;
157
+ }
158
+ const mappedArea = currentMappedAreas?.find((x) => x.areaId == areaId);
159
+ platform.log.debug(`mappedArea:
160
+ source_segment_id: ${source_segment_id},
161
+ source_target_segment_id: ${source_target_segment_id},
162
+ segment_id: ${segment_id},
163
+ areaId: ${areaId},
164
+ result: ${mappedArea ? debugStringify(mappedArea) : 'undefined'}
165
+ `);
166
+ if (areaId !== -1 && mappedArea) {
167
+ robot.updateAttribute(ServiceArea.Cluster.id, 'currentArea', areaId, platform.log);
168
+ }
169
+ }
@@ -0,0 +1,359 @@
1
+ import { MapInfo } from '../../roborockCommunication/index.js';
2
+ export const supportedAreas = [
3
+ { areaId: 100, mapId: 0, areaInfo: { locationInfo: { locationName: 'Kitchen', floorNumber: 0, areaType: null }, landmarkInfo: null } },
4
+ { areaId: 101, mapId: 0, areaInfo: { locationInfo: { locationName: 'Study', floorNumber: 0, areaType: null }, landmarkInfo: null } },
5
+ { areaId: 102, mapId: 0, areaInfo: { locationInfo: { locationName: 'Living room', floorNumber: 0, areaType: null }, landmarkInfo: null } },
6
+ { areaId: 103, mapId: 0, areaInfo: { locationInfo: { locationName: 'Bedroom', floorNumber: 0, areaType: null }, landmarkInfo: null } },
7
+ { areaId: 104, mapId: 1, areaInfo: { locationInfo: { locationName: 'Living room', floorNumber: 1, areaType: null }, landmarkInfo: null } },
8
+ { areaId: 105, mapId: 1, areaInfo: { locationInfo: { locationName: 'Guest bedroom', floorNumber: 1, areaType: null }, landmarkInfo: null } },
9
+ { areaId: 106, mapId: 1, areaInfo: { locationInfo: { locationName: 'Master bedroom', floorNumber: 1, areaType: null }, landmarkInfo: null } },
10
+ { areaId: 107, mapId: 1, areaInfo: { locationInfo: { locationName: 'Balcony', floorNumber: 1, areaType: null }, landmarkInfo: null } },
11
+ ];
12
+ export const supportedMaps = [
13
+ { mapId: 0, name: 'First Map' },
14
+ { mapId: 1, name: 'Second Map' },
15
+ ];
16
+ export const roomIndexMap = {
17
+ indexMap: new Map([
18
+ [100, { roomId: 1, mapId: 0 }],
19
+ [101, { roomId: 2, mapId: 0 }],
20
+ [102, { roomId: 3, mapId: 0 }],
21
+ [103, { roomId: 4, mapId: 0 }],
22
+ [104, { roomId: 1, mapId: 1 }],
23
+ [105, { roomId: 2, mapId: 1 }],
24
+ [106, { roomId: 3, mapId: 1 }],
25
+ [107, { roomId: 4, mapId: 1 }],
26
+ ]),
27
+ roomMap: new Map([
28
+ [1, 104],
29
+ [2, 105],
30
+ [3, 106],
31
+ [4, 107],
32
+ ]),
33
+ };
34
+ export const mapInfo = new MapInfo({
35
+ max_multi_map: 1,
36
+ max_bak_map: 1,
37
+ multi_map_count: 1,
38
+ map_info: [
39
+ {
40
+ mapFlag: 0,
41
+ add_time: 1753511673,
42
+ length: 9,
43
+ name: 'First Map',
44
+ bak_maps: [{ mapFlag: 4, add_time: 1753578164 }],
45
+ rooms: [
46
+ { id: 1, tag: 14, iot_name_id: '11100845', iot_name: 'Kitchen' },
47
+ { id: 2, tag: 9, iot_name_id: '11100849', iot_name: 'Study' },
48
+ {
49
+ id: 3,
50
+ tag: 6,
51
+ iot_name_id: '11100842',
52
+ iot_name: 'Living room',
53
+ },
54
+ { id: 4, tag: 1, iot_name_id: '11100847', iot_name: 'Bedroom' },
55
+ ],
56
+ },
57
+ {
58
+ mapFlag: 1,
59
+ add_time: 1753579596,
60
+ length: 10,
61
+ name: 'Second Map',
62
+ bak_maps: [{ mapFlag: 5, add_time: 1753578579 }],
63
+ rooms: [
64
+ {
65
+ id: 1,
66
+ tag: 6,
67
+ iot_name_id: '11100842',
68
+ iot_name: 'Living room',
69
+ },
70
+ {
71
+ id: 2,
72
+ tag: 3,
73
+ iot_name_id: '12461114',
74
+ iot_name: 'Guest bedroom',
75
+ },
76
+ {
77
+ id: 3,
78
+ tag: 2,
79
+ iot_name_id: '12461109',
80
+ iot_name: 'Master bedroom',
81
+ },
82
+ { id: 4, tag: 7, iot_name_id: '12461111', iot_name: 'Balcony' },
83
+ ],
84
+ },
85
+ ],
86
+ });
87
+ export const roomData = [
88
+ [1, '11100845', 14],
89
+ [2, '11100849', 9],
90
+ [3, '11100842', 6],
91
+ [4, '11100847', 1],
92
+ ];
93
+ export const cloudMessageResult1 = {
94
+ msg_ver: 2,
95
+ msg_seq: 424,
96
+ state: 5,
97
+ battery: 100,
98
+ clean_time: 2823,
99
+ clean_area: 36002500,
100
+ error_code: 0,
101
+ map_present: 1,
102
+ in_cleaning: 0,
103
+ in_returning: 0,
104
+ in_fresh_state: 1,
105
+ lab_status: 3,
106
+ water_box_status: 1,
107
+ back_type: -1,
108
+ wash_phase: 0,
109
+ wash_ready: 1,
110
+ wash_status: 0,
111
+ fan_power: 110,
112
+ dnd_enabled: 0,
113
+ map_status: 3,
114
+ is_locating: 0,
115
+ lock_status: 0,
116
+ water_box_mode: 209,
117
+ distance_off: 155,
118
+ water_box_carriage_status: 1,
119
+ mop_forbidden_enable: 1,
120
+ camera_status: 1,
121
+ is_exploring: 0,
122
+ adbumper_status: [0, 0, 0],
123
+ water_shortage_status: 0,
124
+ dock_type: 14,
125
+ dust_collection_status: 0,
126
+ auto_dust_collection: 1,
127
+ avoid_count: 209,
128
+ mop_mode: 306,
129
+ debug_mode: 0,
130
+ in_warmup: 0,
131
+ collision_avoid_status: 1,
132
+ switch_map_mode: 1,
133
+ dock_error_status: 0,
134
+ charge_status: 1,
135
+ unsave_map_reason: 0,
136
+ unsave_map_flag: -1,
137
+ dry_status: 0,
138
+ rdt: 0,
139
+ clean_percent: 0,
140
+ extra_time: 860,
141
+ rss: 2,
142
+ dss: 168,
143
+ common_status: 2,
144
+ last_clean_t: 1754063701,
145
+ replenish_mode: 0,
146
+ repeat: 1,
147
+ kct: 0,
148
+ subdivision_sets: 0,
149
+ cleaning_info: { target_segment_id: -1, segment_id: 3, fan_power: 102, water_box_status: 202, mop_mode: 306 },
150
+ exit_dock: 0,
151
+ seq_type: 0,
152
+ };
153
+ export const cloudMessageResult2 = {
154
+ msg_ver: 2,
155
+ msg_seq: 424,
156
+ state: 5,
157
+ battery: 100,
158
+ clean_time: 2823,
159
+ clean_area: 36002500,
160
+ error_code: 0,
161
+ map_present: 1,
162
+ in_cleaning: 0,
163
+ in_returning: 0,
164
+ in_fresh_state: 1,
165
+ lab_status: 3,
166
+ water_box_status: 1,
167
+ back_type: -1,
168
+ wash_phase: 0,
169
+ wash_ready: 1,
170
+ wash_status: 0,
171
+ fan_power: 110,
172
+ dnd_enabled: 0,
173
+ map_status: 3,
174
+ is_locating: 0,
175
+ lock_status: 0,
176
+ water_box_mode: 209,
177
+ distance_off: 155,
178
+ water_box_carriage_status: 1,
179
+ mop_forbidden_enable: 1,
180
+ camera_status: 1,
181
+ is_exploring: 0,
182
+ adbumper_status: [0, 0, 0],
183
+ water_shortage_status: 0,
184
+ dock_type: 14,
185
+ dust_collection_status: 0,
186
+ auto_dust_collection: 1,
187
+ avoid_count: 209,
188
+ mop_mode: 306,
189
+ debug_mode: 0,
190
+ in_warmup: 0,
191
+ collision_avoid_status: 1,
192
+ switch_map_mode: 1,
193
+ dock_error_status: 0,
194
+ charge_status: 1,
195
+ unsave_map_reason: 0,
196
+ unsave_map_flag: -1,
197
+ dry_status: 0,
198
+ rdt: 0,
199
+ clean_percent: 0,
200
+ extra_time: 860,
201
+ rss: 2,
202
+ dss: 168,
203
+ common_status: 2,
204
+ last_clean_t: 1754063701,
205
+ replenish_mode: 0,
206
+ repeat: 1,
207
+ kct: 0,
208
+ subdivision_sets: 0,
209
+ cleaning_info: { target_segment_id: 4, segment_id: -1, fan_power: 102, water_box_status: 202, mop_mode: 306 },
210
+ exit_dock: 0,
211
+ seq_type: 0,
212
+ };
213
+ export const cloudMessageResult3 = {
214
+ msg_ver: 2,
215
+ msg_seq: 1579,
216
+ state: 5,
217
+ battery: 94,
218
+ clean_time: 567,
219
+ clean_area: 36002500,
220
+ error_code: 0,
221
+ map_present: 1,
222
+ in_cleaning: 0,
223
+ in_returning: 0,
224
+ in_fresh_state: 1,
225
+ lab_status: 3,
226
+ water_box_status: 1,
227
+ fan_power: 104,
228
+ dnd_enabled: 0,
229
+ map_status: 3,
230
+ is_locating: 0,
231
+ lock_status: 0,
232
+ water_box_mode: 202,
233
+ distance_off: 60,
234
+ water_box_carriage_status: 0,
235
+ mop_forbidden_enable: 0,
236
+ adbumper_status: [0, 0, 0],
237
+ dock_type: 5,
238
+ dust_collection_status: 0,
239
+ auto_dust_collection: 1,
240
+ debug_mode: 0,
241
+ switch_map_mode: 0,
242
+ dock_error_status: 0,
243
+ charge_status: 1,
244
+ };
245
+ export const homeData = {
246
+ id: 3645093,
247
+ name: 'My Home',
248
+ products: [
249
+ {
250
+ id: '2CjvhDFL7Q9NdJQmhE86zn',
251
+ name: 'Roborock Qrevo Edge Series',
252
+ model: 'test-model',
253
+ category: 'robot.vacuum.cleaner',
254
+ schema: [
255
+ { id: 101, name: 'rpc_request', code: 'rpc_request', mode: 'rw', type: 'RAW', property: null },
256
+ { id: 102, name: 'rpc_response', code: 'rpc_response', mode: 'rw', type: 'RAW', property: null },
257
+ { id: 120, name: '错误代码', code: 'error_code', mode: 'ro', type: 'ENUM', property: '{"range": [""]}' },
258
+ { id: 121, name: '设备状态', code: 'state', mode: 'ro', type: 'ENUM', property: '{"range": [""]}' },
259
+ { id: 122, name: '设备电量', code: 'battery', mode: 'ro', type: 'ENUM', property: '{"range": [""]}' },
260
+ { id: 123, name: '清扫模式', code: 'fan_power', mode: 'rw', type: 'ENUM', property: '{"range": [""]}' },
261
+ { id: 124, name: '拖地模式', code: 'water_box_mode', mode: 'rw', type: 'ENUM', property: '{"range": [""]}' },
262
+ { id: 125, name: '主刷寿命', code: 'main_brush_life', mode: 'rw', type: 'VALUE', property: '{"max": 100, "min": 0, "step": 1, "unit": "null", "scale": 1}' },
263
+ { id: 126, name: '边刷寿命', code: 'side_brush_life', mode: 'rw', type: 'VALUE', property: '{"max": 100, "min": 0, "step": 1, "unit": "null", "scale": 1}' },
264
+ { id: 127, name: '滤网寿命', code: 'filter_life', mode: 'rw', type: 'VALUE', property: '{"max": 100, "min": 0, "step": 1, "unit": "null", "scale": 1}' },
265
+ { id: 128, name: '额外状态', code: 'additional_props', mode: 'ro', type: 'RAW', property: null },
266
+ { id: 130, name: '完成事件', code: 'task_complete', mode: 'ro', type: 'RAW', property: null },
267
+ { id: 131, name: '电量不足任务取消', code: 'task_cancel_low_power', mode: 'ro', type: 'RAW', property: null },
268
+ { id: 132, name: '运动中任务取消', code: 'task_cancel_in_motion', mode: 'ro', type: 'RAW', property: null },
269
+ { id: 133, name: '充电状态', code: 'charge_status', mode: 'ro', type: 'RAW', property: null },
270
+ { id: 134, name: '烘干状态', code: 'drying_status', mode: 'ro', type: 'RAW', property: null },
271
+ { id: 135, name: '离线原因细分', code: 'offline_status', mode: 'ro', type: 'RAW', property: null },
272
+ { id: 139, name: '回基站目的', code: 'back_type', mode: 'ro', type: 'RAW', property: null },
273
+ ],
274
+ },
275
+ ],
276
+ devices: [
277
+ {
278
+ duid: 'test-duid',
279
+ name: 'Roborock Qrevo Edge 5V1',
280
+ activeTime: 1749443275,
281
+ createTime: 1746940587,
282
+ localKey: 'v0OKpWXwBmiCk4ku',
283
+ productId: '2CjvhDFL7Q9NdJQmhE86zn',
284
+ online: true,
285
+ fv: '02.28.34',
286
+ pv: '1.0',
287
+ sn: 'RCIEBS50900224',
288
+ featureSet: '2247397454282751',
289
+ newFeatureSet: '00040040282834C9C2FA8F5C7EDEFFFE',
290
+ deviceStatus: { 120: 0, 121: 8, 122: 100, 123: 110, 124: 209, 125: 93, 126: 69, 127: 86, 128: 0, 133: 1, 134: 0, 135: 0, 139: 0 },
291
+ silentOtaSwitch: true,
292
+ rrHomeId: 3645093,
293
+ rooms: [
294
+ { id: 11100849, name: 'Study' },
295
+ { id: 11100847, name: 'Bedroom' },
296
+ { id: 11100845, name: 'Kitchen' },
297
+ { id: 11100842, name: 'Living room' },
298
+ ],
299
+ serialNumber: 'RCIEBS50900224',
300
+ data: {
301
+ id: 'test-duid',
302
+ firmwareVersion: '02.28.34',
303
+ serialNumber: 'RCIEBS50900224',
304
+ model: 'test-model',
305
+ category: 'robot.vacuum.cleaner',
306
+ batteryLevel: 100,
307
+ },
308
+ store: {
309
+ userData: {
310
+ uid: 3635748,
311
+ tokentype: '',
312
+ token: 'rr65af7107da5840:txP8ZF7dj8v7xUMkoFMzZA==:01981b12f83a7723a1cbef8c8e89a7e1',
313
+ rruid: 'rr65af7107da5840',
314
+ region: 'us',
315
+ countrycode: '84',
316
+ country: 'VN',
317
+ nickname: 'Ryan',
318
+ rriot: {
319
+ u: '6BtaRwE14spvanEazqX0kQ',
320
+ s: 'OsErWk',
321
+ h: '195Xn4u3fe',
322
+ k: 'ofKw7nJc',
323
+ r: { r: 'US', a: 'https://api-us.roborock.com', m: 'ssl://mqtt-us-2.roborock.com:8883', l: 'https://wood-us.roborock.com' },
324
+ },
325
+ },
326
+ localKey: 'v0OKpWXwBmiCk4ku',
327
+ pv: '1.0',
328
+ model: 'test-model',
329
+ },
330
+ schema: [
331
+ { id: 101, name: 'rpc_request', code: 'rpc_request', mode: 'rw', type: 'RAW', property: null },
332
+ { id: 102, name: 'rpc_response', code: 'rpc_response', mode: 'rw', type: 'RAW', property: null },
333
+ { id: 120, name: '错误代码', code: 'error_code', mode: 'ro', type: 'ENUM', property: '{"range": [""]}' },
334
+ { id: 121, name: '设备状态', code: 'state', mode: 'ro', type: 'ENUM', property: '{"range": [""]}' },
335
+ { id: 122, name: '设备电量', code: 'battery', mode: 'ro', type: 'ENUM', property: '{"range": [""]}' },
336
+ { id: 123, name: '清扫模式', code: 'fan_power', mode: 'rw', type: 'ENUM', property: '{"range": [""]}' },
337
+ { id: 124, name: '拖地模式', code: 'water_box_mode', mode: 'rw', type: 'ENUM', property: '{"range": [""]}' },
338
+ { id: 125, name: '主刷寿命', code: 'main_brush_life', mode: 'rw', type: 'VALUE', property: '{"max": 100, "min": 0, "step": 1, "unit": "null", "scale": 1}' },
339
+ { id: 126, name: '边刷寿命', code: 'side_brush_life', mode: 'rw', type: 'VALUE', property: '{"max": 100, "min": 0, "step": 1, "unit": "null", "scale": 1}' },
340
+ { id: 127, name: '滤网寿命', code: 'filter_life', mode: 'rw', type: 'VALUE', property: '{"max": 100, "min": 0, "step": 1, "unit": "null", "scale": 1}' },
341
+ { id: 128, name: '额外状态', code: 'additional_props', mode: 'ro', type: 'RAW', property: null },
342
+ { id: 130, name: '完成事件', code: 'task_complete', mode: 'ro', type: 'RAW', property: null },
343
+ { id: 131, name: '电量不足任务取消', code: 'task_cancel_low_power', mode: 'ro', type: 'RAW', property: null },
344
+ { id: 132, name: '运动中任务取消', code: 'task_cancel_in_motion', mode: 'ro', type: 'RAW', property: null },
345
+ { id: 133, name: '充电状态', code: 'charge_status', mode: 'ro', type: 'RAW', property: null },
346
+ { id: 134, name: '烘干状态', code: 'drying_status', mode: 'ro', type: 'RAW', property: null },
347
+ { id: 135, name: '离线原因细分', code: 'offline_status', mode: 'ro', type: 'RAW', property: null },
348
+ { id: 139, name: '回基站目的', code: 'back_type', mode: 'ro', type: 'RAW', property: null },
349
+ ],
350
+ },
351
+ ],
352
+ receivedDevices: [],
353
+ rooms: [
354
+ { id: 11100849, name: 'Study' },
355
+ { id: 11100847, name: 'Bedroom' },
356
+ { id: 11100845, name: 'Kitchen' },
357
+ { id: 11100842, name: 'Living room' },
358
+ ],
359
+ };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "matterbridge-roborock-vacuum-plugin",
3
3
  "type": "DynamicPlatform",
4
- "version": "1.1.0-rc17",
4
+ "version": "1.1.1-rc01",
5
5
  "whiteList": [],
6
6
  "blackList": [],
7
7
  "useInterval": true,
@@ -38,4 +38,4 @@
38
38
  "debug": true,
39
39
  "unregisterOnShutdown": false,
40
40
  "enableExperimentalFeature": false
41
- }
41
+ }
@@ -1,11 +1,8 @@
1
1
  {
2
2
  "title": "Matterbridge Roborock Vacuum Plugin",
3
- "description": "matterbridge-roborock-vacuum-plugin v. 1.1.0-rc17 by https://github.com/RinDevJunior",
3
+ "description": "matterbridge-roborock-vacuum-plugin v. 1.1.1-rc01 by https://github.com/RinDevJunior",
4
4
  "type": "object",
5
- "required": [
6
- "username",
7
- "password"
8
- ],
5
+ "required": ["username", "password"],
9
6
  "properties": {
10
7
  "name": {
11
8
  "description": "Plugin name",
@@ -60,9 +57,7 @@
60
57
  "const": true
61
58
  }
62
59
  },
63
- "required": [
64
- "enableExperimentalFeature"
65
- ]
60
+ "required": ["enableExperimentalFeature"]
66
61
  },
67
62
  "then": {
68
63
  "properties": {
@@ -124,9 +119,7 @@
124
119
  "const": true
125
120
  }
126
121
  },
127
- "required": [
128
- "enableCleanModeMapping"
129
- ]
122
+ "required": ["enableCleanModeMapping"]
130
123
  },
131
124
  "then": {
132
125
  "properties": {
@@ -171,9 +164,7 @@
171
164
  "default": 25
172
165
  }
173
166
  },
174
- "required": [
175
- "distanceOff"
176
- ]
167
+ "required": ["distanceOff"]
177
168
  }
178
169
  }
179
170
  ]
@@ -210,9 +201,7 @@
210
201
  "default": 25
211
202
  }
212
203
  },
213
- "required": [
214
- "distanceOff"
215
- ]
204
+ "required": ["distanceOff"]
216
205
  }
217
206
  }
218
207
  ]
@@ -242,36 +231,20 @@
242
231
  "fanMode": {
243
232
  "type": "string",
244
233
  "description": "Suction power mode to use (e.g., 'Quiet', 'Balanced', 'Turbo', 'Max', 'MaxPlus').",
245
- "enum": [
246
- "Quiet",
247
- "Balanced",
248
- "Turbo",
249
- "Max",
250
- "MaxPlus"
251
- ],
234
+ "enum": ["Quiet", "Balanced", "Turbo", "Max", "MaxPlus"],
252
235
  "default": "Balanced"
253
236
  },
254
237
  "waterFlowMode": {
255
238
  "type": "string",
256
239
  "description": "Water flow mode to use (e.g., 'Low', 'Medium', 'High', 'CustomizeWithDistanceOff').",
257
- "enum": [
258
- "Low",
259
- "Medium",
260
- "High",
261
- "CustomizeWithDistanceOff"
262
- ],
240
+ "enum": ["Low", "Medium", "High", "CustomizeWithDistanceOff"],
263
241
  "default": "Medium"
264
242
  },
265
243
  "mopRouteMode": {
266
244
  "type": "string",
267
245
  "description": "Mop route intensity to use (e.g., 'Standard', 'Deep', 'DeepPlus', 'Fast').",
268
- "enum": [
269
- "Standard",
270
- "Deep",
271
- "DeepPlus",
272
- "Fast"
273
- ],
246
+ "enum": ["Standard", "Deep", "DeepPlus", "Fast"],
274
247
  "default": "Standard"
275
248
  }
276
249
  }
277
- }
250
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge-roborock-vacuum-plugin",
3
- "version": "1.1.0-rc17",
3
+ "version": "1.1.1-rc01",
4
4
  "description": "Matterbridge Roborock Vacuum Plugin",
5
5
  "author": "https://github.com/RinDevJunior",
6
6
  "license": "MIT",
@@ -31,7 +31,7 @@
31
31
  "apple home"
32
32
  ],
33
33
  "engines": {
34
- "node": ">=18.0.0 <19.0.0 || >=20.0.0 <21.0.0 || >=22.0.0"
34
+ "node": ">=22.0.0"
35
35
  },
36
36
  "dependencies": {
37
37
  "@log4js-node/log4js-api": "^1.0.2",
@@ -1,6 +1,6 @@
1
1
  import { CleanSetting, MopRoute, MopWaterFlow, VacuumSuctionPower } from './default.js';
2
2
 
3
- export function getCurrentCleanModeDefault(setting: { suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number }): number | undefined {
3
+ export function getCurrentCleanModeDefault(setting: { suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number | undefined }): number | undefined {
4
4
  if (!setting || typeof setting !== 'object') {
5
5
  return undefined;
6
6
  }
@@ -1,7 +1,7 @@
1
1
  import { getCurrentCleanModeDefault } from '../default/runtimes.js';
2
2
  import { MopRouteSmart, MopWaterFlowSmart, VacuumSuctionPowerSmart } from './smart.js';
3
3
 
4
- export function getCurrentCleanModeSmart(setting: { suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number }): number | undefined {
4
+ export function getCurrentCleanModeSmart(setting: { suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number | undefined }): number | undefined {
5
5
  if (!setting || typeof setting !== 'object') {
6
6
  return undefined;
7
7
  }