iobroker.bmw 2.8.0 → 2.8.2

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 CHANGED
@@ -25,10 +25,13 @@ bmw.0.VIN.properties
25
25
  bmw.0.VIN.remotev2
26
26
 
27
27
  ## Changelog
28
+ ### 2.8.2 (2024-10-05)
28
29
 
29
- ### 2,8.0
30
+ - fix error getvehicles v2 failed
30
31
 
31
- - Add support service demand and trip api
32
+ ### 2.8.1 (2024-09-30)
33
+
34
+ - fix remote commands
32
35
 
33
36
  ### 2.7.1
34
37
 
@@ -1,101 +1,108 @@
1
1
  <html>
2
- <head>
3
- <!-- Load ioBroker scripts and styles-->
4
- <link rel="stylesheet" type="text/css" href="../../css/adapter.css" />
5
- <link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css" />
2
+ <head>
3
+ <!-- Load ioBroker scripts and styles-->
4
+ <link rel="stylesheet" type="text/css" href="../../css/adapter.css" />
5
+ <link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css" />
6
6
 
7
- <script type="text/javascript" src="../../lib/js/jquery-3.2.1.min.js"></script>
8
- <script type="text/javascript" src="../../socket.io/socket.io.js"></script>
7
+ <script type="text/javascript" src="../../lib/js/jquery-3.2.1.min.js"></script>
8
+ <script type="text/javascript" src="../../socket.io/socket.io.js"></script>
9
9
 
10
- <script type="text/javascript" src="../../js/translate.js"></script>
11
- <script type="text/javascript" src="../../lib/js/materialize.js"></script>
12
- <script type="text/javascript" src="../../js/adapter-settings.js"></script>
10
+ <script type="text/javascript" src="../../js/translate.js"></script>
11
+ <script type="text/javascript" src="../../lib/js/materialize.js"></script>
12
+ <script type="text/javascript" src="../../js/adapter-settings.js"></script>
13
13
 
14
- <!-- Load our own files -->
15
- <link rel="stylesheet" type="text/css" href="style.css" />
16
- <script type="text/javascript" src="words.js"></script>
14
+ <!-- Load our own files -->
15
+ <link rel="stylesheet" type="text/css" href="style.css" />
16
+ <script type="text/javascript" src="words.js"></script>
17
17
 
18
- <script type="text/javascript">
19
- // This will be called by the admin adapter when the settings page loads
20
- function load(settings, onChange) {
21
- // example: select elements with id=key and class=value and insert value
22
- if (!settings) return;
23
- $(".value").each(function () {
24
- var $key = $(this);
25
- var id = $key.attr("id");
26
- if ($key.attr("type") === "checkbox") {
27
- // do not call onChange direct, because onChange could expect some arguments
28
- $key.prop("checked", settings[id]).on("change", () => onChange());
29
- } else {
30
- // do not call onChange direct, because onChange could expect some arguments
31
- $key.val(settings[id])
32
- .on("change", () => onChange())
33
- .on("keyup", () => onChange());
34
- }
35
- });
36
- onChange(false);
37
- // reinitialize all the Materialize labels on the page if you are dynamically adding inputs:
38
- if (M) M.updateTextFields();
39
- }
18
+ <script type="text/javascript">
19
+ // This will be called by the admin adapter when the settings page loads
20
+ function load(settings, onChange) {
21
+ // example: select elements with id=key and class=value and insert value
22
+ if (!settings) return;
23
+ $('.value').each(function () {
24
+ var $key = $(this);
25
+ var id = $key.attr('id');
26
+ if ($key.attr('type') === 'checkbox') {
27
+ // do not call onChange direct, because onChange could expect some arguments
28
+ $key.prop('checked', settings[id]).on('change', () => onChange());
29
+ } else {
30
+ // do not call onChange direct, because onChange could expect some arguments
31
+ $key
32
+ .val(settings[id])
33
+ .on('change', () => onChange())
34
+ .on('keyup', () => onChange());
35
+ }
36
+ });
37
+ onChange(false);
38
+ // reinitialize all the Materialize labels on the page if you are dynamically adding inputs:
39
+ if (M) M.updateTextFields();
40
+ }
40
41
 
