iobroker.bmw 2.5.7 → 2.6.0
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/io-package.json +5 -1
- package/main.js +203 -13
- package/package.json +17 -16
package/io-package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "bmw",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.6.0",
|
|
5
5
|
"news": {
|
|
6
|
+
"2.6.0": {
|
|
7
|
+
"en": "Fix Status Updat. New status under bmw.0.VIN.state",
|
|
8
|
+
"de": "Status Update gefixt. Neuer Status unter bmw.0.VIN.state"
|
|
9
|
+
},
|
|
6
10
|
"2.5.7": {
|
|
7
11
|
"en": "Fix Quota problem",
|
|
8
12
|
"de": "Quota Problem es muss jetzt explizit die Marke BMW oder Mini in den Optionen gewählt werden."
|
package/main.js
CHANGED
|
@@ -12,6 +12,7 @@ const axios = require("axios").default;
|
|
|
12
12
|
const { HttpsCookieAgent } = require("http-cookie-agent/http");
|
|
13
13
|
const crypto = require("crypto");
|
|
14
14
|
const qs = require("qs");
|
|
15
|
+
const Json2iob = require("json2iob");
|
|
15
16
|
const { extractKeys } = require("./lib/extractKeys");
|
|
16
17
|
const tough = require("tough-cookie");
|
|
17
18
|
class Bmw extends utils.Adapter {
|
|
@@ -37,6 +38,131 @@ class Bmw extends utils.Adapter {
|
|
|
37
38
|
this.session = {};
|
|
38
39
|
this.statusBlock = {};
|
|
39
40
|
this.nonChargingHistory = {};
|
|
41
|
+
this.json2iob = new Json2iob(this);
|
|
42
|
+
this.description = {
|
|
43
|
+
allTrips: "alle Fahrten des Autos",
|
|
44
|
+
avgCombinedConsumption: "Durchschnittlicher kombinierter Verbrauch",
|
|
45
|
+
communityAverage: "Gesamt Durchschnitt",
|
|
46
|
+
communityHigh: "Gesamt max.",
|
|
47
|
+
communityLow: "Gesamt min.",
|
|
48
|
+
userAverage: "Fahrer Durchschnitt",
|
|
49
|
+
avgElectricConsumption: "Durchschnittlicher elektrischer Verbrauch",
|
|
50
|
+
avgRecuperation: "Durchschnittliche Rekuperation",
|
|
51
|
+
chargecycleRange: "Ladezyklus Reichweite",
|
|
52
|
+
userCurrentChargeCycle: "aktueller Ladezyklus",
|
|
53
|
+
userHigh: "Fahrer max.",
|
|
54
|
+
totalElectricDistance: "gesamte elektrische Distanz",
|
|
55
|
+
batterySizeMax: "max. Batterie Ladeleistung in Wh",
|
|
56
|
+
resetDate: "Werte zur+ckgesetz am",
|
|
57
|
+
savedCO2: "Eingespartes CO2",
|
|
58
|
+
savedCO2greenEnergy: "Eingespartes CO2 grüne Energie",
|
|
59
|
+
totalSavedFuel: "Gesamt gesparter Kraftstoff",
|
|
60
|
+
apiV2: "limitierte v2 Api des Autos",
|
|
61
|
+
basicType: "Grundtyp",
|
|
62
|
+
bodyType: "Fahrzeugtyp",
|
|
63
|
+
brand: "Marke",
|
|
64
|
+
modelName: "Model Name",
|
|
65
|
+
series: "Serie",
|
|
66
|
+
vin: "Fahrzeugidentifikationsnummer",
|
|
67
|
+
chargingprofile: "Ladeprofil",
|
|
68
|
+
overrideTimer: "Einmalige Abfahrtszeit",
|
|
69
|
+
weekdays: "Wochentag",
|
|
70
|
+
departureTime: "Abfahrtszeit",
|
|
71
|
+
timerEnabled: "Timer Aktiviert",
|
|
72
|
+
preferredChargingWindow: "Tägliches Ladefenster",
|
|
73
|
+
endTime: "Ende Uhrzeit",
|
|
74
|
+
startTime: "Start Uhrzeit",
|
|
75
|
+
MONDAY: "Montag",
|
|
76
|
+
TUESDAY: "Dienstag",
|
|
77
|
+
WEDNESDAY: "Mittwoch",
|
|
78
|
+
THURSDAY: "Donnerstag",
|
|
79
|
+
FRIDAY: "Freitag",
|
|
80
|
+
SATURDAY: "Samstag",
|
|
81
|
+
SUNDAY: "Sonntag",
|
|
82
|
+
chargingMode: "Lademodus",
|
|
83
|
+
chargingPreferences: "Ladeeinstellungen",
|
|
84
|
+
climatizationEnabled: "Klimatisierung Aktiviert",
|
|
85
|
+
general: "Allgemeine Fahrzeuginformationen",
|
|
86
|
+
dealer: "Händler",
|
|
87
|
+
city: "Stadt",
|
|
88
|
+
country: "Land",
|
|
89
|
+
phone: "Telefon",
|
|
90
|
+
postalCode: "Postleitzahl",
|
|
91
|
+
street: "Straße",
|
|
92
|
+
supportedChargingModes: "unterstützte Lademodi",
|
|
93
|
+
accelerationValue: "Beschleunigungs Wert",
|
|
94
|
+
anticipationValue: "Erwartungswert",
|
|
95
|
+
auxiliaryConsumptionValue: "Hilfsverbrauchswert",
|
|
96
|
+
date: "Datum",
|
|
97
|
+
drivingModeValue: "Fahrmodus",
|
|
98
|
+
duration: "Dauer",
|
|
99
|
+
efficiencyValue: "Effizienz Wert",
|
|
100
|
+
electricDistance: "elektrische Distanz",
|
|
101
|
+
electricDistanceRatio: "elektrisches Distanzverhältnis in %",
|
|
102
|
+
savedFuel: "Eingesparter Kraftstoff",
|
|
103
|
+
totalConsumptionValue: "Gesamtverbrauchswert",
|
|
104
|
+
totalDistance: "Gesamtstrecke",
|
|
105
|
+
rangemap: "Reichweitenkarte",
|
|
106
|
+
center: "Mitte",
|
|
107
|
+
remote: "Fernbedienung",
|
|
108
|
+
CHARGE_NOW: "jetzt Aufladen",
|
|
109
|
+
CLIMATE_NOW: "Klimatisierung starten",
|
|
110
|
+
DOOR_LOCK: "Autotüren zusperren",
|
|
111
|
+
DOOR_UNLOCK: "Autotüren aufsperren",
|
|
112
|
+
GET_VEHICLES: "Fahrzeuginformationen abrufen",
|
|
113
|
+
GET_VEHICLE_STATUS: "Fahrzeug Status abrufen",
|
|
114
|
+
HORN_BLOW: "Hupe einschalten",
|
|
115
|
+
LIGHT_FLASH: "Lichthupe einschalten",
|
|
116
|
+
START_CHARGING: "Laden starten",
|
|
117
|
+
START_PRECONDITIONING: "Startvoraussetzung",
|
|
118
|
+
STOP_CHARGING: "Laden stoppen",
|
|
119
|
+
VEHICLE_FINDER: "Positionsdaten Fahrzeug abrufen",
|
|
120
|
+
serviceExecutionHistory: "Verlauf der Remote-Ausführung",
|
|
121
|
+
status: "Aktueller Status",
|
|
122
|
+
BRAKE_FLUID: "Bremsflüssigkeit",
|
|
123
|
+
cbsDescription: "Service Beschreibung",
|
|
124
|
+
cbsDueDate: "Service Fälligkeitsdatum",
|
|
125
|
+
cbsState: "Service Status",
|
|
126
|
+
cbsType: "Service Art",
|
|
127
|
+
VEHICLE_CHECK: "Fahrzeug Überprüfung",
|
|
128
|
+
position: "Position",
|
|
129
|
+
heading: "Richtung",
|
|
130
|
+
lat: "Latitude",
|
|
131
|
+
lon: "Longitude",
|
|
132
|
+
DCS_CCH_Activation: "DCS CCH Aktivierung",
|
|
133
|
+
DCS_CCH_Ongoing: "DCS CHH Laufend",
|
|
134
|
+
chargingConnectionType: "Ladeverbindungstyp",
|
|
135
|
+
chargingInductivePositioning: "Aufladen Induktive Positionierung",
|
|
136
|
+
chargingLevelHv: "Batterie SoC in %",
|
|
137
|
+
chargingStatus: "Ladestatus",
|
|
138
|
+
chargingTimeRemaining: "Verbleibende Ladezeit",
|
|
139
|
+
connectionStatus: "Verbindungsstatus Ladestecker",
|
|
140
|
+
doorDriverFront: "Fahrertüren",
|
|
141
|
+
driverFront: "Fahrertüren",
|
|
142
|
+
doorDriverRear: "Hintere Türe Fahrerseite",
|
|
143
|
+
doorLockState: "Fahrzeug Verriegelungszustand Türen und Fenster",
|
|
144
|
+
doorPassengerFront: "Beifahrertüre",
|
|
145
|
+
doorPassengerRear: "Hintere Türe Beifahrerseite",
|
|
146
|
+
hood: "Motorhaube",
|
|
147
|
+
internalDataTimeUTC: "Fahrzeugzeit UTC",
|
|
148
|
+
lastChargingEndReason: "letzter Grund für das Ende des Ladevorgangs",
|
|
149
|
+
lastChargingEndResult: "letztes Ladeendergebnis",
|
|
150
|
+
maxRangeElectric: "max. elektrische Reichweite in km",
|
|
151
|
+
maxRangeElectricMls: "max. elektrische Reichweite in mi",
|
|
152
|
+
mileage: "Kilometerstand",
|
|
153
|
+
remainingFuel: "Tankinhalt",
|
|
154
|
+
remainingRangeElectric: "restliche Reichweite Elektrisch in km",
|
|
155
|
+
remainingRangeElectricMls: "restliche Reichweite Elektrisch in mi",
|
|
156
|
+
remainingRangeFuel: "restliche Reichweite Kraftstoff in km",
|
|
157
|
+
remainingRangeFuelMls: "restliche Reichweite Kraftstoff in mi",
|
|
158
|
+
singleImmediateCharging: "einmalige Sofortaufladung",
|
|
159
|
+
trunk: "Kofferraum",
|
|
160
|
+
updateReason: "Aktualisierungsgrund",
|
|
161
|
+
updateTime: "Aktualisierungszeit",
|
|
162
|
+
vehicleCountry: "Fahrzeug Land",
|
|
163
|
+
windowDriverFront: "Fenster Fahrerseite",
|
|
164
|
+
windowPassengerFront: "Fenster Beifahrerseite",
|
|
165
|
+
};
|
|
40
166
|
this.cookieJar = new tough.CookieJar(null, { ignoreError: true });
|
|
41
167
|
|
|
42
168
|
this.requestClient = axios.create({
|
|
@@ -64,12 +190,13 @@ class Bmw extends utils.Adapter {
|
|
|
64
190
|
await this.login();
|
|
65
191
|
if (this.session.access_token) {
|
|
66
192
|
// await this.getVehicles(); //old depracted api
|
|
67
|
-
await this.cleanObjects();
|
|
68
193
|
|
|
69
194
|
this.log.info(`Start getting ${this.config.brand} vehicles`);
|
|
70
|
-
await this.getVehiclesv2();
|
|
195
|
+
await this.getVehiclesv2(true);
|
|
196
|
+
await this.cleanObjects();
|
|
197
|
+
await this.updateDevices();
|
|
71
198
|
this.updateInterval = setInterval(async () => {
|
|
72
|
-
await this.
|
|
199
|
+
await this.updateDevices();
|
|
73
200
|
}, this.config.interval * 60 * 1000);
|
|
74
201
|
this.refreshTokenInterval = setInterval(() => {
|
|
75
202
|
this.refreshToken();
|
|
@@ -233,6 +360,7 @@ class Bmw extends utils.Adapter {
|
|
|
233
360
|
// },
|
|
234
361
|
// native: {},
|
|
235
362
|
// });
|
|
363
|
+
|
|
236
364
|
await this.setObjectNotExistsAsync(vehicle.vin + ".general", {
|
|
237
365
|
type: "channel",
|
|
238
366
|
common: {
|
|
@@ -250,7 +378,7 @@ class Bmw extends utils.Adapter {
|
|
|
250
378
|
error.response && this.log.error(JSON.stringify(error.response.data));
|
|
251
379
|
});
|
|
252
380
|
}
|
|
253
|
-
async getVehiclesv2() {
|
|
381
|
+
async getVehiclesv2(firstStart) {
|
|
254
382
|
const brand = this.config.brand;
|
|
255
383
|
const headers = {
|
|
256
384
|
"user-agent": this.userAgentDart,
|
|
@@ -263,17 +391,20 @@ class Bmw extends utils.Adapter {
|
|
|
263
391
|
|
|
264
392
|
await this.requestClient({
|
|
265
393
|
method: "get",
|
|
266
|
-
url: "https://cocoapi.bmwgroup.com/eadrax-vcs/
|
|
394
|
+
url: "https://cocoapi.bmwgroup.com/eadrax-vcs/v4/vehicles?apptimezone=120&appDateTime=" + Date.now() + "&tireGuardMode=ENABLED",
|
|
267
395
|
headers: headers,
|
|
268
396
|
})
|
|
269
397
|
.then(async (res) => {
|
|
270
398
|
this.log.debug(JSON.stringify(res.data));
|
|
271
|
-
|
|
399
|
+
if (firstStart) {
|
|
400
|
+
this.log.info(`Found ${res.data.length} ${brand} vehicles`);
|
|
401
|
+
}
|
|
272
402
|
if (res.data.length === 0) {
|
|
273
403
|
this.log.info(`No ${brand} vehicles found please check brand in instance settings`);
|
|
274
404
|
return;
|
|
275
405
|
}
|
|
276
406
|
for (const vehicle of res.data) {
|
|
407
|
+
this.vinArray.push(vehicle.vin);
|
|
277
408
|
await this.setObjectNotExistsAsync(vehicle.vin, {
|
|
278
409
|
type: "device",
|
|
279
410
|
common: {
|
|
@@ -281,11 +412,10 @@ class Bmw extends utils.Adapter {
|
|
|
281
412
|
},
|
|
282
413
|
native: {},
|
|
283
414
|
});
|
|
284
|
-
|
|
285
|
-
await this.setObjectNotExistsAsync(vehicle.vin + ".properties", {
|
|
415
|
+
await this.setObjectNotExistsAsync(vehicle.vin + ".state", {
|
|
286
416
|
type: "channel",
|
|
287
417
|
common: {
|
|
288
|
-
name: "Current status of the car
|
|
418
|
+
name: "Current status of the car v4",
|
|
289
419
|
},
|
|
290
420
|
native: {},
|
|
291
421
|
});
|
|
@@ -320,7 +450,12 @@ class Bmw extends utils.Adapter {
|
|
|
320
450
|
native: {},
|
|
321
451
|
});
|
|
322
452
|
});
|
|
323
|
-
this.extractKeys(this, vehicle.vin, vehicle, null, true);
|
|
453
|
+
// this.extractKeys(this, vehicle.vin, vehicle, null, true);
|
|
454
|
+
this.json2iob.parse(vehicle.vin, vehicle, {
|
|
455
|
+
forceIndex: true,
|
|
456
|
+
descriptions: this.description,
|
|
457
|
+
});
|
|
458
|
+
|
|
324
459
|
await this.sleep(5000);
|
|
325
460
|
this.updateChargingSessionv2(vehicle.vin);
|
|
326
461
|
}
|
|
@@ -332,6 +467,36 @@ class Bmw extends utils.Adapter {
|
|
|
332
467
|
});
|
|
333
468
|
await this.sleep(5000);
|
|
334
469
|
}
|
|
470
|
+
async updateDevices() {
|
|
471
|
+
const brand = this.config.brand;
|
|
472
|
+
const headers = {
|
|
473
|
+
"user-agent": this.userAgentDart,
|
|
474
|
+
"x-user-agent": this.xuserAgent.replace(";brand;", `;${brand};`),
|
|
475
|
+
authorization: "Bearer " + this.session.access_token,
|
|
476
|
+
"accept-language": "de-DE",
|
|
477
|
+
host: "cocoapi.bmwgroup.com",
|
|
478
|
+
"24-hour-format": "true",
|
|
479
|
+
};
|
|
480
|
+
for (const vin of this.vinArray) {
|
|
481
|
+
this.log.debug("update " + vin);
|
|
482
|
+
headers["bmw-vin"] = vin;
|
|
483
|
+
await this.requestClient({
|
|
484
|
+
method: "get",
|
|
485
|
+
url:
|
|
486
|
+
"https://cocoapi.bmwgroup.com/eadrax-vcs/v4/vehicles/state?apptimezone=120&appDateTime=" + Date.now() + "&tireGuardMode=ENABLED",
|
|
487
|
+
headers: headers,
|
|
488
|
+
})
|
|
489
|
+
.then(async (res) => {
|
|
490
|
+
this.log.debug(JSON.stringify(res.data));
|
|
491
|
+
this.json2iob.parse(vin, res.data, { forceIndex: true, descriptions: this.description });
|
|
492
|
+
})
|
|
493
|
+
.catch((error) => {
|
|
494
|
+
this.log.error("update failed");
|
|
495
|
+
this.log.error(error);
|
|
496
|
+
error.response && this.log.error(JSON.stringify(error.response.data));
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
335
500
|
sleep(ms) {
|
|
336
501
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
337
502
|
}
|
|
@@ -369,7 +534,7 @@ class Bmw extends utils.Adapter {
|
|
|
369
534
|
urlArray.push({
|
|
370
535
|
url: "https://cocoapi.bmwgroup.com/eadrax-chs/v1/charging-statistics?vin=" + vin + "¤tDate=" + fullDate,
|
|
371
536
|
path: ".charging-statistics.",
|
|
372
|
-
name: "
|
|
537
|
+
name: "charging statistics",
|
|
373
538
|
});
|
|
374
539
|
for (const element of urlArray) {
|
|
375
540
|
await this.requestClient({
|
|
@@ -390,8 +555,31 @@ class Bmw extends utils.Adapter {
|
|
|
390
555
|
},
|
|
391
556
|
native: {},
|
|
392
557
|
});
|
|
558
|
+
await this.extractKeys(this, vin + element.path + dateFormatted, data);
|
|
393
559
|
|
|
394
|
-
|
|
560
|
+
if (element.name === "chargingSessions" && data.sessions && data.sessions.length > 0) {
|
|
561
|
+
try {
|
|
562
|
+
const datal = data.sessions[0];
|
|
563
|
+
datal._date = datal.id.split("_")[0];
|
|
564
|
+
datal._id = datal.id.split("_")[1];
|
|
565
|
+
datal.timestamp = new Date(datal._date).valueOf();
|
|
566
|
+
if (datal.energyCharged.replace) {
|
|
567
|
+
datal.energy = datal.energyCharged.replace("~", "").trim().split(" ")[0];
|
|
568
|
+
datal.unit = datal.energyCharged.replace("~", "").trim().split(" ")[1];
|
|
569
|
+
}
|
|
570
|
+
datal.id = "latest";
|
|
571
|
+
await this.setObjectNotExistsAsync(vin + element.path + "latest", {
|
|
572
|
+
type: "channel",
|
|
573
|
+
common: {
|
|
574
|
+
name: element.name + "latest of the car v2",
|
|
575
|
+
},
|
|
576
|
+
native: {},
|
|
577
|
+
});
|
|
578
|
+
await this.extractKeys(this, vin + element.path + "latest", datal);
|
|
579
|
+
} catch (error) {
|
|
580
|
+
this.log.debug(error);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
395
583
|
})
|
|
396
584
|
.catch((error) => {
|
|
397
585
|
if (error.response) {
|
|
@@ -409,7 +597,7 @@ class Bmw extends utils.Adapter {
|
|
|
409
597
|
|
|
410
598
|
async cleanObjects() {
|
|
411
599
|
for (const vin of this.vinArray) {
|
|
412
|
-
const remoteState = await this.getObjectAsync(vin + ".
|
|
600
|
+
const remoteState = await this.getObjectAsync(vin + ".properties");
|
|
413
601
|
|
|
414
602
|
if (remoteState) {
|
|
415
603
|
this.log.debug("clean old states" + vin);
|
|
@@ -417,6 +605,8 @@ class Bmw extends utils.Adapter {
|
|
|
417
605
|
await this.delObjectAsync(vin + ".lastTrip", { recursive: true });
|
|
418
606
|
await this.delObjectAsync(vin + ".allTrips", { recursive: true });
|
|
419
607
|
await this.delObjectAsync(vin + ".status", { recursive: true });
|
|
608
|
+
await this.delObjectAsync(vin + ".properties", { recursive: true });
|
|
609
|
+
await this.delObjectAsync(vin + ".capabilities", { recursive: true });
|
|
420
610
|
await this.delObjectAsync(vin + ".chargingprofile", { recursive: true });
|
|
421
611
|
await this.delObjectAsync(vin + ".serviceExecutionHistory", { recursive: true });
|
|
422
612
|
await this.delObjectAsync(vin + ".apiV2", { recursive: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.bmw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Adapter for BMW",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TA2k",
|
|
@@ -16,30 +16,31 @@
|
|
|
16
16
|
"url": "https://github.com/TA2k/ioBroker.bmw"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@iobroker/adapter-core": "^2.6.
|
|
20
|
-
"axios": "^
|
|
21
|
-
"http-cookie-agent": "^
|
|
19
|
+
"@iobroker/adapter-core": "^2.6.8",
|
|
20
|
+
"axios": "^1.4.0",
|
|
21
|
+
"http-cookie-agent": "^5.0.4",
|
|
22
22
|
"json-bigint": "^1.0.0",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
23
|
+
"json2iob": "^2.4.4",
|
|
24
|
+
"qs": "^6.11.2",
|
|
25
|
+
"tough-cookie": "^4.1.3"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"@iobroker/testing": "^4.1.0",
|
|
28
|
-
"@types/chai": "^4.3.
|
|
29
|
+
"@types/chai": "^4.3.5",
|
|
29
30
|
"@types/chai-as-promised": "^7.1.5",
|
|
30
|
-
"@types/mocha": "^
|
|
31
|
-
"@types/node": "^18.
|
|
31
|
+
"@types/mocha": "^10.0.1",
|
|
32
|
+
"@types/node": "^18.16.18",
|
|
32
33
|
"@types/proxyquire": "^1.3.28",
|
|
33
|
-
"@types/sinon": "^10.0.
|
|
34
|
-
"@types/sinon-chai": "^3.2.
|
|
35
|
-
"chai": "^4.3.
|
|
34
|
+
"@types/sinon": "^10.0.15",
|
|
35
|
+
"@types/sinon-chai": "^3.2.9",
|
|
36
|
+
"chai": "^4.3.7",
|
|
36
37
|
"chai-as-promised": "^7.1.1",
|
|
37
|
-
"eslint": "^8.
|
|
38
|
-
"mocha": "^10.
|
|
38
|
+
"eslint": "^8.43.0",
|
|
39
|
+
"mocha": "^10.2.0",
|
|
39
40
|
"proxyquire": "^2.1.3",
|
|
40
|
-
"sinon": "^
|
|
41
|
+
"sinon": "^15.2.0",
|
|
41
42
|
"sinon-chai": "^3.7.0",
|
|
42
|
-
"typescript": "^
|
|
43
|
+
"typescript": "^5.1.6"
|
|
43
44
|
},
|
|
44
45
|
"main": "main.js",
|
|
45
46
|
"scripts": {
|