matterbridge-roborock-vacuum-plugin 1.1.1-rc06 → 1.1.1-rc08
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/model/roomIndexMap.js +2 -2
- package/dist/platform.js +2 -2
- package/dist/roborockService.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/behaviors/roborock.vacuum/default/default.ts +9 -5
- package/src/behaviors/roborock.vacuum/default/runtimes.ts +2 -2
- package/src/behaviors/roborock.vacuum/smart/runtimes.ts +2 -1
- package/src/behaviors/roborock.vacuum/smart/smart.ts +2 -2
- package/src/initialData/getSupportedAreas.ts +25 -13
- package/src/model/CloudMessageModel.ts +6 -8
- package/src/model/ExperimentalFeatureSetting.ts +32 -24
- package/src/model/roomIndexMap.ts +6 -4
- package/src/platform.ts +2 -2
- package/src/roborockCommunication/Zmodel/batteryMessage.ts +3 -1
- package/src/roborockCommunication/Zmodel/device.ts +18 -22
- package/src/roborockCommunication/Zmodel/map.ts +6 -1
- package/src/roborockCommunication/Zmodel/messageResult.ts +9 -7
- package/src/roborockCommunication/Zmodel/roomInfo.ts +6 -1
- package/src/roborockCommunication/Zmodel/scene.ts +6 -4
- package/src/roborockCommunication/Zmodel/userData.ts +8 -6
- package/src/roborockCommunication/broadcast/messageProcessor.ts +3 -2
- package/src/roborockCommunication/broadcast/model/dps.ts +6 -4
- package/src/roborockCommunication/broadcast/model/messageContext.ts +7 -1
- package/src/roborockCommunication/helper/messageSerializer.ts +6 -1
- package/src/roborockService.ts +14 -8
- package/src/rvc.ts +5 -1
- package/src/share/runtimeHelper.ts +2 -1
- package/src/tests/runtimes/handleHomeDataMessage.test.ts +2 -1
- package/src/tests/runtimes/handleLocalMessage.test.ts +6 -1
|
@@ -4,8 +4,8 @@ export class RoomIndexMap {
|
|
|
4
4
|
constructor(roomMap) {
|
|
5
5
|
this.indexMap = roomMap;
|
|
6
6
|
this.roomMap = new Map();
|
|
7
|
-
for (const [areaId,
|
|
8
|
-
this.roomMap.set(`${roomId}:${mapId}`, areaId);
|
|
7
|
+
for (const [areaId, r] of roomMap.entries()) {
|
|
8
|
+
this.roomMap.set(`${r.roomId}:${r.mapId}`, areaId);
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
getAreaId(roomId, mapId) {
|
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.3.
|
|
30
|
-
throw new Error(`This plugin requires Matterbridge version >= "3.3.
|
|
29
|
+
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.3.6')) {
|
|
30
|
+
throw new Error(`This plugin requires Matterbridge version >= "3.3.6". 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)
|
package/dist/roborockService.js
CHANGED
|
@@ -97,7 +97,7 @@ export default class RoborockService {
|
|
|
97
97
|
}
|
|
98
98
|
async changeCleanMode(duid, { suctionPower, waterFlow, distance_off, mopRoute }) {
|
|
99
99
|
this.logger.notice('RoborockService - changeCleanMode');
|
|
100
|
-
return this.getMessageProcessor(duid)?.changeCleanMode(duid, suctionPower, waterFlow, mopRoute, distance_off);
|
|
100
|
+
return this.getMessageProcessor(duid)?.changeCleanMode(duid, suctionPower, waterFlow, mopRoute ?? 0, distance_off);
|
|
101
101
|
}
|
|
102
102
|
async startClean(duid) {
|
|
103
103
|
const supportedRooms = this.supportedAreas.get(duid) ?? [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "Matterbridge Roborock Vacuum Plugin",
|
|
3
|
-
"description": "matterbridge-roborock-vacuum-plugin v. 1.1.1-
|
|
3
|
+
"description": "matterbridge-roborock-vacuum-plugin v. 1.1.1-rc08 by https://github.com/RinDevJunior",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"required": ["username", "password"],
|
|
6
6
|
"properties": {
|
package/package.json
CHANGED
|
@@ -79,7 +79,14 @@ export const RvcCleanMode: Record<number, string> = {
|
|
|
79
79
|
[99]: 'Go Vacation',
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
export
|
|
82
|
+
export interface CleanModeSetting {
|
|
83
|
+
suctionPower: number;
|
|
84
|
+
waterFlow: number;
|
|
85
|
+
distance_off: number;
|
|
86
|
+
mopRoute: number | undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const CleanSetting: Record<number, CleanModeSetting> = {
|
|
83
90
|
[5]: { suctionPower: VacuumSuctionPower.Balanced, waterFlow: MopWaterFlow.Medium, distance_off: 0, mopRoute: MopRoute.Standard }, // 'Vac & Mop Default'
|
|
84
91
|
[6]: { suctionPower: VacuumSuctionPower.Balanced, waterFlow: MopWaterFlow.Medium, distance_off: 0, mopRoute: MopRoute.Fast }, // 'Vac & Mop Quick'
|
|
85
92
|
|
|
@@ -192,10 +199,7 @@ export function setDefaultCommandHandler(
|
|
|
192
199
|
});
|
|
193
200
|
}
|
|
194
201
|
|
|
195
|
-
export const getSettingFromCleanMode = (
|
|
196
|
-
activity: string,
|
|
197
|
-
cleanModeSettings?: CleanModeSettings,
|
|
198
|
-
): { suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number } | undefined => {
|
|
202
|
+
export const getSettingFromCleanMode = (activity: string, cleanModeSettings?: CleanModeSettings): CleanModeSetting | undefined => {
|
|
199
203
|
switch (activity) {
|
|
200
204
|
case 'Mop: Default': {
|
|
201
205
|
const mopSetting = cleanModeSettings?.mopping;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CleanSetting, MopRoute, MopWaterFlow, VacuumSuctionPower } from './default.js';
|
|
1
|
+
import { CleanModeSetting, CleanSetting, MopRoute, MopWaterFlow, VacuumSuctionPower } from './default.js';
|
|
2
2
|
|
|
3
|
-
export function getCurrentCleanModeDefault(setting:
|
|
3
|
+
export function getCurrentCleanModeDefault(setting: CleanModeSetting): number | undefined {
|
|
4
4
|
if (!setting || typeof setting !== 'object') {
|
|
5
5
|
return undefined;
|
|
6
6
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { CleanModeSetting } from '../default/default.js';
|
|
1
2
|
import { getCurrentCleanModeDefault } from '../default/runtimes.js';
|
|
2
3
|
import { MopRouteSmart, MopWaterFlowSmart, VacuumSuctionPowerSmart } from './smart.js';
|
|
3
4
|
|
|
4
|
-
export function getCurrentCleanModeSmart(setting:
|
|
5
|
+
export function getCurrentCleanModeSmart(setting: CleanModeSetting): number | undefined {
|
|
5
6
|
if (!setting || typeof setting !== 'object') {
|
|
6
7
|
return undefined;
|
|
7
8
|
}
|
|
@@ -3,7 +3,7 @@ import { AnsiLogger, debugStringify } from 'matterbridge/logger';
|
|
|
3
3
|
import { BehaviorDeviceGeneric, BehaviorRoborock, DeviceCommands } from '../../BehaviorDeviceGeneric.js';
|
|
4
4
|
import RoborockService from '../../../roborockService.js';
|
|
5
5
|
import { CleanModeSettings } from '../../../model/ExperimentalFeatureSetting.js';
|
|
6
|
-
import { RvcCleanMode as DefaultRvcCleanMode, CleanSetting as DefaultCleanSetting, getSettingFromCleanMode, RvcRunMode } from '../default/default.js';
|
|
6
|
+
import { RvcCleanMode as DefaultRvcCleanMode, CleanSetting as DefaultCleanSetting, getSettingFromCleanMode, RvcRunMode, CleanModeSetting } from '../default/default.js';
|
|
7
7
|
|
|
8
8
|
export interface EndpointCommandsSmart extends DeviceCommands {
|
|
9
9
|
selectAreas: (newAreas: number[] | undefined) => MaybePromise;
|
|
@@ -61,7 +61,7 @@ export const RvcCleanMode: Record<number, string> = {
|
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
// { suctionPower: [ 102 ], waterFlow: 200, distance_off: 0, mopRoute: [ 102 ] }
|
|
64
|
-
export const CleanSetting: Record<number,
|
|
64
|
+
export const CleanSetting: Record<number, CleanModeSetting> = {
|
|
65
65
|
[4]: { suctionPower: 0, waterFlow: 0, distance_off: 0, mopRoute: MopRouteSmart.Smart }, // 'Smart Plan'
|
|
66
66
|
...DefaultCleanSetting,
|
|
67
67
|
};
|
|
@@ -5,12 +5,13 @@ import { Room } from '../roborockCommunication/Zmodel/room.js';
|
|
|
5
5
|
import { randomInt } from 'node:crypto';
|
|
6
6
|
import { RoomIndexMap } from '../model/roomIndexMap.js';
|
|
7
7
|
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
export interface SupportedAreasResult {
|
|
9
|
+
supportedAreas: ServiceArea.Area[];
|
|
10
|
+
supportedMaps: ServiceArea.Map[];
|
|
11
|
+
roomIndexMap: RoomIndexMap;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getSupportedAreas(vacuumRooms: Room[], roomMap: RoomMap | undefined, enableMultipleMap = false, log?: AnsiLogger): SupportedAreasResult {
|
|
14
15
|
log?.debug('getSupportedAreas-vacuum room', debugStringify(vacuumRooms));
|
|
15
16
|
log?.debug('getSupportedAreas-roomMap', roomMap ? debugStringify(roomMap) : 'undefined');
|
|
16
17
|
|
|
@@ -80,9 +81,14 @@ export function getSupportedAreas(
|
|
|
80
81
|
};
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
interface SupportedArea {
|
|
85
|
+
areaId: number;
|
|
86
|
+
mapId: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
83
89
|
function findDuplicatedAreaIds(areas: ServiceArea.Area[], log?: AnsiLogger): boolean {
|
|
84
90
|
const seen = new Set<string>();
|
|
85
|
-
const duplicates:
|
|
91
|
+
const duplicates: SupportedArea[] = [];
|
|
86
92
|
|
|
87
93
|
for (const area of areas) {
|
|
88
94
|
const key = `${area.areaId}=${area.mapId}`;
|
|
@@ -101,12 +107,18 @@ function findDuplicatedAreaIds(areas: ServiceArea.Area[], log?: AnsiLogger): boo
|
|
|
101
107
|
return duplicates.length > 0;
|
|
102
108
|
}
|
|
103
109
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
export interface MapInfo {
|
|
111
|
+
roomId: number;
|
|
112
|
+
mapId: number | null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface ProcessedData {
|
|
116
|
+
supportedAreas: ServiceArea.Area[];
|
|
117
|
+
indexMap: Map<number, MapInfo>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function processValidData(enableMultipleMap: boolean, vacuumRooms: Room[], roomMap?: RoomMap): ProcessedData {
|
|
121
|
+
const indexMap = new Map<number, MapInfo>();
|
|
110
122
|
const supportedAreas: ServiceArea.Area[] =
|
|
111
123
|
roomMap?.rooms !== undefined && roomMap.rooms.length > 0
|
|
112
124
|
? roomMap.rooms.map((room, index) => {
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { CloudMessageResult } from '../roborockCommunication/Zmodel/messageResult.js';
|
|
2
2
|
|
|
3
|
+
interface CloudMessageDpsEntry {
|
|
4
|
+
id: number;
|
|
5
|
+
result: CloudMessageResult[];
|
|
6
|
+
}
|
|
7
|
+
|
|
3
8
|
export interface CloudMessageModel {
|
|
4
9
|
duid: string;
|
|
5
|
-
dps: Record<
|
|
6
|
-
string,
|
|
7
|
-
| number
|
|
8
|
-
| {
|
|
9
|
-
id: number;
|
|
10
|
-
result: CloudMessageResult[];
|
|
11
|
-
}
|
|
12
|
-
>;
|
|
10
|
+
dps: Record<string, number | CloudMessageDpsEntry>;
|
|
13
11
|
}
|
|
@@ -1,34 +1,42 @@
|
|
|
1
|
+
export interface AdvancedFeature {
|
|
2
|
+
showRoutinesAsRoom: boolean;
|
|
3
|
+
includeDockStationStatus: boolean;
|
|
4
|
+
forceRunAtDefault: boolean;
|
|
5
|
+
useVacationModeToSendVacuumToDock: boolean;
|
|
6
|
+
enableServerMode: boolean;
|
|
7
|
+
alwaysExecuteAuthentication: boolean;
|
|
8
|
+
enableMultipleMap: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
1
11
|
export interface ExperimentalFeatureSetting {
|
|
2
12
|
enableExperimentalFeature: boolean;
|
|
3
|
-
advancedFeature:
|
|
4
|
-
showRoutinesAsRoom: boolean;
|
|
5
|
-
includeDockStationStatus: boolean;
|
|
6
|
-
forceRunAtDefault: boolean;
|
|
7
|
-
useVacationModeToSendVacuumToDock: boolean;
|
|
8
|
-
enableServerMode: boolean;
|
|
9
|
-
alwaysExecuteAuthentication: boolean;
|
|
10
|
-
enableMultipleMap: boolean;
|
|
11
|
-
};
|
|
13
|
+
advancedFeature: AdvancedFeature;
|
|
12
14
|
cleanModeSettings: CleanModeSettings;
|
|
13
15
|
}
|
|
14
16
|
|
|
17
|
+
interface VacuumingCleanModeSetting {
|
|
18
|
+
fanMode: 'Balanced' | string;
|
|
19
|
+
mopRouteMode: 'Standard' | string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface MoppingCleanModeSetting {
|
|
23
|
+
waterFlowMode: 'Medium' | string;
|
|
24
|
+
mopRouteMode: 'Standard' | string;
|
|
25
|
+
distanceOff?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface VacMopCleanModeSetting {
|
|
29
|
+
fanMode: 'Balanced' | string;
|
|
30
|
+
waterFlowMode: 'Medium' | string;
|
|
31
|
+
mopRouteMode: 'Standard' | string;
|
|
32
|
+
distanceOff?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
15
35
|
export interface CleanModeSettings {
|
|
16
36
|
enableCleanModeMapping: boolean;
|
|
17
|
-
vacuuming?:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
21
|
-
mopping?: {
|
|
22
|
-
waterFlowMode: 'Medium' | string;
|
|
23
|
-
mopRouteMode: 'Standard' | string;
|
|
24
|
-
distanceOff?: number;
|
|
25
|
-
};
|
|
26
|
-
vacmop?: {
|
|
27
|
-
fanMode: 'Balanced' | string;
|
|
28
|
-
waterFlowMode: 'Medium' | string;
|
|
29
|
-
mopRouteMode: 'Standard' | string;
|
|
30
|
-
distanceOff?: number;
|
|
31
|
-
};
|
|
37
|
+
vacuuming?: VacuumingCleanModeSetting;
|
|
38
|
+
mopping?: MoppingCleanModeSetting;
|
|
39
|
+
vacmop?: VacMopCleanModeSetting;
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
export function createDefaultExperimentalFeatureSetting(): ExperimentalFeatureSetting {
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { MapInfo } from '../initialData/getSupportedAreas.js';
|
|
2
|
+
|
|
1
3
|
export class RoomIndexMap {
|
|
2
|
-
public indexMap: Map<number,
|
|
4
|
+
public indexMap: Map<number, MapInfo>;
|
|
3
5
|
public roomMap: Map<string, number>;
|
|
4
6
|
|
|
5
|
-
constructor(roomMap: Map<number,
|
|
7
|
+
constructor(roomMap: Map<number, MapInfo>) {
|
|
6
8
|
this.indexMap = roomMap;
|
|
7
9
|
this.roomMap = new Map();
|
|
8
|
-
for (const [areaId,
|
|
9
|
-
this.roomMap.set(`${roomId}:${mapId}`, areaId);
|
|
10
|
+
for (const [areaId, r] of roomMap.entries()) {
|
|
11
|
+
this.roomMap.set(`${r.roomId}:${r.mapId}`, areaId);
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
|
package/src/platform.ts
CHANGED
|
@@ -33,9 +33,9 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
33
33
|
super(matterbridge, log, config);
|
|
34
34
|
|
|
35
35
|
// Verify that Matterbridge is the correct version
|
|
36
|
-
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.3.
|
|
36
|
+
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.3.6')) {
|
|
37
37
|
throw new Error(
|
|
38
|
-
`This plugin requires Matterbridge version >= "3.3.
|
|
38
|
+
`This plugin requires Matterbridge version >= "3.3.6". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`,
|
|
39
39
|
);
|
|
40
40
|
}
|
|
41
41
|
this.log.info('Initializing platform:', this.config.name);
|
|
@@ -11,4 +11,6 @@ export interface DeviceErrorMessage {
|
|
|
11
11
|
errorCode: VacuumErrorCode;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export
|
|
14
|
+
export interface DeviceStatusNotify extends DeviceStatus, CloudMessageResult {
|
|
15
|
+
duid: string;
|
|
16
|
+
}
|
|
@@ -3,6 +3,22 @@ import { Room } from './room.js';
|
|
|
3
3
|
import { Scene } from './scene.js';
|
|
4
4
|
import { UserData } from './userData.js';
|
|
5
5
|
|
|
6
|
+
export interface DeviceData {
|
|
7
|
+
id: string;
|
|
8
|
+
firmwareVersion: string;
|
|
9
|
+
serialNumber: string;
|
|
10
|
+
model: string;
|
|
11
|
+
category: string;
|
|
12
|
+
batteryLevel: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface DeviceInformation {
|
|
16
|
+
userData: UserData;
|
|
17
|
+
localKey: string;
|
|
18
|
+
pv: string;
|
|
19
|
+
model?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
6
22
|
export interface Device {
|
|
7
23
|
duid: string;
|
|
8
24
|
name: string;
|
|
@@ -15,40 +31,20 @@ export interface Device {
|
|
|
15
31
|
|
|
16
32
|
activeTime: number;
|
|
17
33
|
createTime: number;
|
|
18
|
-
|
|
19
34
|
localKey: string;
|
|
20
35
|
|
|
21
36
|
/** The protocol version of the robot. */
|
|
22
37
|
pv: string;
|
|
23
38
|
online: boolean;
|
|
24
|
-
|
|
25
39
|
productId: string;
|
|
26
|
-
|
|
27
40
|
rrHomeId: number;
|
|
28
|
-
|
|
29
41
|
/** The firmware version of the robot. */
|
|
30
42
|
fv: string;
|
|
31
43
|
|
|
32
44
|
deviceStatus: Record<string, number>;
|
|
33
45
|
rooms: Room[];
|
|
34
|
-
|
|
35
46
|
schema: DeviceSchema[];
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
id: string;
|
|
39
|
-
firmwareVersion: string;
|
|
40
|
-
serialNumber: string;
|
|
41
|
-
model: string;
|
|
42
|
-
category: string;
|
|
43
|
-
batteryLevel: number;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
store?: {
|
|
47
|
-
userData: UserData;
|
|
48
|
-
localKey: string;
|
|
49
|
-
pv: string;
|
|
50
|
-
model?: string;
|
|
51
|
-
};
|
|
52
|
-
|
|
47
|
+
data: DeviceData;
|
|
48
|
+
store?: DeviceInformation;
|
|
53
49
|
scenes?: Scene[];
|
|
54
50
|
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
interface MapBackupInformation {
|
|
2
|
+
mapFlag: number;
|
|
3
|
+
add_time: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
1
6
|
export interface MapInformation {
|
|
2
7
|
mapFlag: number;
|
|
3
8
|
add_time: number;
|
|
4
9
|
length: number;
|
|
5
10
|
name: string;
|
|
6
11
|
rooms?: RoomInformation[] | undefined;
|
|
7
|
-
bak_maps:
|
|
12
|
+
bak_maps: MapBackupInformation[];
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
export interface RoomInformation {
|
|
@@ -54,17 +54,19 @@ export interface CloudMessageResult {
|
|
|
54
54
|
repeat?: number;
|
|
55
55
|
kct?: number;
|
|
56
56
|
subdivision_sets?: number;
|
|
57
|
-
cleaning_info?:
|
|
58
|
-
target_segment_id: number;
|
|
59
|
-
segment_id: number;
|
|
60
|
-
fan_power: number;
|
|
61
|
-
water_box_status: number;
|
|
62
|
-
mop_mode: number;
|
|
63
|
-
};
|
|
57
|
+
cleaning_info?: CleanInformation;
|
|
64
58
|
exit_dock?: number;
|
|
65
59
|
seq_type?: number;
|
|
66
60
|
}
|
|
67
61
|
|
|
62
|
+
interface CleanInformation {
|
|
63
|
+
target_segment_id: number;
|
|
64
|
+
segment_id: number;
|
|
65
|
+
fan_power: number;
|
|
66
|
+
water_box_status: number;
|
|
67
|
+
mop_mode: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
68
70
|
export enum CarpetCleanMode {
|
|
69
71
|
Avoid = 0,
|
|
70
72
|
Ignore = 2,
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import decodeComponent from '../helper/nameDecoder.js';
|
|
2
2
|
import { Room } from './room.js';
|
|
3
3
|
|
|
4
|
+
interface RoomEntry {
|
|
5
|
+
id: number;
|
|
6
|
+
name: string | undefined;
|
|
7
|
+
}
|
|
8
|
+
|
|
4
9
|
export class RoomInfo {
|
|
5
|
-
readonly rooms:
|
|
10
|
+
readonly rooms: RoomEntry[] = [];
|
|
6
11
|
|
|
7
12
|
constructor(roomInfo: Room[], roomData: number[][]) {
|
|
8
13
|
this.rooms = roomData
|
|
@@ -7,12 +7,14 @@ export class Scene {
|
|
|
7
7
|
type: string | undefined;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
interface ActionInformation {
|
|
11
|
+
type: string;
|
|
12
|
+
items: SceneItem[];
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
export interface SceneParam {
|
|
11
16
|
triggers: unknown[];
|
|
12
|
-
action:
|
|
13
|
-
type: string;
|
|
14
|
-
items: SceneItem[];
|
|
15
|
-
};
|
|
17
|
+
action: ActionInformation;
|
|
16
18
|
matchType: string;
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -10,15 +10,17 @@ export interface UserData {
|
|
|
10
10
|
rriot: Rriot;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
interface r {
|
|
14
|
+
r: string;
|
|
15
|
+
a: string;
|
|
16
|
+
m: string;
|
|
17
|
+
l: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
export interface Rriot {
|
|
14
21
|
u: string;
|
|
15
22
|
s: string;
|
|
16
23
|
h: string;
|
|
17
24
|
k: string;
|
|
18
|
-
r:
|
|
19
|
-
r: string;
|
|
20
|
-
a: string;
|
|
21
|
-
m: string;
|
|
22
|
-
l: string;
|
|
23
|
-
};
|
|
25
|
+
r: r;
|
|
24
26
|
}
|
|
@@ -6,6 +6,7 @@ import { RequestMessage } from './model/requestMessage.js';
|
|
|
6
6
|
import { DeviceStatus } from '../Zmodel/deviceStatus.js';
|
|
7
7
|
import { Client } from './client.js';
|
|
8
8
|
import { NetworkInfo } from '../Zmodel/networkInfo.js';
|
|
9
|
+
import { CleanModeSetting } from '../../behaviors/roborock.vacuum/default/default.js';
|
|
9
10
|
|
|
10
11
|
export class MessageProcessor {
|
|
11
12
|
private readonly client: Client;
|
|
@@ -108,7 +109,7 @@ export class MessageProcessor {
|
|
|
108
109
|
return this.client.get(duid, request);
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
public async getCleanModeData(duid: string): Promise<
|
|
112
|
+
public async getCleanModeData(duid: string): Promise<CleanModeSetting> {
|
|
112
113
|
const currentMopMode = await this.getCustomMessage(duid, new RequestMessage({ method: 'get_mop_mode' }));
|
|
113
114
|
const suctionPowerRaw = await this.getCustomMessage(duid, new RequestMessage({ method: 'get_custom_mode' }));
|
|
114
115
|
const waterFlowRaw = await this.getCustomMessage(duid, new RequestMessage({ method: 'get_water_box_custom_mode' }));
|
|
@@ -145,7 +146,7 @@ export class MessageProcessor {
|
|
|
145
146
|
waterFlow: waterFlow,
|
|
146
147
|
distance_off: distance_off,
|
|
147
148
|
mopRoute: mopRoute,
|
|
148
|
-
};
|
|
149
|
+
} satisfies CleanModeSetting;
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
public async changeCleanMode(duid: string, suctionPower: number, waterFlow: number, mopRoute: number, distance_off: number): Promise<void> {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
interface Security {
|
|
2
|
+
endpoint: string;
|
|
3
|
+
nonce: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
1
6
|
export interface DpsPayload {
|
|
2
7
|
id: number;
|
|
3
8
|
method?: string;
|
|
4
9
|
params?: unknown[] | Record<string, unknown> | undefined;
|
|
5
|
-
security?:
|
|
6
|
-
endpoint: string;
|
|
7
|
-
nonce: string;
|
|
8
|
-
};
|
|
10
|
+
security?: Security;
|
|
9
11
|
result: unknown;
|
|
10
12
|
}
|
|
11
13
|
|
|
@@ -2,9 +2,15 @@ import { randomBytes, randomInt } from 'node:crypto';
|
|
|
2
2
|
import * as CryptoUtils from '../../helper/cryptoHelper.js';
|
|
3
3
|
import { UserData } from '../../Zmodel/userData.js';
|
|
4
4
|
|
|
5
|
+
interface DeviceInfo {
|
|
6
|
+
localKey: string;
|
|
7
|
+
protocolVersion: string;
|
|
8
|
+
nonce: number | undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
export class MessageContext {
|
|
6
12
|
private readonly endpoint: string;
|
|
7
|
-
private readonly devices = new Map<string,
|
|
13
|
+
private readonly devices = new Map<string, DeviceInfo>();
|
|
8
14
|
public readonly nonce: number;
|
|
9
15
|
public readonly serializeNonce: Buffer;
|
|
10
16
|
|
|
@@ -7,6 +7,11 @@ import { MessageContext } from '../broadcast/model/messageContext.js';
|
|
|
7
7
|
import { AnsiLogger } from 'matterbridge/logger';
|
|
8
8
|
import { Protocol } from '../broadcast/model/protocol.js';
|
|
9
9
|
|
|
10
|
+
interface SerializeResult {
|
|
11
|
+
messageId: number;
|
|
12
|
+
buffer: Buffer<ArrayBufferLike>;
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
export class MessageSerializer {
|
|
11
16
|
private readonly context: MessageContext;
|
|
12
17
|
private readonly logger: AnsiLogger;
|
|
@@ -18,7 +23,7 @@ export class MessageSerializer {
|
|
|
18
23
|
this.logger = logger;
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
public serialize(duid: string, request: RequestMessage):
|
|
26
|
+
public serialize(duid: string, request: RequestMessage): SerializeResult {
|
|
22
27
|
const messageId = request.messageId;
|
|
23
28
|
const buffer = this.buildBuffer(duid, messageId, request);
|
|
24
29
|
return { messageId: messageId, buffer: buffer };
|
package/src/roborockService.ts
CHANGED
|
@@ -26,8 +26,17 @@ import { ServiceArea } from 'matterbridge/matter/clusters';
|
|
|
26
26
|
import { LocalNetworkClient } from './roborockCommunication/broadcast/client/LocalNetworkClient.js';
|
|
27
27
|
import { RoomIndexMap } from './model/roomIndexMap.js';
|
|
28
28
|
import { DpsPayload } from './roborockCommunication/broadcast/model/dps.js';
|
|
29
|
+
import { CleanModeSetting } from './behaviors/roborock.vacuum/default/default.js';
|
|
29
30
|
export type Factory<A, T> = (logger: AnsiLogger, arg: A) => T;
|
|
30
31
|
|
|
32
|
+
interface MapRoomResponse {
|
|
33
|
+
vacuumRoom?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface Security {
|
|
37
|
+
nonce: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
31
40
|
export default class RoborockService {
|
|
32
41
|
private loginApi: RoborockAuthenticateApi;
|
|
33
42
|
private logger: AnsiLogger;
|
|
@@ -130,7 +139,7 @@ export default class RoborockService {
|
|
|
130
139
|
return this.supportedAreaIndexMaps.get(duid);
|
|
131
140
|
}
|
|
132
141
|
|
|
133
|
-
public async getCleanModeData(duid: string): Promise<
|
|
142
|
+
public async getCleanModeData(duid: string): Promise<CleanModeSetting> {
|
|
134
143
|
this.logger.notice('RoborockService - getCleanModeData');
|
|
135
144
|
const data = await this.getMessageProcessor(duid)?.getCleanModeData(duid);
|
|
136
145
|
if (!data) {
|
|
@@ -140,7 +149,7 @@ export default class RoborockService {
|
|
|
140
149
|
}
|
|
141
150
|
|
|
142
151
|
public async getRoomIdFromMap(duid: string): Promise<number | undefined> {
|
|
143
|
-
const data = (await this.customGet(duid, new RequestMessage({ method: 'get_map_v1' }))) as
|
|
152
|
+
const data = (await this.customGet(duid, new RequestMessage({ method: 'get_map_v1' }))) as MapRoomResponse;
|
|
144
153
|
return data?.vacuumRoom;
|
|
145
154
|
}
|
|
146
155
|
|
|
@@ -153,12 +162,9 @@ export default class RoborockService {
|
|
|
153
162
|
});
|
|
154
163
|
}
|
|
155
164
|
|
|
156
|
-
public async changeCleanMode(
|
|
157
|
-
duid: string,
|
|
158
|
-
{ suctionPower, waterFlow, distance_off, mopRoute }: { suctionPower: number; waterFlow: number; distance_off: number; mopRoute: number },
|
|
159
|
-
): Promise<void> {
|
|
165
|
+
public async changeCleanMode(duid: string, { suctionPower, waterFlow, distance_off, mopRoute }: CleanModeSetting): Promise<void> {
|
|
160
166
|
this.logger.notice('RoborockService - changeCleanMode');
|
|
161
|
-
return this.getMessageProcessor(duid)?.changeCleanMode(duid, suctionPower, waterFlow, mopRoute, distance_off);
|
|
167
|
+
return this.getMessageProcessor(duid)?.changeCleanMode(duid, suctionPower, waterFlow, mopRoute ?? 0, distance_off);
|
|
162
168
|
}
|
|
163
169
|
|
|
164
170
|
public async startClean(duid: string): Promise<void> {
|
|
@@ -497,7 +503,7 @@ export default class RoborockService {
|
|
|
497
503
|
|
|
498
504
|
if (message instanceof ResponseMessage && message.contain(Protocol.hello_response)) {
|
|
499
505
|
const dps = message.dps[Protocol.hello_response] as DpsPayload;
|
|
500
|
-
const result = dps.result as
|
|
506
|
+
const result = dps.result as Security;
|
|
501
507
|
self.messageClient?.updateNonce(message.duid, result.nonce);
|
|
502
508
|
}
|
|
503
509
|
},
|
package/src/rvc.ts
CHANGED
|
@@ -8,6 +8,10 @@ import { ModeBase, RvcOperationalState, ServiceArea } from 'matterbridge/matter/
|
|
|
8
8
|
import { ExperimentalFeatureSetting } from './model/ExperimentalFeatureSetting.js';
|
|
9
9
|
import { DockingStationStatus } from './model/DockingStationStatus.js';
|
|
10
10
|
|
|
11
|
+
interface IdentifyCommandRequest {
|
|
12
|
+
identifyTime?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
11
15
|
export class RoborockVacuumCleaner extends RoboticVacuumCleaner {
|
|
12
16
|
username: string | undefined;
|
|
13
17
|
device: Device;
|
|
@@ -64,7 +68,7 @@ export class RoborockVacuumCleaner extends RoboticVacuumCleaner {
|
|
|
64
68
|
public configurateHandler(behaviorHandler: BehaviorFactoryResult): void {
|
|
65
69
|
this.addCommandHandler('identify', async ({ request, cluster, attributes, endpoint }) => {
|
|
66
70
|
this.log.info(`Identify command received for endpoint ${endpoint}, cluster ${cluster}, attributes ${debugStringify(attributes)}, request: ${JSON.stringify(request)}`);
|
|
67
|
-
behaviorHandler.executeCommand('playSoundToLocate', (request as
|
|
71
|
+
behaviorHandler.executeCommand('playSoundToLocate', (request as IdentifyCommandRequest).identifyTime ?? 0);
|
|
68
72
|
});
|
|
69
73
|
|
|
70
74
|
this.addCommandHandler('selectAreas', async ({ request }) => {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { CleanModeSetting } from '../behaviors/roborock.vacuum/default/default.js';
|
|
1
2
|
import { getCurrentCleanModeDefault } from '../behaviors/roborock.vacuum/default/runtimes.js';
|
|
2
3
|
import { getCurrentCleanModeSmart } from '../behaviors/roborock.vacuum/smart/runtimes.js';
|
|
3
4
|
import { DeviceModel } from '../roborockCommunication/Zmodel/deviceModel.js';
|
|
4
5
|
|
|
5
|
-
export type CleanModeFunc = (setting:
|
|
6
|
+
export type CleanModeFunc = (setting: CleanModeSetting) => number | undefined;
|
|
6
7
|
|
|
7
8
|
export function getCurrentCleanModeFunc(model: string, forceRunAtDefault: boolean): CleanModeFunc {
|
|
8
9
|
if (forceRunAtDefault) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DeviceData } from '../../roborockCommunication/Zmodel/device';
|
|
1
2
|
import { updateFromHomeData } from '../../runtimes/handleHomeDataMessage';
|
|
2
3
|
import { homeData } from '../testData/mockData';
|
|
3
4
|
import { PowerSource, RvcRunMode } from 'matterbridge/matter/clusters';
|
|
@@ -7,7 +8,7 @@ const mockUpdateAttribute = jest.fn();
|
|
|
7
8
|
const duid = 'test-duid';
|
|
8
9
|
const robot = {
|
|
9
10
|
updateAttribute: mockUpdateAttribute,
|
|
10
|
-
device: { data: { model: 'test-model' } as
|
|
11
|
+
device: { data: { model: 'test-model' } as DeviceData | undefined },
|
|
11
12
|
dockStationStatus: {},
|
|
12
13
|
};
|
|
13
14
|
const platform = {
|
|
@@ -196,7 +196,7 @@ describe('handleLocalMessage -- FF OFF', () => {
|
|
|
196
196
|
[4, 4],
|
|
197
197
|
]),
|
|
198
198
|
|
|
199
|
-
getAreaId(roomId: number):
|
|
199
|
+
getAreaId(roomId: number): Area | undefined {
|
|
200
200
|
const index = this.roomMap.get(roomId);
|
|
201
201
|
if (index === undefined) {
|
|
202
202
|
return undefined;
|
|
@@ -220,3 +220,8 @@ describe('handleLocalMessage -- FF OFF', () => {
|
|
|
220
220
|
expect(mockUpdateAttribute).toHaveBeenCalledWith(ServiceArea.Cluster.id, 'currentArea', 4, mockLog);
|
|
221
221
|
});
|
|
222
222
|
});
|
|
223
|
+
|
|
224
|
+
interface Area {
|
|
225
|
+
roomId: number;
|
|
226
|
+
mapId: number;
|
|
227
|
+
}
|