41
- // This will be called by the admin adapter when the user presses the save button
42
- function save(callback) {
43
- // example: select elements with class=value and build settings object
44
- var obj = {};
45
- $(".value").each(function () {
46
- var $this = $(this);
47
- if ($this.attr("type") === "checkbox") {
48
- obj[$this.attr("id")] = $this.prop("checked");
49
- } else if ($this.attr("type") === "number") {
50
- obj[$this.attr("id")] = parseFloat($this.val());
51
- } else {
52
- obj[$this.attr("id")] = $this.val();
53
- }
54
- });
55
- callback(obj);
56
- }
57
- </script>
58
- </head>
42
+ // This will be called by the admin adapter when the user presses the save button
43
+ function save(callback) {
44
+ // example: select elements with class=value and build settings object
45
+ var obj = {};
46
+ $('.value').each(function () {
47
+ var $this = $(this);
48
+ if ($this.attr('type') === 'checkbox') {
49
+ obj[$this.attr('id')] = $this.prop('checked');
50
+ } else if ($this.attr('type') === 'number') {
51
+ obj[$this.attr('id')] = parseFloat($this.val());
52
+ } else {
53
+ obj[$this.attr('id')] = $this.val();
54
+ }
55
+ });
56
+ callback(obj);
57
+ }
58
+ </script>
59
+ </head>
59
60
 
60
- <body>
61
- <div class="m adapter-container">
62
- <div class="row">
63
- <div class="col s12 m4 l2">
64
- <img src="bmw.png" class="logo" />
65
- </div>
66
- </div>
61
+ <body>
62
+ <div class="m adapter-container">
63
+ <div class="row">
64
+ <div class="col s12 m4 l2">
65
+ <img src="bmw.png" class="logo" />
66
+ </div>
67
+ </div>
67
68
 
68
- <!-- Put your content here -->
69
+ <!-- Put your content here -->
69
70
 
70
- <!-- For example columns with settings: -->
71
- <div class="row">
72
- <div class="col s6 input-field">
73
- <input type="text" class="value" id="username" />
74
- <label for="username" class="translate">App Email</label>
75
- </div>
76
- </div>
77
- <div class="row">
78
- <div class="col s6 input-field">
79
- <input type="password" class="value" id="password" />
80
- <label for="password" class="translate">App Password</label>
81
- </div>
82
- </div>
83
- <div class="row">
84
- <div class="col s2 input-field">
85
- <select id="brand" class="value">
86
- <option value="bmw">BMW</option>
87
- <option value="mini">Mini</option>
88
- </select>
89
- <label for="brand" class="translate">Brand</label>
90
- </div>
91
- </div>
71
+ <!-- For example columns with settings: -->
72
+ <div class="row">
73
+ <div class="col s6 input-field">
74
+ <input type="text" class="value" id="username" />
75
+ <label for="username" class="translate">App Email</label>
76
+ </div>
77
+ </div>
78
+ <div class="row">
79
+ <div class="col s6 input-field">
80
+ <input type="password" class="value" id="password" />
81
+ <label for="password" class="translate">App Password</label>
82
+ </div>
83
+ </div>
84
+ <div class="row">
85
+ <div class="col s2 input-field">
86
+ <select id="brand" class="value">
87
+ <option value="bmw">BMW</option>
88
+ <option value="mini">Mini</option>
89
+ </select>
90
+ <label for="brand" class="translate">Brand</label>
91
+ </div>
92
+ </div>
92
93
 
93
- <div class="row">
94
- <div class="col s2 input-field">
95
- <input type="number" class="value" id="interval" />
96
- <label for="interval" class="translate">Update interval (in minutes)"</label>
97
- </div>
98
- </div>
94
+ <div class="row">
95
+ <div class="col s2 input-field">
96
+ <input type="number" class="value" id="interval" />
97
+ <label for="interval" class="translate">Update interval (in minutes)"</label>
98
+ </div>
99
+ </div>
100
+ <div class="row">
101
+ <div class="col s6 input-field">
102
+ <input type="text" class="value" id="ignorelist" />
103
+ <label for="ignorelist" class="translate">VIN Ignore List</label>
99
104
  </div>
