iobroker.renault 0.0.21 → 0.0.23

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/main.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
3
  /*
4
4
  * Created with @iobroker/create-adapter v2.0.1
@@ -6,10 +6,10 @@
6
6
 
7
7
  // The adapter-core module gives you access to the core ioBroker functions
8
8
  // you need to create an adapter
9
- const utils = require("@iobroker/adapter-core");
10
- const axios = require("axios").default;
11
- const qs = require("qs");
12
- const Json2iob = require("json2iob");
9
+ const utils = require('@iobroker/adapter-core');
10
+ const axios = require('axios').default;
11
+ const qs = require('qs');
12
+ const Json2iob = require('json2iob');
13
13
 
14
14
  class Renault extends utils.Adapter {
15
15
  /**
@@ -18,16 +18,27 @@ class Renault extends utils.Adapter {
18
18
  constructor(options) {
19
19
  super({
20
20
  ...options,
21
- name: "renault",
21
+ name: 'renault',
22
22
  });
23
- this.on("ready", this.onReady.bind(this));
24
- this.on("stateChange", this.onStateChange.bind(this));
25
- this.on("unload", this.onUnload.bind(this));
23
+ this.on('ready', this.onReady.bind(this));
24
+ this.on('stateChange', this.onStateChange.bind(this));
25
+ this.on('unload', this.onUnload.bind(this));
26
26
  this.deviceArray = [];
27
27
  this.json2iob = new Json2iob(this);
28
28
  this.ignoreState = {};
29
29
  this.firstUpdate = true;
30
30
  this.requestClient = axios.create();
31
+ this.userAgent = 'okhttp/5.3.0';
32
+ }
33
+
34
+ /** APK rI2.smali (WiredHeaderAppVersionInterceptor): build={brand}-android-{version};trId={uuid} on wired Kamereon host */
35
+ buildTraceId() {
36
+ const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
37
+ const r = (Math.random() * 16) | 0;
38
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
39
+ return v.toString(16);
40
+ });
41
+ return 'build=renault-android-6.11.2;trId=' + uuid;
31
42
  }
32
43
 
33
44
  /**
@@ -35,23 +46,23 @@ class Renault extends utils.Adapter {
35
46
  */
