matterbridge-roborock-vacuum-plugin 1.1.1-rc09 → 1.1.1-rc11
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/README_SUPPORTED.md +1 -0
- package/dist/behaviorFactory.js +2 -1
- package/dist/initialData/getSupportedCleanModes.js +1 -0
- package/dist/platform.js +9 -1
- package/dist/roborockCommunication/RESTAPI/roborockAuthenticateApi.js +22 -4
- package/dist/roborockCommunication/Zmodel/deviceModel.js +1 -0
- package/dist/roborockService.js +2 -2
- package/dist/share/runtimeHelper.js +1 -0
- package/matterbridge-roborock-vacuum-plugin.config.json +1 -1
- package/matterbridge-roborock-vacuum-plugin.schema.json +8 -3
- package/package.json +1 -1
- package/src/behaviorFactory.ts +2 -1
- package/src/initialData/getSupportedCleanModes.ts +1 -0
- package/src/platform.ts +13 -1
- package/src/roborockCommunication/RESTAPI/roborockAuthenticateApi.ts +22 -4
- package/src/roborockCommunication/Zmodel/deviceModel.ts +1 -0
- package/src/roborockService.ts +4 -2
- package/src/share/runtimeHelper.ts +1 -0
package/README_SUPPORTED.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
| Roborock Qrevo Edge 5V1 | `QREVO_EDGE_5V1` | `roborock.vacuum.a187` | |
|
|
8
8
|
| Roborock S8 Pro Ultra | `S8_PRO_ULTRA` | `roborock.vacuum.a70` | |
|
|
9
9
|
| Roborock S7 MaxV | `S7_MAXV` | `roborock.vacuum.a27` | |
|
|
10
|
+
| Roborock Qrevo Plus | `QREVO_PLUS` | `roborock.vacuum.a123` | |
|
|
10
11
|
|
|
11
12
|
These devices have been fully tested and are confirmed to work as expected.
|
|
12
13
|
|
package/dist/behaviorFactory.js
CHANGED
|
@@ -9,7 +9,8 @@ export function configurateBehavior(model, duid, roborockService, cleanModeSetti
|
|
|
9
9
|
return deviceHandler;
|
|
10
10
|
}
|
|
11
11
|
switch (model) {
|
|
12
|
-
case DeviceModel.QREVO_EDGE_5V1:
|
|
12
|
+
case DeviceModel.QREVO_EDGE_5V1:
|
|
13
|
+
case DeviceModel.QREVO_PLUS: {
|
|
13
14
|
const deviceHandler = new BehaviorDeviceGeneric(logger);
|
|
14
15
|
setCommandHandlerSmart(duid, deviceHandler, logger, roborockService, cleanModeSettings);
|
|
15
16
|
return deviceHandler;
|
|
@@ -7,6 +7,7 @@ export function getSupportedCleanModes(model, enableExperimentalFeature) {
|
|
|
7
7
|
}
|
|
8
8
|
switch (model) {
|
|
9
9
|
case DeviceModel.QREVO_EDGE_5V1:
|
|
10
|
+
case DeviceModel.QREVO_PLUS:
|
|
10
11
|
return getSupportedCleanModesSmart(enableExperimentalFeature);
|
|
11
12
|
case DeviceModel.S7_MAXV:
|
|
12
13
|
case DeviceModel.S8_PRO_ULTRA:
|
package/dist/platform.js
CHANGED
|
@@ -25,6 +25,11 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
25
25
|
enableExperimentalFeature;
|
|
26
26
|
persist;
|
|
27
27
|
rrHomeId;
|
|
28
|
+
regionUrls = {
|
|
29
|
+
US: 'https://usiot.roborock.com',
|
|
30
|
+
EU: 'https://euiot.roborock.com',
|
|
31
|
+
CN: 'https://iot.roborock.com',
|
|
32
|
+
};
|
|
28
33
|
constructor(matterbridge, log, config) {
|
|
29
34
|
super(matterbridge, log, config);
|
|
30
35
|
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.3.6')) {
|
|
@@ -69,7 +74,10 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
69
74
|
else {
|
|
70
75
|
this.log.debug('Using cached deviceId:', deviceId);
|
|
71
76
|
}
|
|
72
|
-
|
|
77
|
+
const region = this.config.region?.toUpperCase() ?? 'US';
|
|
78
|
+
const baseUrl = this.regionUrls[region] ?? this.regionUrls['US'];
|
|
79
|
+
this.log.notice(`Using region: ${region} (${baseUrl})`);
|
|
80
|
+
this.roborockService = new RoborockService((logger, url) => new RoborockAuthenticateApi(this.log, axiosInstance, deviceId, url), (logger, ud) => new RoborockIoTApi(ud, logger), this.config.refreshInterval ?? 60, this.clientManager, this.log, baseUrl);
|
|
73
81
|
const username = this.config.username;
|
|
74
82
|
this.log.debug(`config: ${debugStringify(this.config)}`);
|
|
75
83
|
const authenticationPayload = this.config.authentication;
|
|
@@ -8,13 +8,15 @@ export class RoborockAuthenticateApi {
|
|
|
8
8
|
deviceId;
|
|
9
9
|
username;
|
|
10
10
|
authToken;
|
|
11
|
+
baseUrl;
|
|
11
12
|
cachedBaseUrl;
|
|
12
13
|
cachedCountry;
|
|
13
14
|
cachedCountryCode;
|
|
14
|
-
constructor(logger, axiosFactory = axios, deviceId) {
|
|
15
|
+
constructor(logger, axiosFactory = axios, deviceId, baseUrl = 'https://usiot.roborock.com') {
|
|
15
16
|
this.deviceId = deviceId ?? crypto.randomUUID();
|
|
16
17
|
this.axiosFactory = axiosFactory;
|
|
17
18
|
this.logger = logger;
|
|
19
|
+
this.baseUrl = baseUrl;
|
|
18
20
|
}
|
|
19
21
|
async loginWithUserData(username, userData) {
|
|
20
22
|
this.loginWithAuthToken(username, userData.token);
|
|
@@ -56,12 +58,28 @@ export class RoborockAuthenticateApi {
|
|
|
56
58
|
const api = await this.getAPIFor(email);
|
|
57
59
|
const xMercyKs = this.generateRandomString(16);
|
|
58
60
|
const xMercyK = await this.signKeyV3(api, xMercyKs);
|
|
61
|
+
let country = this.cachedCountry;
|
|
62
|
+
let countryCode = this.cachedCountryCode;
|
|
63
|
+
if (!country || !countryCode) {
|
|
64
|
+
if (this.baseUrl.includes('euiot')) {
|
|
65
|
+
country = country || 'Germany';
|
|
66
|
+
countryCode = countryCode || 'DE';
|
|
67
|
+
}
|
|
68
|
+
else if (this.baseUrl.includes('usiot')) {
|
|
69
|
+
country = country || 'United States';
|
|
70
|
+
countryCode = countryCode || 'US';
|
|
71
|
+
}
|
|
72
|
+
else if (this.baseUrl.includes('iot.roborock.com')) {
|
|
73
|
+
country = country || 'China';
|
|
74
|
+
countryCode = countryCode || 'CN';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
59
77
|
const response = await api.post('api/v4/auth/email/login/code', null, {
|
|
60
78
|
params: {
|
|
61
79
|
email: email,
|
|
62
80
|
code: code,
|
|
63
|
-
country:
|
|
64
|
-
countryCode:
|
|
81
|
+
country: country ?? '',
|
|
82
|
+
countryCode: countryCode ?? '',
|
|
65
83
|
majorVersion: '14',
|
|
66
84
|
minorVersion: '0',
|
|
67
85
|
},
|
|
@@ -117,7 +135,7 @@ export class RoborockAuthenticateApi {
|
|
|
117
135
|
this.username = username;
|
|
118
136
|
return apiResponse.data.url;
|
|
119
137
|
}
|
|
120
|
-
async apiForUser(username, baseUrl =
|
|
138
|
+
async apiForUser(username, baseUrl = this.baseUrl) {
|
|
121
139
|
const instance = this.axiosFactory.create({
|
|
122
140
|
baseURL: baseUrl,
|
|
123
141
|
headers: {
|
|
@@ -25,4 +25,5 @@ export var DeviceModel;
|
|
|
25
25
|
DeviceModel["QREVO_MAXV"] = "roborock.vacuum.a87";
|
|
26
26
|
DeviceModel["QREVO_EDGE_5V1"] = "roborock.vacuum.a187";
|
|
27
27
|
DeviceModel["QREVO_EDGE_5AE"] = "roborock.vacuum.xxxx";
|
|
28
|
+
DeviceModel["QREVO_PLUS"] = "roborock.vacuum.a123";
|
|
28
29
|
})(DeviceModel || (DeviceModel = {}));
|
package/dist/roborockService.js
CHANGED
|
@@ -24,9 +24,9 @@ export default class RoborockService {
|
|
|
24
24
|
selectedAreas = new Map();
|
|
25
25
|
supportedAreaIndexMaps = new Map();
|
|
26
26
|
vacuumNeedAPIV3 = ['roborock.vacuum.ss07'];
|
|
27
|
-
constructor(authenticateApiSupplier = (logger) => new RoborockAuthenticateApi(logger), iotApiSupplier = (logger, ud) => new RoborockIoTApi(ud, logger), refreshInterval, clientManager, logger) {
|
|
27
|
+
constructor(authenticateApiSupplier = (logger, baseUrl) => new RoborockAuthenticateApi(logger, undefined, undefined, baseUrl), iotApiSupplier = (logger, ud) => new RoborockIoTApi(ud, logger), refreshInterval, clientManager, logger, baseUrl = 'https://usiot.roborock.com') {
|
|
28
28
|
this.logger = logger;
|
|
29
|
-
this.loginApi = authenticateApiSupplier(logger);
|
|
29
|
+
this.loginApi = authenticateApiSupplier(logger, baseUrl);
|
|
30
30
|
this.iotApiFactory = iotApiSupplier;
|
|
31
31
|
this.refreshInterval = refreshInterval;
|
|
32
32
|
this.clientManager = clientManager;
|
|
@@ -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-rc11 by https://github.com/RinDevJunior",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"required": ["username"],
|
|
6
6
|
"properties": {
|
|
@@ -29,6 +29,12 @@
|
|
|
29
29
|
"description": "Roborock account email address",
|
|
30
30
|
"type": "string"
|
|
31
31
|
},
|
|
32
|
+
"region": {
|
|
33
|
+
"description": "Roborock account region",
|
|
34
|
+
"type": "string",
|
|
35
|
+
"enum": ["US", "EU", "CN"],
|
|
36
|
+
"default": "US"
|
|
37
|
+
},
|
|
32
38
|
"authentication": {
|
|
33
39
|
"description": "Authentication method to use",
|
|
34
40
|
"type": "object",
|
|
@@ -49,7 +55,7 @@
|
|
|
49
55
|
"maxLength": 6
|
|
50
56
|
}
|
|
51
57
|
},
|
|
52
|
-
"required": ["authenticationMethod"
|
|
58
|
+
"required": ["authenticationMethod"]
|
|
53
59
|
},
|
|
54
60
|
{
|
|
55
61
|
"title": "Password",
|
|
@@ -70,7 +76,6 @@
|
|
|
70
76
|
}
|
|
71
77
|
]
|
|
72
78
|
},
|
|
73
|
-
|
|
74
79
|
"refreshInterval": {
|
|
75
80
|
"description": "Refresh interval in seconds (default: 60)",
|
|
76
81
|
"type": "number",
|
package/package.json
CHANGED
package/src/behaviorFactory.ts
CHANGED
|
@@ -23,7 +23,8 @@ export function configurateBehavior(
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
switch (model) {
|
|
26
|
-
case DeviceModel.QREVO_EDGE_5V1:
|
|
26
|
+
case DeviceModel.QREVO_EDGE_5V1:
|
|
27
|
+
case DeviceModel.QREVO_PLUS: {
|
|
27
28
|
const deviceHandler = new BehaviorDeviceGeneric<EndpointCommandsSmart>(logger);
|
|
28
29
|
setCommandHandlerSmart(duid, deviceHandler, logger, roborockService, cleanModeSettings);
|
|
29
30
|
return deviceHandler;
|
|
@@ -11,6 +11,7 @@ export function getSupportedCleanModes(model: string, enableExperimentalFeature:
|
|
|
11
11
|
|
|
12
12
|
switch (model) {
|
|
13
13
|
case DeviceModel.QREVO_EDGE_5V1:
|
|
14
|
+
case DeviceModel.QREVO_PLUS:
|
|
14
15
|
return getSupportedCleanModesSmart(enableExperimentalFeature);
|
|
15
16
|
|
|
16
17
|
case DeviceModel.S7_MAXV:
|
package/src/platform.ts
CHANGED
|
@@ -30,6 +30,12 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
30
30
|
persist: NodePersist.LocalStorage;
|
|
31
31
|
rrHomeId: number | undefined;
|
|
32
32
|
|
|
33
|
+
private regionUrls: Record<string, string> = {
|
|
34
|
+
US: 'https://usiot.roborock.com',
|
|
35
|
+
EU: 'https://euiot.roborock.com',
|
|
36
|
+
CN: 'https://iot.roborock.com',
|
|
37
|
+
};
|
|
38
|
+
|
|
33
39
|
constructor(matterbridge: PlatformMatterbridge, log: AnsiLogger, config: PlatformConfig) {
|
|
34
40
|
super(matterbridge, log, config);
|
|
35
41
|
|
|
@@ -91,12 +97,18 @@ export class RoborockMatterbridgePlatform extends MatterbridgeDynamicPlatform {
|
|
|
91
97
|
this.log.debug('Using cached deviceId:', deviceId);
|
|
92
98
|
}
|
|
93
99
|
|
|
100
|
+
const region = (this.config.region as string)?.toUpperCase() ?? 'US';
|
|
101
|
+
// use regionmap to get baseUrl
|
|
102
|
+
const baseUrl = this.regionUrls[region] ?? this.regionUrls['US'];
|
|
103
|
+
this.log.notice(`Using region: ${region} (${baseUrl})`);
|
|
104
|
+
|
|
94
105
|
this.roborockService = new RoborockService(
|
|
95
|
-
() => new RoborockAuthenticateApi(this.log, axiosInstance, deviceId),
|
|
106
|
+
(logger, url) => new RoborockAuthenticateApi(this.log, axiosInstance, deviceId, url),
|
|
96
107
|
(logger, ud) => new RoborockIoTApi(ud, logger),
|
|
97
108
|
(this.config.refreshInterval as number) ?? 60,
|
|
98
109
|
this.clientManager,
|
|
99
110
|
this.log,
|
|
111
|
+
baseUrl,
|
|
100
112
|
);
|
|
101
113
|
|
|
102
114
|
const username = this.config.username as string;
|
|
@@ -14,15 +14,17 @@ export class RoborockAuthenticateApi {
|
|
|
14
14
|
private deviceId: string;
|
|
15
15
|
private username?: string;
|
|
16
16
|
private authToken?: string;
|
|
17
|
+
private readonly baseUrl: string;
|
|
17
18
|
// Cached values from base URL lookup for v4 login
|
|
18
19
|
private cachedBaseUrl?: string;
|
|
19
20
|
private cachedCountry?: string;
|
|
20
21
|
private cachedCountryCode?: string;
|
|
21
22
|
|
|
22
|
-
constructor(logger: AnsiLogger, axiosFactory: AxiosStatic = axios, deviceId?: string) {
|
|
23
|
+
constructor(logger: AnsiLogger, axiosFactory: AxiosStatic = axios, deviceId?: string, baseUrl = 'https://usiot.roborock.com') {
|
|
23
24
|
this.deviceId = deviceId ?? crypto.randomUUID();
|
|
24
25
|
this.axiosFactory = axiosFactory;
|
|
25
26
|
this.logger = logger;
|
|
27
|
+
this.baseUrl = baseUrl;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
public async loginWithUserData(username: string, userData: UserData): Promise<UserData> {
|
|
@@ -98,12 +100,28 @@ export class RoborockAuthenticateApi {
|
|
|
98
100
|
// Get signed key from API
|
|
99
101
|
const xMercyK = await this.signKeyV3(api, xMercyKs);
|
|
100
102
|
|
|
103
|
+
// Fallback for missing country info to avoid 1002 parameter error
|
|
104
|
+
let country = this.cachedCountry;
|
|
105
|
+
let countryCode = this.cachedCountryCode;
|
|
106
|
+
if (!country || !countryCode) {
|
|
107
|
+
if (this.baseUrl.includes('euiot')) {
|
|
108
|
+
country = country || 'Germany';
|
|
109
|
+
countryCode = countryCode || 'DE';
|
|
110
|
+
} else if (this.baseUrl.includes('usiot')) {
|
|
111
|
+
country = country || 'United States';
|
|
112
|
+
countryCode = countryCode || 'US';
|
|
113
|
+
} else if (this.baseUrl.includes('iot.roborock.com')) {
|
|
114
|
+
country = country || 'China';
|
|
115
|
+
countryCode = countryCode || 'CN';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
101
119
|
const response = await api.post('api/v4/auth/email/login/code', null, {
|
|
102
120
|
params: {
|
|
103
121
|
email: email,
|
|
104
122
|
code: code,
|
|
105
|
-
country:
|
|
106
|
-
countryCode:
|
|
123
|
+
country: country ?? '',
|
|
124
|
+
countryCode: countryCode ?? '',
|
|
107
125
|
majorVersion: '14',
|
|
108
126
|
minorVersion: '0',
|
|
109
127
|
},
|
|
@@ -177,7 +195,7 @@ export class RoborockAuthenticateApi {
|
|
|
177
195
|
return apiResponse.data.url;
|
|
178
196
|
}
|
|
179
197
|
|
|
180
|
-
private async apiForUser(username: string, baseUrl =
|
|
198
|
+
private async apiForUser(username: string, baseUrl = this.baseUrl): Promise<AxiosInstance> {
|
|
181
199
|
const instance = this.axiosFactory.create({
|
|
182
200
|
baseURL: baseUrl,
|
|
183
201
|
headers: {
|
package/src/roborockService.ts
CHANGED
|
@@ -64,14 +64,16 @@ export default class RoborockService {
|
|
|
64
64
|
private readonly vacuumNeedAPIV3 = ['roborock.vacuum.ss07'];
|
|
65
65
|
|
|
66
66
|
constructor(
|
|
67
|
-
authenticateApiSupplier:
|
|
67
|
+
authenticateApiSupplier: (logger: AnsiLogger, baseUrl: string) => RoborockAuthenticateApi = (logger, baseUrl) =>
|
|
68
|
+
new RoborockAuthenticateApi(logger, undefined, undefined, baseUrl),
|
|
68
69
|
iotApiSupplier: Factory<UserData, RoborockIoTApi> = (logger, ud) => new RoborockIoTApi(ud, logger),
|
|
69
70
|
refreshInterval: number,
|
|
70
71
|
clientManager: ClientManager,
|
|
71
72
|
logger: AnsiLogger,
|
|
73
|
+
baseUrl = 'https://usiot.roborock.com',
|
|
72
74
|
) {
|
|
73
75
|
this.logger = logger;
|
|
74
|
-
this.loginApi = authenticateApiSupplier(logger);
|
|
76
|
+
this.loginApi = authenticateApiSupplier(logger, baseUrl);
|
|
75
77
|
this.iotApiFactory = iotApiSupplier;
|
|
76
78
|
this.refreshInterval = refreshInterval;
|
|
77
79
|
this.clientManager = clientManager;
|