100
- </body>
105
+ </div>
106
+ </div>
107
+ </body>
101
108
  </html>
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "bmw",
4
- "version": "2.8.0",
4
+ "version": "2.8.2",
5
5
  "news": {
6
+ "2.8.2": {
7
+ "en": "fix error getvehicles v2 failed",
8
+ "de": "fehlerbehebung v2 versagt",
9
+ "ru": "ошибка фиксации",
10
+ "pt": "corrigir erro getvehicles v2 falhou",
11
+ "nl": "fix error get vehicles v2 is mislukt",
12
+ "fr": "erreur de correction getvéhicules v2 échoué",
13
+ "it": "errore di correzione getvehicles v2 guasto",
14
+ "es": "error de corrección getvehicles v2 fallado",
15
+ "pl": "naprawić błąd getvehicles v2 nie powiodło się",
16
+ "uk": "виправлення помилок getvehicles v2 не вдалося",
17
+ "zh-cn": "修补错误获得车辆 v2 失败"
18
+ },
19
+ "2.8.1": {
20
+ "en": "fix for remote commands",
21
+ "de": "Fix für Remote Commands",
22
+ "ru": "фиксация удаленных команд",
23
+ "pt": "corrigir comandos remotos",
24
+ "nl": "fix remote commando's",
25
+ "fr": "correction des commandes distantes",
26
+ "it": "correggere i comandi remoti",
27
+ "es": "fijar comandos remotos",
28
+ "pl": "naprawianie zdalnych poleceń",
29
+ "uk": "фіксувати віддалені команди",
30
+ "zh-cn": "修正远程命令"
31
+ },
6
32
  "2.8.0": {
7
33
  "en": "Add support service demand and trip api",
8
34
  "de": "Support für Service und Trips API hinzugefügt"
@@ -22,61 +48,6 @@
22
48
  "2.6.2": {
23
49
  "en": "Fix Charging response parsing",
24
50
  "de": "Fix Charging Antwort Verarbeitung"
25
- },
26
- "2.6.1": {
27
- "en": "Fix Status Update. New status under bmw.0.VIN.state",
28
- "de": "Status Update gefixt. Neuer Status unter bmw.0.VIN.state"
29
- },
30
- "2.5.7": {
31
- "en": "Fix Quota problem",
32
- "de": "Quota Problem es muss jetzt explizit die Marke BMW oder Mini in den Optionen gewählt werden."
33
- },
34
- "2.5.6": {
35
- "en": "Fix charging message"
36
- },
37
- "2.5.5": {
38
- "en": "Fix login"
39
- },
40
- "2.5.4": {
41
- "en": "Fix login"
42
- },
43
- "2.5.3": {
44
- "en": "Fix login"
45
- },
46
- "2.5.2": {
47
- "en": "Bugfixes"
48
- },
49
- "2.5.1": {
50
- "en": "Add login error message",
51
- "de": "Loginproblem Nachricht hinzugefügt"
52
- },
53
- "2.5.0": {
54
- "en": "Fix Login",
55
- "de": "Loginproblem behoben"
56
- },
57
- "2.4.1": {
58
- "en": "Add support for MINI and a force refresh remote",
59
- "de": "Support für MINI hinzugefügt und ein Update erzwingen remote"
60
- },
61
- "2.3.0": {
62
- "en": "Disable v1 Endpoints",
63
- "de": "Deaktivieren v1 Endpunkte wurden entfernt."
64
- },
65
- "2.1.2": {
66
- "en": "Upgrade to statusV2 and remoteV2",
67
- "de": "Status und Remote Kontrolle auf v2 der neuen BMW App geupdated"
68
- },
69
- "2.0.0": {
70
- "en": "initial release",
71
- "de": "Erstveröffentlichung",
72
- "ru": "Начальная версия",
73
- "pt": "lançamento inicial",
74
- "nl": "Eerste uitgave",
75
- "fr": "Première version",
76
- "it": "Versione iniziale",
77
- "es": "Versión inicial",
78
- "pl": "Pierwsze wydanie",
79
- "zh-cn": "首次出版"
80
51
  }
81
52
  },
82
53
  "titleLang": {
@@ -105,8 +76,12 @@
105
76
  "uk": "Adapter for BMW",
106
77
  "zh-cn": "宝马适配器"
107
78
  },
108
- "authors": ["TA2k <tombox2020@gmail.com>"],
109
- "keywords": ["BMW"],
79
+ "authors": [
80
+ "TA2k <tombox2020@gmail.com>"
81
+ ],
82
+ "keywords": [
83
+ "BMW"
84
+ ],
110
85
  "license": "MIT",
111
86
  "platform": "Javascript/Node.js",
112
87
  "main": "main.js",
@@ -137,13 +112,18 @@
137
112
  }
