iobroker.bmw 2.1.1 → 2.5.1
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.md +20 -1
- package/io-package.json +23 -2
- package/main.js +118 -179
- package/package.json +10 -11
package/README.md
CHANGED
|
@@ -16,10 +16,29 @@
|
|
|
16
16
|
|
|
17
17
|
Adapter for BMW
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
**Aktueller Status**
|
|
20
|
+
|
|
21
|
+
bmw.0.VIN.properties
|
|
22
|
+
|
|
23
|
+
**Remote Befehle sind möglich unter**
|
|
24
|
+
|
|
25
|
+
bmw.0.VIN.remotev2
|
|
26
|
+
|
|
20
27
|
|
|
21
28
|
## Changelog
|
|
22
29
|
|
|
30
|
+
### 2.5.0
|
|
31
|
+
|
|
32
|
+
- Fix login
|
|
33
|
+
|
|
34
|
+
### 2.4.1
|
|
35
|
+
|
|
36
|
+
- Add support for MINI and force refresh remote
|
|
37
|
+
|
|
38
|
+
### 2.3.0
|
|
39
|
+
|
|
40
|
+
- Disable v1 Endpoints
|
|
41
|
+
|
|
23
42
|
### 2.1.1
|
|
24
43
|
|
|
25
44
|
- Upgrade to statusV2 and remoteV2
|
package/io-package.json
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "bmw",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.5.1",
|
|
5
5
|
"news": {
|
|
6
|
-
"2.
|
|
6
|
+
"2.5.1": {
|
|
7
|
+
"en": "Add login error message",
|
|
8
|
+
"de": "Loginproblem Nachricht hinzugefügt"
|
|
9
|
+
},
|
|
10
|
+
"2.5.0": {
|
|
11
|
+
"en": "Fix Login",
|
|
12
|
+
"de": "Loginproblem behoben"
|
|
13
|
+
},
|
|
14
|
+
"2.4.1": {
|
|
15
|
+
"en": "Add support for MINI and a force refresh remote",
|
|
16
|
+
"de": "Support für MINI hinzugefügt und ein Update erzwingen remote"
|
|
17
|
+
},
|
|
18
|
+
"2.3.0": {
|
|
19
|
+
"en": "Disable v1 Endpoints",
|
|
20
|
+
"de": "Deaktivieren v1 Endpunkte wurden entfernt."
|
|
21
|
+
},
|
|
22
|
+
"2.1.2": {
|
|
7
23
|
"en": "Upgrade to statusV2 and remoteV2",
|
|
8
24
|
"de": "Status und Remote Kontrolle auf v2 der neuen BMW App geupdated"
|
|
9
25
|
},
|
|
@@ -64,6 +80,11 @@
|
|
|
64
80
|
"connectionType": "cloud",
|
|
65
81
|
"dataSource": "poll",
|
|
66
82
|
"materialize": true,
|
|
83
|
+
"plugins": {
|
|
84
|
+
"sentry": {
|
|
85
|
+
"dsn": "https://f976d718acc2489fb0e1991d4c8d26a0@sentry.iobroker.net/148"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
67
88
|
"dependencies": [
|
|
68
89
|
{
|
|
69
90
|
"js-controller": ">=3.0.0"
|
package/main.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
// you need to create an adapter
|
|
9
9
|
const utils = require("@iobroker/adapter-core");
|
|
10
10
|
const axios = require("axios");
|
|
11
|
+
|
|
12
|
+
const crypto = require("crypto");
|
|
11
13
|
const qs = require("qs");
|
|
12
14
|
const { extractKeys } = require("./lib/extractKeys");
|
|
13
15
|
const axiosCookieJarSupport = require("axios-cookiejar-support").default;
|
|
@@ -48,15 +50,16 @@ class Bmw extends utils.Adapter {
|
|
|
48
50
|
this.statusBlock = {};
|
|
49
51
|
this.nonChargingHistory = {};
|
|
50
52
|
this.subscribeStates("*");
|
|
51
|
-
|
|
53
|
+
if (!this.config.username || !this.config.password) {
|
|
54
|
+
this.log.error("Please set username and password");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
52
57
|
await this.login();
|
|
53
58
|
if (this.session.access_token) {
|
|
54
59
|
await this.getVehicles();
|
|
55
60
|
await this.cleanObjects();
|
|
56
61
|
await this.getVehiclesv2();
|
|
57
|
-
await this.updateVehicles();
|
|
58
62
|
this.updateInterval = setInterval(async () => {
|
|
59
|
-
await this.updateVehicles();
|
|
60
63
|
await this.getVehiclesv2();
|
|
61
64
|
}, this.config.interval * 60 * 1000);
|
|
62
65
|
this.refreshTokenInterval = setInterval(() => {
|
|
@@ -71,17 +74,21 @@ class Bmw extends utils.Adapter {
|
|
|
71
74
|
"Accept-Language": "de-de",
|
|
72
75
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
73
76
|
};
|
|
77
|
+
const [code_verifier, codeChallenge] = this.getCodeChallenge();
|
|
74
78
|
const data = {
|
|
75
79
|
client_id: "31c357a0-7a1d-4590-aa99-33b97244d048",
|
|
76
80
|
response_type: "code",
|
|
77
81
|
scope: "openid profile email offline_access smacc vehicle_data perseus dlm svds cesim vsapi remote_services fupo authenticate_user",
|
|
78
82
|
redirect_uri: "com.bmw.connected://oauth",
|
|
79
|
-
state: "
|
|
83
|
+
state: "cwU-gIE27j67poy2UcL3KQ",
|
|
80
84
|
nonce: "login_nonce",
|
|
85
|
+
code_challenge_method: "S256",
|
|
86
|
+
code_challenge: codeChallenge,
|
|
81
87
|
username: this.config.username,
|
|
82
88
|
password: this.config.password,
|
|
83
89
|
grant_type: "authorization_code",
|
|
84
90
|
};
|
|
91
|
+
|
|
85
92
|
const authUrl = await this.requestClient({
|
|
86
93
|
method: "post",
|
|
87
94
|
url: "https://customer.bmwgroup.com/gcdm/oauth/authenticate",
|
|
@@ -100,7 +107,13 @@ class Bmw extends utils.Adapter {
|
|
|
100
107
|
this.log.error(JSON.stringify(error.response.data));
|
|
101
108
|
}
|
|
102
109
|
if (error.response && error.response.status === 401) {
|
|
103
|
-
this.log.error("Please check username and password");
|
|
110
|
+
this.log.error("Please check username and password or too many logins in 5 minutes");
|
|
111
|
+
|
|
112
|
+
this.log.error("Start relogin in 5min");
|
|
113
|
+
this.reLoginTimeout && clearTimeout(this.reLoginTimeout);
|
|
114
|
+
this.reLoginTimeout = setTimeout(() => {
|
|
115
|
+
this.login();
|
|
116
|
+
}, 5000 * 60 * 1);
|
|
104
117
|
}
|
|
105
118
|
if (error.response && error.response.status === 400) {
|
|
106
119
|
this.log.error("Please check username and password");
|
|
@@ -153,7 +166,7 @@ class Bmw extends utils.Adapter {
|
|
|
153
166
|
"Accept-Language": "de-de",
|
|
154
167
|
Authorization: "Basic MzFjMzU3YTAtN2ExZC00NTkwLWFhOTktMzNiOTcyNDRkMDQ4OmMwZTMzOTNkLTcwYTItNGY2Zi05ZDNjLTg1MzBhZjY0ZDU1Mg==",
|
|
155
168
|
},
|
|
156
|
-
data: "code=" + code + "&
|
|
169
|
+
data: "code=" + code + "&redirect_uri=com.bmw.connected://oauth&grant_type=authorization_code&code_verifier=" + code_verifier,
|
|
157
170
|
})
|
|
158
171
|
.then((res) => {
|
|
159
172
|
this.log.debug(JSON.stringify(res.data));
|
|
@@ -168,6 +181,17 @@ class Bmw extends utils.Adapter {
|
|
|
168
181
|
}
|
|
169
182
|
});
|
|
170
183
|
}
|
|
184
|
+
getCodeChallenge() {
|
|
185
|
+
let hash = "";
|
|
186
|
+
let result = "";
|
|
187
|
+
const chars = "0123456789abcdef";
|
|
188
|
+
result = "";
|
|
189
|
+
for (let i = 64; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
|
|
190
|
+
hash = crypto.createHash("sha256").update(result).digest("base64");
|
|
191
|
+
hash = hash.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
192
|
+
|
|
193
|
+
return [result, hash];
|
|
194
|
+
}
|
|
171
195
|
async getVehicles() {
|
|
172
196
|
const headers = {
|
|
173
197
|
"Content-Type": "application/json",
|
|
@@ -206,34 +230,6 @@ class Bmw extends utils.Adapter {
|
|
|
206
230
|
native: {},
|
|
207
231
|
});
|
|
208
232
|
|
|
209
|
-
// const remoteArray = [
|
|
210
|
-
// { command: "CHARGE_NOW" },
|
|
211
|
-
// { command: "CLIMATE_NOW" },
|
|
212
|
-
// { command: "DOOR_LOCK" },
|
|
213
|
-
// { command: "DOOR_UNLOCK" },
|
|
214
|
-
// { command: "GET_VEHICLES" },
|
|
215
|
-
// { command: "GET_VEHICLE_STATUS" },
|
|
216
|
-
// { command: "HORN_BLOW" },
|
|
217
|
-
// { command: "LIGHT_FLASH" },
|
|
218
|
-
// { command: "VEHICLE_FINDER" },
|
|
219
|
-
// { command: "CLIMATE_NOW" },
|
|
220
|
-
// { command: "START_CHARGING" },
|
|
221
|
-
// { command: "STOP_CHARGING" },
|
|
222
|
-
// { command: "START_PRECONDITIONING" },
|
|
223
|
-
// ];
|
|
224
|
-
// remoteArray.forEach((remote) => {
|
|
225
|
-
// this.setObjectNotExists(vehicle.vin + ".remote." + remote.command, {
|
|
226
|
-
// type: "state",
|
|
227
|
-
// common: {
|
|
228
|
-
// name: remote.name || "",
|
|
229
|
-
// type: remote.type || "boolean",
|
|
230
|
-
// role: remote.role || "boolean",
|
|
231
|
-
// write: true,
|
|
232
|
-
// read: true,
|
|
233
|
-
// },
|
|
234
|
-
// native: {},
|
|
235
|
-
// });
|
|
236
|
-
// });
|
|
237
233
|
this.extractKeys(this, vehicle.vin + ".general", vehicle);
|
|
238
234
|
}
|
|
239
235
|
})
|
|
@@ -243,76 +239,80 @@ class Bmw extends utils.Adapter {
|
|
|
243
239
|
});
|
|
244
240
|
}
|
|
245
241
|
async getVehiclesv2() {
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
242
|
+
const brands = ["bmw", "mini"];
|
|
243
|
+
for (const brand of brands) {
|
|
244
|
+
const headers = {
|
|
245
|
+
"user-agent": "Dart/2.10 (dart:io)",
|
|
246
|
+
"x-user-agent": "android(v1.07_20200330);" + brand + ";1.5.2(8932)",
|
|
247
|
+
authorization: "Bearer " + this.session.access_token,
|
|
248
|
+
"accept-language": "de-DE",
|
|
249
|
+
host: "cocoapi.bmwgroup.com",
|
|
250
|
+
"24-hour-format": "true",
|
|
251
|
+
};
|
|
254
252
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
for (const vehicle of res.data) {
|
|
264
|
-
await this.setObjectNotExistsAsync(vehicle.vin, {
|
|
265
|
-
type: "device",
|
|
266
|
-
common: {
|
|
267
|
-
name: vehicle.model,
|
|
268
|
-
},
|
|
269
|
-
native: {},
|
|
270
|
-
});
|
|
253
|
+
await this.requestClient({
|
|
254
|
+
method: "get",
|
|
255
|
+
url: "https://cocoapi.bmwgroup.com/eadrax-vcs/v1/vehicles?apptimezone=120&appDateTime=" + Date.now() + "&tireGuardMode=ENABLED",
|
|
256
|
+
headers: headers,
|
|
257
|
+
})
|
|
258
|
+
.then(async (res) => {
|
|
259
|
+
this.log.debug(JSON.stringify(res.data));
|
|
271
260
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
type: "channel",
|
|
281
|
-
common: {
|
|
282
|
-
name: "Remote Controls",
|
|
283
|
-
},
|
|
284
|
-
native: {},
|
|
285
|
-
});
|
|
261
|
+
for (const vehicle of res.data) {
|
|
262
|
+
await this.setObjectNotExistsAsync(vehicle.vin, {
|
|
263
|
+
type: "device",
|
|
264
|
+
common: {
|
|
265
|
+
name: vehicle.model,
|
|
266
|
+
},
|
|
267
|
+
native: {},
|
|
268
|
+
});
|
|
286
269
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
{ command: "door-unlock" },
|
|
290
|
-
{ command: "horn-blow" },
|
|
291
|
-
{ command: "light-flash" },
|
|
292
|
-
{ command: "vehicle-finder" },
|
|
293
|
-
{ command: "climate-now_START" },
|
|
294
|
-
{ command: "climate-now_STOP" },
|
|
295
|
-
];
|
|
296
|
-
remoteArray.forEach((remote) => {
|
|
297
|
-
this.setObjectNotExists(vehicle.vin + ".remotev2." + remote.command, {
|
|
298
|
-
type: "state",
|
|
270
|
+
await this.setObjectNotExistsAsync(vehicle.vin + ".properties", {
|
|
271
|
+
type: "channel",
|
|
299
272
|
common: {
|
|
300
|
-
name:
|
|
301
|
-
type: remote.type || "boolean",
|
|
302
|
-
role: remote.role || "boolean",
|
|
303
|
-
write: true,
|
|
304
|
-
read: true,
|
|
273
|
+
name: "Current status of the car v2",
|
|
305
274
|
},
|
|
306
275
|
native: {},
|
|
307
276
|
});
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
277
|
+
await this.setObjectNotExistsAsync(vehicle.vin + ".remotev2", {
|
|
278
|
+
type: "channel",
|
|
279
|
+
common: {
|
|
280
|
+
name: "Remote Controls",
|
|
281
|
+
},
|
|
282
|
+
native: {},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const remoteArray = [
|
|
286
|
+
{ command: "door-lock" },
|
|
287
|
+
{ command: "door-unlock" },
|
|
288
|
+
{ command: "horn-blow" },
|
|
289
|
+
{ command: "light-flash" },
|
|
290
|
+
{ command: "vehicle-finder" },
|
|
291
|
+
{ command: "climate-now_START" },
|
|
292
|
+
{ command: "climate-now_STOP" },
|
|
293
|
+
{ command: "force-refresh", name: "Force Refresh" },
|
|
294
|
+
];
|
|
295
|
+
remoteArray.forEach((remote) => {
|
|
296
|
+
this.setObjectNotExists(vehicle.vin + ".remotev2." + remote.command, {
|
|
297
|
+
type: "state",
|
|
298
|
+
common: {
|
|
299
|
+
name: remote.name || "",
|
|
300
|
+
type: remote.type || "boolean",
|
|
301
|
+
role: remote.role || "boolean",
|
|
302
|
+
write: true,
|
|
303
|
+
read: true,
|
|
304
|
+
},
|
|
305
|
+
native: {},
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
this.extractKeys(this, vehicle.vin, vehicle, null, true);
|
|
309
|
+
this.updateChargingSessionv2(vehicle.vin);
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
.catch((error) => {
|
|
313
|
+
this.log.error(error);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
316
|
}
|
|
317
317
|
async updateChargingSessionv2(vin) {
|
|
318
318
|
if (this.nonChargingHistory[vin]) {
|
|
@@ -365,7 +365,7 @@ class Bmw extends utils.Adapter {
|
|
|
365
365
|
this.extractKeys(this, vin + element.path + dateFormatted, data);
|
|
366
366
|
})
|
|
367
367
|
.catch((error) => {
|
|
368
|
-
if (error.response && error.response.status === 422) {
|
|
368
|
+
if (error.response && (error.response.status === 422 || error.response.status === 403)) {
|
|
369
369
|
this.log.info("No charging session available. Ignore " + vin);
|
|
370
370
|
this.nonChargingHistory[vin] = true;
|
|
371
371
|
return;
|
|
@@ -376,87 +376,20 @@ class Bmw extends utils.Adapter {
|
|
|
376
376
|
});
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
|
-
async updateVehicles() {
|
|
380
|
-
const date = this.getDate();
|
|
381
379
|
|
|
382
|
-
const statusArray = [
|
|
383
|
-
{ path: "statusv1", url: "https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/$vin/status", desc: "Current status of the car v1" },
|
|
384
|
-
{ path: "chargingprofile", url: "https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/$vin/chargingprofile", desc: "Charging profile of the car v1" },
|
|
385
|
-
{ path: "lastTrip", url: "https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/$vin/statistics/lastTrip", desc: "Last trip of the car v1" },
|
|
386
|
-
{ path: "allTrips", url: "https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/$vin/statistics/allTrips", desc: "All trips of the car v1" },
|
|
387
|
-
{ path: "serviceExecutionHistory", url: "https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/$vin/serviceExecutionHistory", desc: "Remote execution history v1" },
|
|
388
|
-
{ path: "apiV2", url: "https://b2vapi.bmwgroup.com/api/vehicle/v2/$vin", desc: "Limited v2 Api of the car" },
|
|
389
|
-
// { path: "socnavigation", url: "https://b2vapi.bmwgroup.com/api/vehicle/navigation/v1/$vin" },
|
|
390
|
-
];
|
|
391
|
-
|
|
392
|
-
const headers = {
|
|
393
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
394
|
-
Accept: "application/json",
|
|
395
|
-
Authorization: "Bearer " + this.session.access_token,
|
|
396
|
-
};
|
|
397
|
-
this.vinArray.forEach((vin) => {
|
|
398
|
-
statusArray.forEach(async (element) => {
|
|
399
|
-
let url = element.url.replace("$vin", vin);
|
|
400
|
-
if (element.path === "statusv1") {
|
|
401
|
-
if (this.statusBlock[vin]) {
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
url += "?deviceTime=" + date + "&dlat=0&dlon=0";
|
|
405
|
-
}
|
|
406
|
-
await this.requestClient({
|
|
407
|
-
method: "get",
|
|
408
|
-
url: url,
|
|
409
|
-
headers: headers,
|
|
410
|
-
})
|
|
411
|
-
.then((res) => {
|
|
412
|
-
this.log.debug(JSON.stringify(res.data));
|
|
413
|
-
if (!res.data) {
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
let data = res.data;
|
|
417
|
-
const keys = Object.keys(res.data);
|
|
418
|
-
if (keys.length === 1) {
|
|
419
|
-
data = res.data[keys[0]];
|
|
420
|
-
}
|
|
421
|
-
let forceIndex = null;
|
|
422
|
-
const preferedArrayName = null;
|
|
423
|
-
if (element.path === "serviceExecutionHistory") {
|
|
424
|
-
forceIndex = true;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
this.extractKeys(this, vin + "." + element.path, data, preferedArrayName, forceIndex, false, element.desc);
|
|
428
|
-
})
|
|
429
|
-
.catch((error) => {
|
|
430
|
-
if (error.response && error.response.status === 401) {
|
|
431
|
-
error.response && this.log.debug(JSON.stringify(error.response.data));
|
|
432
|
-
this.log.info(element.path + " receive 401 error. Refresh Token in 30 seconds");
|
|
433
|
-
clearTimeout(this.refreshTokenTimeout);
|
|
434
|
-
this.refreshTokenTimeout = setTimeout(() => {
|
|
435
|
-
this.refreshToken();
|
|
436
|
-
}, 1000 * 30);
|
|
437
|
-
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
if (error.response && error.response.status === 404) {
|
|
441
|
-
if (element.path === "statusv1") {
|
|
442
|
-
this.statusBlock[vin] = true;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
this.log.error(url);
|
|
447
|
-
this.log.error(error);
|
|
448
|
-
error.response && this.log.error(JSON.stringify(error.response.data));
|
|
449
|
-
});
|
|
450
|
-
});
|
|
451
|
-
});
|
|
452
|
-
}
|
|
453
380
|
async cleanObjects() {
|
|
454
381
|
for (const vin of this.vinArray) {
|
|
455
|
-
const remoteState = await this.getObjectAsync(vin + ".
|
|
382
|
+
const remoteState = await this.getObjectAsync(vin + ".apiV2");
|
|
456
383
|
|
|
457
384
|
if (remoteState) {
|
|
458
|
-
this.log.debug("clean " + vin);
|
|
385
|
+
this.log.debug("clean old states" + vin);
|
|
386
|
+
await this.delObjectAsync(vin + ".statusv1", { recursive: true });
|
|
387
|
+
await this.delObjectAsync(vin + ".lastTrip", { recursive: true });
|
|
388
|
+
await this.delObjectAsync(vin + ".allTrips", { recursive: true });
|
|
459
389
|
await this.delObjectAsync(vin + ".status", { recursive: true });
|
|
390
|
+
await this.delObjectAsync(vin + ".chargingprofile", { recursive: true });
|
|
391
|
+
await this.delObjectAsync(vin + ".serviceExecutionHistory", { recursive: true });
|
|
392
|
+
await this.delObjectAsync(vin + ".apiV2", { recursive: true });
|
|
460
393
|
await this.delObject(vin + ".remote", { recursive: true });
|
|
461
394
|
await this.delObject("_DatenNeuLaden");
|
|
462
395
|
await this.delObject("_LetzterDatenabrufOK");
|
|
@@ -505,6 +438,7 @@ class Bmw extends utils.Adapter {
|
|
|
505
438
|
this.log.error(error);
|
|
506
439
|
error.response && this.log.error(JSON.stringify(error.response.data));
|
|
507
440
|
this.log.error("Start relogin in 1min");
|
|
441
|
+
this.reLoginTimeout && clearTimeout(this.reLoginTimeout);
|
|
508
442
|
this.reLoginTimeout = setTimeout(() => {
|
|
509
443
|
this.login();
|
|
510
444
|
}, 1000 * 60 * 1);
|
|
@@ -536,16 +470,22 @@ class Bmw extends utils.Adapter {
|
|
|
536
470
|
async onStateChange(id, state) {
|
|
537
471
|
if (state) {
|
|
538
472
|
if (!state.ack) {
|
|
473
|
+
if (id.indexOf(".remotev2.") === -1) {
|
|
474
|
+
this.log.warn("Please use remotev2 to control");
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
539
478
|
const vin = id.split(".")[2];
|
|
540
|
-
const version = id.split(".")[3];
|
|
541
479
|
|
|
542
480
|
let command = id.split(".")[4];
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
this.log.warn("Please use remotev2");
|
|
481
|
+
if (command === "force-refresh") {
|
|
482
|
+
this.log.debug("force refresh");
|
|
483
|
+
this.getVehiclesv2();
|
|
547
484
|
return;
|
|
548
485
|
}
|
|
486
|
+
const action = command.split("_")[1];
|
|
487
|
+
command = command.split("_")[0];
|
|
488
|
+
|
|
549
489
|
const headers = {
|
|
550
490
|
"user-agent": "Dart/2.10 (dart:io)",
|
|
551
491
|
"x-user-agent": "android(v1.07_20200330);bmw;1.5.2(8932)",
|
|
@@ -576,7 +516,6 @@ class Bmw extends utils.Adapter {
|
|
|
576
516
|
}
|
|
577
517
|
});
|
|
578
518
|
this.refreshTimeout = setTimeout(async () => {
|
|
579
|
-
await this.updateVehicles();
|
|
580
519
|
await this.getVehiclesv2();
|
|
581
520
|
}, 10 * 1000);
|
|
582
521
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.bmw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"description": "Adapter for BMW",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TA2k",
|
|
@@ -17,32 +17,31 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@iobroker/adapter-core": "^2.5.1",
|
|
20
|
-
"axios": "^0.
|
|
20
|
+
"axios": "^0.24.0",
|
|
21
21
|
"json-bigint": "^1.0.0",
|
|
22
22
|
"qs": "^6.10.1",
|
|
23
23
|
"axios-cookiejar-support": "^1.0.1",
|
|
24
24
|
"tough-cookie": "^4.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@iobroker/testing": "^2.
|
|
28
|
-
"@types/chai": "^4.2.
|
|
27
|
+
"@iobroker/testing": "^2.5.2",
|
|
28
|
+
"@types/chai": "^4.2.22",
|
|
29
29
|
"@types/chai-as-promised": "^7.1.4",
|
|
30
30
|
"@types/gulp": "^4.0.9",
|
|
31
31
|
"@types/mocha": "^9.0.0",
|
|
32
|
-
"@types/node": "^14.17.
|
|
32
|
+
"@types/node": "^14.17.32",
|
|
33
33
|
"@types/proxyquire": "^1.3.28",
|
|
34
|
-
"@types/sinon": "^10.0.
|
|
34
|
+
"@types/sinon": "^10.0.6",
|
|
35
35
|
"@types/sinon-chai": "^3.2.5",
|
|
36
|
-
"axios": "^0.21.1",
|
|
37
36
|
"chai": "^4.3.4",
|
|
38
37
|
"chai-as-promised": "^7.1.1",
|
|
39
|
-
"eslint": "^
|
|
38
|
+
"eslint": "^8.1.0",
|
|
40
39
|
"gulp": "^4.0.2",
|
|
41
|
-
"mocha": "^9.
|
|
40
|
+
"mocha": "^9.1.3",
|
|
42
41
|
"proxyquire": "^2.1.3",
|
|
43
|
-
"sinon": "^
|
|
42
|
+
"sinon": "^12.0.0",
|
|
44
43
|
"sinon-chai": "^3.7.0",
|
|
45
|
-
"typescript": "
|
|
44
|
+
"typescript": "~4.4.4"
|
|
46
45
|
},
|
|
47
46
|
"main": "main.js",
|
|
48
47
|
"scripts": {
|