36
47
  async onReady() {
37
48
  // Reset the connection indicator during startup
38
- this.setState("info.connection", false, true);
49
+ this.setState('info.connection', false, true);
39
50
  if (this.config.interval < 0.5) {
40
- this.log.info("Set interval to minimum 0.5");
51
+ this.log.info('Set interval to minimum 0.5');
41
52
  this.config.interval = 0.5;
42
53
  }
43
54
  this.updateInterval = null;
44
55
  this.reLoginTimeout = null;
45
56
  this.refreshTokenTimeout = null;
46
- this.country = this.config.country || "de";
57
+ this.country = this.config.country || 'de';
47
58
  this.session = {};
48
59
  //DE API Key
49
- this.apiKey = "3_7PLksOyBRkHv126x5WhHb-5pqC1qFR8pQjxSeLB6nhAnPERTUlwnYoznHSxwX668";
50
- this.apiKeyUpdate = "YjkKtHmGfaceeuExUDKGxrLZGGvtVS0J";
60
+ this.apiKey = '3_VgdkgtIRH3AdHvJm-cjV2ug2EFE0lxt0IJzMC4MFqZjFpn_GYFXVdNZ19L7wZX0N';
61
+ this.apiKeyUpdate = 'YjkKtHmGfaceeuExUDKGxrLZGGvtVS0J';
51
62
  try {
52
63
  await this.requestClient({
53
- method: "get",
54
- url: "https://raw.githubusercontent.com/hacf-fr/renault-api/main/src/renault_api/const.py",
64
+ method: 'get',
65
+ url: 'https://raw.githubusercontent.com/hacf-fr/renault-api/main/src/renault_api/const.py',
55
66
  })
56
67
 
57
68
  .then((res) => {
@@ -71,16 +82,19 @@ class Renault extends utils.Adapter {
71
82
  this.apiKeyUpdate = this.config.apiKeyUpdate;
72
83
  }
73
84
 
74
- this.subscribeStates("*");
85
+ this.subscribeStates('*');
75
86
 
76
87
  await this.login();
77
88
 
78
89
  if (this.session.id_token && this.session_data && this.account) {
79
90
  await this.getDeviceList();
80
91
  await this.updateDevices();
81
- this.updateInterval = setInterval(async () => {
82
- await this.updateDevices();
83
- }, this.config.interval * 60 * 1000);
92
+ this.updateInterval = setInterval(
93
+ async () => {
94
+ await this.updateDevices();
95
+ },
96
+ this.config.interval * 60 * 1000,
97
+ );
84
98
  this.refreshTokenInterval = setInterval(() => {
85
99
  this.refreshToken();
86
100
  }, 3500 * 1000);
@@ -88,25 +102,29 @@ class Renault extends utils.Adapter {
88
102
  }
89
103
  async login() {
90
104
  this.session_data = await this.requestClient({
91
- method: "post",
92
- url: "https://accounts.eu1.gigya.com/accounts.login",
105
+ method: 'post',
106
+ url: 'https://accounts.eu1.gigya.com/accounts.login',
93
107
  headers: {
94
- "User-Agent": "MYRenault/39 CFNetwork/1312 Darwin/21.0.0",
95
- Accept: "*/*",
96
- "Accept-Language": "de-de",
97
- "Cache-Control": "no-cache",
98
- "Content-Type": "application/x-www-form-urlencoded",
108
+ 'User-Agent': this.userAgent,
109
+ Accept: '*/*',
110
+ 'Accept-Language': 'de-de',
111
+ 'Cache-Control': 'no-cache',
112
+ 'Content-Type': 'application/x-www-form-urlencoded',
99
113
  },
100
114
  data: qs.stringify({
101
115
  apikey: this.apiKey,
102
- format: "json",
103
- httpStatusCodes: "false",
116
+ format: 'json',
117
+ httpStatusCodes: 'false',
104
118
  loginID: this.config.username,
105
119
  password: this.config.password,
106
120
  }),
107
121
  })
108
122
  .then((res) => {
109
123
  this.log.debug(JSON.stringify(res.data));
124
+ if (res.data.errorMessage) {
125
+ this.log.error(JSON.stringify(res.data));
126
+ return;
127
+ }
110
128
  return res.data.sessionInfo;
111
129
  })
112
130
  .catch((error) => {
@@ -116,32 +134,32 @@ class Renault extends utils.Adapter {
116
134
  }
117
135
  });
118
136
  if (!this.session_data) {
119
- this.log.error("No session found for this account");
137
+ this.log.error('No session found for this account. Please login in the app. Maybe a new password is needed.');
120
138
  return;
121
139
  }
122
140
  await this.requestClient({
123
- method: "post",
124
- url: "https://accounts.eu1.gigya.com/accounts.getJWT",
141
+ method: 'post',
142
+ url: 'https://accounts.eu1.gigya.com/accounts.getJWT',
125
143
  headers: {
126
- "User-Agent": "MYRenault/39 CFNetwork/1312 Darwin/21.0.0",
127
- Accept: "*/*",
128
- "Accept-Language": "de-de",
129
- "Cache-Control": "no-cache",
130
- "Content-Type": "application/x-www-form-urlencoded",
144
+ 'User-Agent': this.userAgent,
145
+ Accept: '*/*',
146
+ 'Accept-Language': 'de-de',
147
+ 'Cache-Control': 'no-cache',
148
+ 'Content-Type': 'application/x-www-form-urlencoded',
131
149
  },
132
150
  data: qs.stringify({
133
- format: "json",
151
+ format: 'json',
134
152
  login_token: this.session_data.cookieValue,
135
- sdk: "js_latest",
136
- fields: "data.personId,data.gigyaDataCenter",
153
+ sdk: 'js_latest',
154
+ fields: 'data.personId,data.gigyaDataCenter',
137
155
  apikey: this.apiKey,
138
- expiration: "3600",
156
+ expiration: '3600',
139
157
  }),
140
158
  })
141
159
  .then((res) => {
142
160
  this.log.debug(JSON.stringify(res.data));
143
161
  this.session = res.data;
144
- this.setState("info.connection", true, true);
162
+ this.setState('info.connection', true, true);
145
163
  })
146
164
  .catch((error) => {
147
165
  this.log.error(error);
@@ -150,59 +168,60 @@ class Renault extends utils.Adapter {
150
168
  }
151
169
  });
152
170
  await this.requestClient({
153
- method: "post",
154
- url: "https://apis.renault.com/myr/api/v1/connection?&country=DE&product=MYRENAULT&locale=de-DE&displayAccounts=MYRENAULT",
171
+ method: 'post',
172
+ url: 'https://apis.renault.com/myr/api/v1/connection?&country=DE&product=MYRENAULT&locale=de-DE&displayAccounts=MYRENAULT',
155
173
  headers: {
156
- "Content-Type": "application/json",
157
- Accept: "*/*",
158
- "User-Agent": "MYRenault/39 CFNetwork/1312 Darwin/21.0.0",
174
+ 'Content-Type': 'application/json',
175
+ Accept: '*/*',
176
+ 'User-Agent': this.userAgent,
159
177
  apiKey: this.apiKeyUpdate,
160
- "Accept-Language": "de-de",
161
- "x-gigya-id_token": this.session.id_token,
178
+ 'Accept-Language': 'de-de',
179
+ 'x-gigya-id_token': this.session.id_token,
162
180
  },
163
181
  })
164
182
  .then((res) => {
165
183
  this.log.debug(JSON.stringify(res.data));
166
184
 
167
185
  const filteredAccounts = res.data.currentUser.accounts.filter(function (el) {
168
- return (el.accountType === "MYRENAULT" || el.accountType === "MYDACIA") && el.accountStatus === "ACTIVE";
186
+ return (el.accountType === 'MYRENAULT' || el.accountType === 'MYDACIA') && el.accountStatus === 'ACTIVE';
169
187
  });
170
188
  if (filteredAccounts.length === 0) {
171
- this.log.error("No Account found");
172
- this.log.error("All accounts: " + res.data.currentUser.accounts);
173
- this.log.error("Filtered accounts: " + filteredAccounts);
189
+ this.log.error('No Account found');
190
+ this.log.error('All accounts: ' + res.data.currentUser.accounts);
191
+ this.log.error('Filtered accounts: ' + filteredAccounts);
174
192
  return;
175
193
  }
176
194
 
177
195
  this.account = filteredAccounts[0];
178
196
  })
179
197
  .catch((error) => {
180
- this.log.error("Error while getting account");
198
+ this.log.error('Error while getting account');
181
199
  this.log.error(error);
182
200
  if (error.response) {
183
201
  this.log.error(JSON.stringify(error.response.data));
184
- if (error.response.data && JSON.stringify(error.response.data).indexOf("apikey") !== -1) {
185
- this.log.error("Wrong API Key. Please update API Key in adapter settings");
202
+ if (error.response.data && JSON.stringify(error.response.data).indexOf('apikey') !== -1) {
203
+ this.log.error('Wrong API Key. Please update API Key in adapter settings');
186
204
  }
187
205
  }
188
206
  });
189
207
  }
190
208
  async getDeviceList() {
191
209
  await this.requestClient({
192
- method: "get",
210
+ method: 'get',
193
211
  url:
194
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
212
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
195
213
  this.account.accountId +
196
- "/vehicles?country=" +
214
+ '/vehicles?country=' +
197
215
  this.country +
198
- "&oms=false",
216
+ '&oms=false',
199
217
  headers: {
200
218
  apikey: this.apiKeyUpdate,
201
- "content-type": "application/json",
202
- accept: "*/*",
203
- "user-agent": "MYRenault/39 CFNetwork/1312 Darwin/21.0.0",
204
- "accept-language": "de-de",
205
- "x-gigya-id_token": this.session.id_token,
219
+ 'content-type': 'application/json',
220
+ accept: '*/*',
221
+ 'user-agent': this.userAgent,
222
+ 'accept-language': 'de-de',
223
+ 'x-gigya-id_token': this.session.id_token,
224
+ 'X-Amzn-Trace-Id': this.buildTraceId(),
206
225
  },
207
226
  })
208
227
  .then(async (res) => {
@@ -217,53 +236,54 @@ class Renault extends utils.Adapter {
217
236
 
218
237
  this.ignoreState[device.vin] = [];
219
238
  await this.setObjectNotExistsAsync(device.vin, {
220
- type: "device",
239
+ type: 'device',
221
240
  common: {
222
241
  name: name,
223
242
  },
224
243
  native: {},
225
244
  });
226
- await this.setObjectNotExistsAsync(device.vin + ".remote", {
227
- type: "channel",
245
+ await this.setObjectNotExistsAsync(device.vin + '.remote', {
246
+ type: 'channel',
228
247
  common: {
229
- name: "Remote Controls",
248
+ name: 'Remote Controls',
230
249
  },
231
250
  native: {},
232
251
  });
233
- await this.setObjectNotExistsAsync(device.vin + ".general", {
234
- type: "channel",
252
+ await this.setObjectNotExistsAsync(device.vin + '.general', {
253
+ type: 'channel',
235
254
  common: {
236
- name: "WIRD NICHT AKTUALISIERT",
255
+ name: 'WIRD NICHT AKTUALISIERT',
237
256
  },
238
257
  native: {},
239
258
  });
240
259
 
241
260
  const remoteArray = [
242
- { command: "actions/hvac-start", name: "True = Start, False = Stop" },
243
- { command: "hvac-temperature", name: "HVAC Temperature", type: "number", role: "value" },
244
- { command: "actions/charging-start", name: "True = Start, False = Stop" },
245
- { command: "charge/pause-resume", name: "True = Start, False = Stop" },
246
- { command: "charge/start", name: "True = Start, False = Stop" },
247
- { command: "refresh", name: "True = Refresh Data" },
261
+ { command: 'actions/hvac-start', name: 'True = Start, False = Stop' },
262
+ { command: 'hvac-temperature', name: 'HVAC Temperature', type: 'number', role: 'value' },
263
+ { command: 'actions/charging-start', name: 'True = Start, False = Stop' },
264
+ { command: 'charge/pause-resume', name: 'True = Start, False = Stop' },
265
+ { command: 'charge/start', name: 'True = Start, False = Stop' },
266
+ { command: 'refresh', name: 'True = Refresh Data' },
248
267
  ];
249
268
  remoteArray.forEach((remote) => {
250
- this.setObjectNotExists(device.vin + ".remote." + remote.command, {
251
- type: "state",
269
+ this.setObjectNotExists(device.vin + '.remote.' + remote.command, {
270
+ type: 'state',
252
271
  common: {
253
- name: remote.name || "",
254
- type: remote.type || "boolean",
255
- role: remote.role || "button",
272
+ name: remote.name || '',
273
+ type: remote.type || 'boolean',
274
+ role: remote.role || 'button',
256
275
  write: true,
257
276
  read: true,
258
277
  },
259
278
  native: {},
260
279
  });
261
280
  });
262
- this.json2iob.parse(device.vin + ".general", device);
281
+ delete device.mileage;
282
+ this.json2iob.parse(device.vin + '.general', device);
263
283
  }
264
284
  })
265
285
  .catch((error) => {
266
- this.log.error("Error while getting vehicle list");
286
+ this.log.error('Error while getting vehicle list');
267
287
  this.log.error(error);
268
288
  error.response && this.log.error(JSON.stringify(error.response.data));
269
289
  });
@@ -271,154 +291,158 @@ class Renault extends utils.Adapter {
271
291
 
272
292
  async updateDevices() {
273
293
  if (!this.account.accountId) {
274
- this.log.error("No accountId found");
294
+ this.log.error('No accountId found');
275
295
  return;
276
296
  }
277
- const curDate = new Date().toISOString().split("T")[0];
297
+ const curDate = new Date().toISOString().split('T')[0];
278
298
 
279
299
  const statusArray = [
280
300
  {
281
- path: "battery-status",
301
+ path: 'battery-status',
282
302
  url:
283
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
303
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
284
304
  this.account.accountId +
285
- "/kamereon/kca/car-adapter/v2/cars/$vin/battery-status?country=" +
305
+ '/kamereon/kca/car-adapter/v2/cars/$vin/battery-status?country=' +
286
306
  this.country,
287
- desc: "Battery status of the car",
307
+ desc: 'Battery status of the car',
288
308
  },
289
309
  {
290
- path: "battery-inhibition-status",
310
+ path: 'battery-inhibition-status',
291
311
  url:
292
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
312
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
293
313
  this.account.accountId +
294
- "/kamereon/kca/car-adapter/v1/cars/$vin/battery-inhibition-status?country=" +
314
+ '/kamereon/kca/car-adapter/v1/cars/$vin/battery-inhibition-status?country=' +
295
315
  this.country,
296
- desc: "Battery inhibition status of the car",
316
+ desc: 'Battery inhibition status of the car',
297
317
  },
298
318
  {
299
- path: "cockpit",
319
+ path: 'cockpit',
300
320
  url:
301
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
321
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
302
322
  this.account.accountId +
303
- "/kamereon/kca/car-adapter/v1/cars/$vin/cockpit?country=" +
323
+ '/kamereon/kca/car-adapter/v1/cars/$vin/cockpit?country=' +
304
324
  this.country,
305
- desc: "Status of the car",
325
+ desc: 'Status of the car',
306
326
  },
307
327
  {
308
- path: "cockpitv2",
328
+ path: 'cockpitv2',
309
329
  url:
310
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
330
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
311
331
  this.account.accountId +
312
- "/kamereon/kca/car-adapter/v2/cars/$vin/cockpit?country=" +
332
+ '/kamereon/kca/car-adapter/v2/cars/$vin/cockpit?country=' +
313
333
  this.country,
314
- desc: "Statusv2 of the car",
334
+ desc: 'Statusv2 of the car',
315
335
  },
316
336
  {
317
- path: "charge-mode",
337
+ path: 'charge-mode',
318
338
  url:
319
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
339
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
320
340
  this.account.accountId +
321
- "/kamereon/kca/car-adapter/v1/cars/$vin/charge-mode?country=" +
341
+ '/kamereon/kca/car-adapter/v1/cars/$vin/charge-mode?country=' +
322
342
  this.country,
323
- desc: "Charge mode of the car",
343
+ desc: 'Charge mode of the car',
324
344
  },
325
345
  {
326
- path: "hvac-status",
346
+ path: 'hvac-status',
327
347
  url:
328
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
348
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
329
349
  this.account.accountId +
330
- "/kamereon/kca/car-adapter/v1/cars/$vin/hvac-status?country=" +
350
+ '/kamereon/kca/car-adapter/v1/cars/$vin/hvac-status?country=' +
331
351
  this.country,
332
- desc: "HVAC status of the car",
352
+ desc: 'HVAC status of the car',
333
353
  },
334
354
  {
335
- path: "hvac-settings",
355
+ path: 'hvac-settings',
336
356
  url:
337
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
357
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
338
358
  this.account.accountId +
339
- "/kamereon/kca/car-adapter/v1/cars/$vin/hvac-settings?country=" +
359
+ '/kamereon/kca/car-adapter/v1/cars/$vin/hvac-settings?country=' +
340
360
  this.country,
341
- desc: "HVAC settings of the car",
361
+ desc: 'HVAC settings of the car',
342
362
  },
343
363
  {
344
- path: "charging-settings",
364
+ path: 'charging-settings',
345
365
  url:
346
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
366
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
347
367
  this.account.accountId +
348
- "/kamereon/kca/car-adapter/v1/cars/$vin/charging-settings?country=" +
368
+ '/kamereon/kca/car-adapter/v1/cars/$vin/charging-settings?country=' +
349
369
  this.country,
350
- desc: "Charging settings of the car",
370
+ desc: 'Charging settings of the car',
351
371
  },
372
+
352
373
  {
353
- path: "charge-history",
374
+ path: 'lock-status',
354
375
  url:
355
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
376
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
356
377
  this.account.accountId +
357
- "/kamereon/kca/car-adapter/v1/cars/$vin/charge-history?type=day&start=1970-01-01&end=" +
358
- curDate +
359
- "&country=" +
378
+ '/kamereon/kca/car-adapter/v1/cars/$vin/lock-status?country=' +
360
379
  this.country,
361
- desc: "Charging history of the car",
380
+ desc: 'Lock status of the car',
362
381
  },
363
382
  {
364
- path: "charges",
383
+ path: 'res-state',
365
384
  url:
366
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
385
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
367
386
  this.account.accountId +
368
- "/kamereon/kca/car-adapter/v1/cars/$vin/charges?start=1970-01-01&end=" +
369
- curDate +
370
- "&country=" +
387
+ '/kamereon/kca/car-adapter/v1/cars/$vin/res-state?country=' +
371
388
  this.country,
372
- desc: "Charges of the car",
389
+ desc: 'Res status of the car',
373
390
  },
374
391
  {
375
- path: "lock-status",
392
+ path: 'location',
376
393
  url:
377
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
394
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
378
395
  this.account.accountId +
379
- "/kamereon/kca/car-adapter/v1/cars/$vin/lock-status?country=" +
396
+ '/kamereon/kca/car-adapter/v1/cars/$vin/location?country=' +
380
397
  this.country,
381
- desc: "Lock status of the car",
398
+ desc: 'Location of the car',
382
399
  },
383
- {
384
- path: "res-state",
400
+ ];
401
+
402
+ if (!this.config.disableChargeFetching) {
403
+ statusArray.push({
404
+ path: 'charge-history',
385
405
  url:
386
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
406
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
387
407
  this.account.accountId +
388
- "/kamereon/kca/car-adapter/v1/cars/$vin/res-state?country=" +
408
+ '/kamereon/kca/car-adapter/v1/cars/$vin/charge-history?type=day&start=1970-01-01&end=' +
409
+ curDate +
410
+ '&country=' +
389
411
  this.country,
390
- desc: "Res status of the car",
391
- },
392
- {
393
- path: "location",
412
+ desc: 'Charging history of the car',
413
+ });
414
+ statusArray.push({
415
+ path: 'charges',
394
416
  url:
395
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
417
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
396
418
  this.account.accountId +
397
- "/kamereon/kca/car-adapter/v1/cars/$vin/location?country=" +
419
+ '/kamereon/kca/car-adapter/v1/cars/$vin/charges?start=1970-01-01&end=' +
420
+ curDate +
421
+ '&country=' +
398
422
  this.country,
399
- desc: "Location of the car",
400
- },
401
- ];
423
+ desc: 'Charges of the car',
424
+ });
425
+ }
402
426
 
403
427
  const headers = {
404
428
  apikey: this.apiKeyUpdate,
405
- "content-type": "application/json",
406
- accept: "*/*",
407
- "user-agent": "MYRenault/39 CFNetwork/1312 Darwin/21.0.0",
408
- "accept-language": "de-de",
409
- "x-gigya-id_token": this.session.id_token,
429
+ 'content-type': 'application/json',
430
+ accept: '*/*',
431
+ 'user-agent': this.userAgent,
432
+ 'accept-language': 'de-de',
433
+ 'x-gigya-id_token': this.session.id_token,
410
434
  };
411
435
  for (const vin of this.deviceArray) {
412
436
  for (const element of statusArray) {
413
437
  if (this.ignoreState[vin] && this.ignoreState[vin].includes(element.path)) {
414
438
  continue;
415
439
  }
416
- const url = element.url.replace("$vin", vin);
440
+ const url = element.url.replace('$vin', vin);
417
441
 
418
442
  await this.requestClient({
419
- method: "get",
443
+ method: 'get',
420
444
  url: url,
421
- headers: headers,
445
+ headers: { ...headers, 'X-Amzn-Trace-Id': this.buildTraceId() },
422
446
  })
423
447
  .then((res) => {
424
448
  this.log.debug(JSON.stringify(res.data));
@@ -430,10 +454,10 @@ class Renault extends utils.Adapter {
430
454
  data = res.data.data.attributes;
431
455
  }
432
456
 
433
- const forceIndex = null;
434
- const preferedArrayName = null;
457
+ const forceIndex = undefined;
458
+ const preferedArrayName = undefined;
435
459
 
436
- this.json2iob.parse(vin + "." + element.path, data, {
460
+ this.json2iob.parse(vin + '.' + element.path, data, {
437
461
  forceIndex: forceIndex,
438
462
  preferedArrayName: preferedArrayName,
439
463
  channelName: element.desc,
@@ -443,7 +467,7 @@ class Renault extends utils.Adapter {
443
467
  if (error.response) {
444
468
  if (error.response.status === 401) {
445
469
  error.response && this.log.debug(JSON.stringify(error.response.data));
446
- this.log.info(element.path + " receive 401 error. Refresh Token in 60 seconds");
470
+ this.log.info(element.path + ' receive 401 error. Refresh Token in 60 seconds');
447
471
  this.refreshTokenTimeout && clearTimeout(this.refreshTokenTimeout);
448
472
  this.refreshTokenTimeout = setTimeout(() => {
449
473
  this.refreshToken();
@@ -464,7 +488,7 @@ class Renault extends utils.Adapter {
464
488
  this.ignoreState[vin] = [];
465
489
  }
466
490
  this.ignoreState[vin].push(element.path);
467
- this.log.info("Feature not found for " + vin + ". Ignore " + element.path + " for updates.");
491
+ this.log.info('Feature not found for ' + vin + '. Ignore ' + element.path + ' for updates.');
468
492
  this.log.debug(error);
469
493
  error.response && this.log.debug(JSON.stringify(error.response.data));
470
494
  return;
@@ -485,42 +509,45 @@ class Renault extends utils.Adapter {
485
509
  }
486
510
  async refreshToken() {
487
511
  if (!this.session_data) {
488
- this.log.error("No session found relogin");
512
+ this.log.error('No session found relogin');
489
513
  await this.login();
490
514
  return;
491
515
  }
492
516
  await this.requestClient({
493
- method: "post",
494
- url: "https://accounts.eu1.gigya.com/accounts.getJWT",
517
+ method: 'post',
518
+ url: 'https://accounts.eu1.gigya.com/accounts.getJWT',
495
519
  headers: {
496
- "User-Agent": "MYRenault/39 CFNetwork/1312 Darwin/21.0.0",
497
- Accept: "*/*",
498
- "Accept-Language": "de-de",
499
- "Cache-Control": "no-cache",
500
- "Content-Type": "application/x-www-form-urlencoded",
520
+ 'User-Agent': this.userAgent,
521
+ Accept: '*/*',
522
+ 'Accept-Language': 'de-de',
523
+ 'Cache-Control': 'no-cache',
524
+ 'Content-Type': 'application/x-www-form-urlencoded',
501
525
  },
502
526
  data: qs.stringify({
503
- format: "json",
527
+ format: 'json',
504
528
  login_token: this.session_data.cookieValue,
505
- sdk: "js_latest",
506
- fields: "data.personId,data.gigyaDataCenter",
529
+ sdk: 'js_latest',
530
+ fields: 'data.personId,data.gigyaDataCenter',
507
531
  apikey: this.apiKey,
508
- expiration: "3600",
532
+ expiration: '3600',
509
533
  }),
510
534
  })
511
535
  .then((res) => {
512
536
  this.log.debug(JSON.stringify(res.data));
513
537
  this.session = res.data;
514
- this.setState("info.connection", true, true);
538
+ this.setState('info.connection', true, true);
515
539
  })
516
540
  .catch((error) => {
517
- this.log.error("refresh token failed");
541
+ this.log.error('refresh token failed');
518
542
  this.log.error(error);
519
543
  error.response && this.log.error(JSON.stringify(error.response.data));
520
- this.log.error("Start relogin in 1min");
521
- this.reLoginTimeout = setTimeout(() => {
522
- this.login();
523
- }, 1000 * 60 * 1);
544
+ this.log.error('Start relogin in 1min');
545
+ this.reLoginTimeout = setTimeout(
546
+ () => {
547
+ this.login();
548
+ },
549
+ 1000 * 60 * 1,
550
+ );
524
551
  });
525
552
  }
526
553
  sleep(ms) {
@@ -530,8 +557,8 @@ class Renault extends utils.Adapter {
530
557
  if (!string) {
531
558
  return;
532
559
  }
533
- string = string.replace("actions/", "");
534
- string = string.replace("/", "-");
560
+ string = string.replace('actions/', '');
561
+ string = string.replace('/', '-');
535
562
  const camelC = string.replace(/-([a-z])/g, function (g) {
536
563
  return g[1].toUpperCase();
537
564
  });
@@ -543,7 +570,7 @@ class Renault extends utils.Adapter {
543
570
  */
544
571
  onUnload(callback) {
545
572
  try {
546
- this.setState("info.connection", false, true);
573
+ this.setState('info.connection', false, true);
547
574
  clearTimeout(this.refreshTimeout);
548
575
  this.reLoginTimeout && clearTimeout(this.reLoginTimeout);
549
576
  this.refreshTokenTimeout && clearTimeout(this.refreshTokenTimeout);
@@ -551,6 +578,7 @@ class Renault extends utils.Adapter {
551
578
  clearInterval(this.refreshTokenInterval);
552
579
  callback();
553
580
  } catch (e) {
581
+ this.log.error('Error onUnload: ' + e);
554
582
  callback();
555
583
  }
556
584
  }
@@ -563,30 +591,30 @@ class Renault extends utils.Adapter {
563
591
  async onStateChange(id, state) {
564
592
  if (state) {
565
593
  if (!state.ack) {
566
- const deviceId = id.split(".")[2];
567
- const path = id.split(".")[4];
568
- if (path === "hvac-temperature") {
594
+ const deviceId = id.split('.')[2];
595
+ const path = id.split('.')[4];
596
+ if (path === 'hvac-temperature') {
569
597
  return;
570
598
  }
571
- if (path === "refresh") {
572
- this.log.info("Force refresh");
599
+ if (path === 'refresh') {
600
+ this.log.info('Force refresh');
573
601
  this.updateDevices();
574
602
  return;
575
603
  }
576
604
  if (!this.account) {
577
- this.log.error("No account found");
605
+ this.log.error('No account found');
578
606
  return;
579
607
  }
580
- const command = path.split("/")[1];
581
- let action = state.val ? "start" : "cancel";
582
- let midPart = "kca/car-adapter/v1/cars/";
583
- if (path === "charge/pause-resume") {
584
- action = state.val ? "resume" : "pause";
585
- midPart = "kcm/v1/vehicles/";
608
+ const command = path.split('/')[1];
609
+ let action = state.val ? 'start' : 'cancel';
610
+ let midPart = 'kca/car-adapter/v1/cars/';
611
+ if (path === 'charge/pause-resume') {
612
+ action = state.val ? 'resume' : 'pause';
613
+ midPart = 'kcm/v1/vehicles/';
586
614
  }
587
615
  const data = { data: { type: this.toCamelCase(path), attributes: { action: action } } };
588
- if (command === "hvac-start") {
589
- const temperatureState = await this.getStateAsync(deviceId + ".remote.hvac-temperature");
616
+ if (command === 'hvac-start') {
617
+ const temperatureState = await this.getStateAsync(deviceId + '.remote.hvac-temperature');
590
618
  if (temperatureState) {
591
619
  data.data.attributes.targetTemperature = temperatureState.val ? temperatureState.val : 21;
592
620
  } else {
@@ -594,27 +622,28 @@ class Renault extends utils.Adapter {
594
622
  }
595
623
  }
596
624
  const url =
597
- "https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/" +
625
+ 'https://api-wired-prod-1-euw1.wrd-aws.com/commerce/v1/accounts/' +
598
626
  this.account.accountId +
599
- "/kamereon/" +
627
+ '/kamereon/' +
600
628
  midPart +
601
629
  deviceId +
602
- "/" +
630
+ '/' +
603
631
  path +
604
- "?country=" +
632
+ '?country=' +
605
633
  this.country;
606
634
  this.log.debug(JSON.stringify(data));
607
635
  this.log.debug(url);
608
636
  await this.requestClient({
609
- method: "post",
637
+ method: 'post',
610
638
  url: url,
611
639
  headers: {
612
640
  apikey: this.apiKeyUpdate,
613
- "content-type": "application/vnd.api+json",
614
- accept: "*/*",
615
- "user-agent": "MYRenault/39 CFNetwork/1312 Darwin/21.0.0",
616
- "accept-language": "de-de",
617
- "x-gigya-id_token": this.session.id_token,
641
+ 'content-type': 'application/vnd.api+json',
642
+ accept: '*/*',
643
+ 'user-agent': this.userAgent,
644
+ 'accept-language': 'de-de',
645
+ 'x-gigya-id_token': this.session.id_token,
646
+ 'X-Amzn-Trace-Id': this.buildTraceId(),
618
647
  },
619
648
  data: data,
620
649
  })