138
113
  ]
139
114
  },
140
- "encryptedNative": ["password"],
141
- "protectedNative": ["password"],
115
+ "encryptedNative": [
116
+ "password"
117
+ ],
118
+ "protectedNative": [
119
+ "password"
120
+ ],
142
121
  "native": {
143
122
  "username": "",
144
123
  "password": "",
145
124
  "interval": 5,
146
- "brand": "bmw"
125
+ "brand": "bmw",
126
+ "ignorelist": ""
147
127
  },
148
128
  "objects": [],
149
129
  "instanceObjects": [
package/main.js CHANGED
@@ -187,6 +187,7 @@ class Bmw extends utils.Adapter {
187
187
  return;
188
188
  }
189
189
  await this.login();
190
+
190
191
  if (this.session.access_token) {
191
192
  this.log.info(`Start getting ${this.config.brand} vehicles`);
192
193
  await this.getVehiclesv2(true);
@@ -195,20 +196,29 @@ class Bmw extends utils.Adapter {
195
196
  await this.updateDemands();
196
197
  await this.sleep(5000);
197
198
  await this.updateTrips();
198
- this.updateInterval = setInterval(async () => {
199
- await this.sleep(2000);
200
- await this.updateDevices();
201
- }, this.config.interval * 60 * 1000);
202
- this.demandInterval = setInterval(async () => {
203
- await this.sleep(2000);
204
- await this.updateDemands();
205
- await this.sleep(5000);
206
- await this.updateTrips();
207
- }, 24 * 60 * 60 * 1000);
208
- this.refreshTokenInterval = setInterval(async () => {
209
- await this.refreshToken();
210
- await this.sleep(5000);
211
- }, (this.session.expires_in - 123) * 1000);
199
+ this.updateInterval = setInterval(
200
+ async () => {
201
+ await this.sleep(2000);
202
+ await this.updateDevices();
203
+ },
204
+ this.config.interval * 60 * 1000,
205
+ );
206
+ this.demandInterval = setInterval(
207
+ async () => {
208
+ await this.sleep(2000);
209
+ await this.updateDemands();
210
+ await this.sleep(5000);
211
+ await this.updateTrips();
212
+ },
213
+ 24 * 60 * 60 * 1000,
214
+ );
215
+ this.refreshTokenInterval = setInterval(
216
+ async () => {
217
+ await this.refreshToken();
218
+ await this.sleep(5000);
219
+ },
220
+ (this.session.expires_in - 123) * 1000,
221
+ );
212
222
  }
213
223
  }
214
224
  async login() {
@@ -256,9 +266,12 @@ class Bmw extends utils.Adapter {
256
266
 
257
267
  this.log.error('Start relogin in 5min');
258
268
  this.reLoginTimeout && clearTimeout(this.reLoginTimeout);
259
- this.reLoginTimeout = setTimeout(() => {
260
- this.login();
261
- }, 5000 * 60 * 1);
269
+ this.reLoginTimeout = setTimeout(
270
+ () => {
271
+ this.login();
272
+ },
273
+ 5000 * 60 * 1,
274
+ );
262
275
  }
263
276
  if (error.response && error.response.status === 400) {
264
277
  this.log.error('Please check username and password');
@@ -365,6 +378,14 @@ class Bmw extends utils.Adapter {
365
378
  return;
366
379
  }
367
380
  for (const vehicle of res.data) {
381
+ if (this.config.ignorelist) {
382
+ this.log.info('Ignorelist found');
383
+ const ignoreListArray = this.config.ignorelist.replace(/\s/g, '').split(',');
384
+ if (ignoreListArray.includes(vehicle.vin)) {
385
+ this.log.info('Ignore ' + vehicle.vin);
386
+ continue;
387
+ }
388
+ }
368
389
  this.vinArray.push(vehicle.vin);
369
390
  await this.extendObjectAsync(vehicle.vin, {
370
391
  type: 'device',
@@ -430,9 +451,12 @@ class Bmw extends utils.Adapter {
430
451
  }
431
452
  this.log.info('Adapter will retry in 3 minutes to get vehicles');
432
453
  this.reLoginTimeout && clearTimeout(this.reLoginTimeout);
433
- this.reLoginTimeout = setTimeout(() => {
434
- this.getVehiclesv2();
435
- }, 1000 * 60 * 3);
454
+ this.reLoginTimeout = setTimeout(
455
+ () => {
456
+ this.getVehiclesv2();
457
+ },
458
+ 1000 * 60 * 3,
459
+ );
436
460
  });
437
461
  await this.sleep(5000);
438
462
  }
@@ -451,7 +475,8 @@ class Bmw extends utils.Adapter {
451
475
  headers['bmw-vin'] = vin;
452
476
  await this.requestClient({
453
477
  method: 'get',
454
- url: 'https://cocoapi.bmwgroup.com/eadrax-vcs/v4/vehicles/state?apptimezone=120&appDateTime=' + Date.now() + '&tireGuardMode=ENABLED',
478
+ url:
479
+ 'https://cocoapi.bmwgroup.com/eadrax-vcs/v4/vehicles/state?apptimezone=120&appDateTime=' + Date.now() + '&tireGuardMode=ENABLED',
455
480
  headers: headers,
456
481
  })
457
482
  .then(async (res) => {
@@ -619,7 +644,9 @@ class Bmw extends utils.Adapter {
619
644
  authorization: 'Bearer ' + this.session.access_token,
620
645
  'accept-language': 'de-DE',
621
646
  '24-hour-format': 'true',
647
+ 'bmw-vin': vin,
622
648
  };
649
+
623
650
  const d = new Date();
624
651
  const dateFormatted =
625
652
  d.getFullYear().toString() +
@@ -631,7 +658,7 @@ class Bmw extends utils.Adapter {
631
658
  const urlArray = [];
632
659
  urlArray.push({
633
660
  url:
634
- 'https://cocoapi.bmwgroup.com/eadrax-chs/v1/charging-sessions?vin=' +
661
+ 'https://cocoapi.bmwgroup.com/eadrax-chs/v2/charging-sessions?vin=' +
635
662
  vin +
636
663
  '&next_token&date=' +
637
664
  dateFormatted +
@@ -641,7 +668,7 @@ class Bmw extends utils.Adapter {
641
668
  });
642
669
 
643
670
  urlArray.push({
644
- url: 'https://cocoapi.bmwgroup.com/eadrax-chs/v1/charging-statistics?vin=' + vin + '&currentDate=' + fullDate,
671
+ url: 'https://cocoapi.bmwgroup.com/eadrax-chs/v2/charging-statistics?vin=' + vin + '&currentDate=' + fullDate,
645
672
  path: '.charging-statistics.',
646
673
  name: 'charging statistics',
647
674
  });
@@ -719,9 +746,15 @@ class Bmw extends utils.Adapter {
719
746
  }
720
747
  })
721
748
  .catch((error) => {
749
+ if (error.response && error.response.status === 403) {
750
+ this.log.debug(error.response.data.message + ' Retry in 5 seconds');
751
+ return;
752
+ }
722
753
  if (error.response) {
723
754
  this.log.info('No charging session available. Ignore ' + vin + ' until restart');
724
755
  this.nonChargingHistory[vin] = true;
756
+ this.log.debug(error);
757
+ error.response && this.log.debug(JSON.stringify(error.response.data));
725
758
  return;
726
759
  }
727
760
  this.log.error('updateChargingSessionv2 failed');
@@ -796,9 +829,12 @@ class Bmw extends utils.Adapter {
796
829
  error.response && this.log.error(JSON.stringify(error.response.data));
797
830
  this.log.error('Start relogin in 1min');
798
831
  this.reLoginTimeout && clearTimeout(this.reLoginTimeout);
799
- this.reLoginTimeout = setTimeout(() => {
800
- this.login();
801
- }, 1000 * 60 * 1);
832
+ this.reLoginTimeout = setTimeout(
833
+ () => {
834
+ this.login();
835
+ },
836
+ 1000 * 60 * 1,
837
+ );
802
838
  });
803
839
  }
804
840
 
@@ -852,7 +888,7 @@ class Bmw extends utils.Adapter {
852
888
  '24-hour-format': 'true',
853
889
  'Content-Type': 'text/plain',
854
890
  };
855
- let url = 'https://cocoapi.bmwgroup.com/eadrax-vrccs/v2/presentation/remote-commands/' + vin + '/' + command;
891
+ let url = 'https://cocoapi.bmwgroup.com/eadrax-vrccs/v3/presentation/remote-commands/' + vin + '/' + command;
856
892
  if (action) {
857
893
  url += '?action=' + action;
858
894
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.bmw",
3
- "version": "2.8.0",
3
+ "version": "2.8.2",
4
4
  "description": "Adapter for BMW",
5
5
  "author": {
6
6
  "name": "TA2k",
@@ -16,35 +16,27 @@
16
16
  "url": "https://github.com/TA2k/ioBroker.bmw"
17
17
  },
18
18
  "dependencies": {
19
- "@iobroker/adapter-core": "^3.0.4",
20
- "axios": "^1.6.5",
19
+ "@iobroker/adapter-core": "^3.2.1",
20
+ "axios": "^1.7.7",
21
21
  "http-cookie-agent": "^5.0.4",
22
22
  "json-bigint": "^1.0.0",
23
- "json2iob": "^2.6.6",
24
- "qs": "^6.11.2",
25
- "tough-cookie": "^4.1.3"
23
+ "json2iob": "^2.6.12",
24
+ "qs": "^6.13.0",
25
+ "tough-cookie": "^4.1.4"
26
26
  },
27
27
  "devDependencies": {
28
- "@alcalzone/release-script": "^3.7.0",
29
- "@alcalzone/release-script-plugin-iobroker": "^3.7.0",
28
+ "@alcalzone/release-script": "^3.8.0",
29
+ "@alcalzone/release-script-plugin-iobroker": "^3.7.2",
30
30
  "@alcalzone/release-script-plugin-license": "^3.7.0",
31
31
  "@alcalzone/release-script-plugin-manual-review": "^3.7.0",
32
- "@iobroker/testing": "^4.1.0",
33
- "@tsconfig/node16": "^16.1.1",
34
- "@types/mocha": "^10.0.6",
35
- "@types/node": "^20.10.7",
36
- "@types/proxyquire": "^1.3.31",
37
- "@types/sinon": "^17.0.2",
38
- "@types/sinon-chai": "^3.2.12",
39
- "eslint": "^8.56.0",
32
+ "@iobroker/testing": "^4.1.3",
33
+ "@tsconfig/node16": "^16.1.3",
34
+ "@types/node": "^20.16.10",
35
+ "eslint": "^8.57.1",
40
36
  "eslint-config-prettier": "^9.1.0",
41
- "eslint-plugin-prettier": "^5.1.2",
42
- "mocha": "^10.2.0",
43
- "prettier": "^3.1.1",
44
- "proxyquire": "^2.1.3",
45
- "sinon": "^17.0.1",
46
- "sinon-chai": "^3.7.0",
47
- "typescript": "~5.3.3"
37
+ "eslint-plugin-prettier": "^5.2.1",
38
+ "prettier": "^3.3.3",
39
+ "typescript": "~5.6.2"
48
40
  },
49
41
  "main": "main.js",
50
42
  "scripts": {
@@ -54,7 +46,8 @@
54
46
  "test:integration": "mocha test/integration --exit",
55
47
  "test": "npm run test:js && npm run test:package",
56
48
  "check": "tsc --noEmit -p tsconfig.check.json",
57
- "lint": "eslint"
49
+ "lint": "eslint",
50
+ "release": "release-script --all"
58
51
  },
59
52
  "bugs": {
60
53
  "url": "https://github.com/TA2k/ioBroker.bmw/issues"