iobroker.toyota 0.2.6 → 0.3.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/lib/tools.js +3 -3
- package/main.js +200 -47
- package/package.json +19 -12
package/io-package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "toyota",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.3.0": {
|
|
7
|
+
"en": "Fix Login and add Eletric Car data",
|
|
8
|
+
"de": "Login gefixt und elektrische Fahrzeugdaten hinzugefügt"
|
|
9
|
+
},
|
|
6
10
|
"0.2.6": {
|
|
7
11
|
"en": "Skip endpoints that are not available",
|
|
8
12
|
"de": "Überspringen von Endpunkten, die nicht verfügbar sind"
|
package/lib/tools.js
CHANGED
|
@@ -64,7 +64,7 @@ async function translateYandex(text, targetLang, apiKey) {
|
|
|
64
64
|
}
|
|
65
65
|
throw new Error('Invalid response for translate request');
|
|
66
66
|
} catch (e) {
|
|
67
|
-
throw new Error(`Could not translate to "${targetLang}": ${e}
|
|
67
|
+
throw new Error(`Could not translate to "${targetLang}": ${e}`, { cause: e });
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -87,9 +87,9 @@ async function translateGoogle(text, targetLang) {
|
|
|
87
87
|
throw new Error('Invalid response for translate request');
|
|
88
88
|
} catch (e) {
|
|
89
89
|
if (e.response && e.response.status === 429) {
|
|
90
|
-
throw new Error(`Could not translate to "${targetLang}": Rate-limited by Google Translate
|
|
90
|
+
throw new Error(`Could not translate to "${targetLang}": Rate-limited by Google Translate`, { cause: e });
|
|
91
91
|
} else {
|
|
92
|
-
throw new Error(`Could not translate to "${targetLang}": ${e}
|
|
92
|
+
throw new Error(`Could not translate to "${targetLang}": ${e}`, { cause: e });
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
}
|
package/main.js
CHANGED
|
@@ -13,6 +13,9 @@ const qs = require('qs');
|
|
|
13
13
|
const tough = require('tough-cookie');
|
|
14
14
|
const { HttpsCookieAgent } = require('http-cookie-agent/http');
|
|
15
15
|
const jwt = require('jsonwebtoken');
|
|
16
|
+
const { v4: uuidv4 } = require('uuid');
|
|
17
|
+
const crypto = require('crypto');
|
|
18
|
+
|
|
16
19
|
class Toyota extends utils.Adapter {
|
|
17
20
|
/**
|
|
18
21
|
* @param {Partial<utils.AdapterOptions>} [options={}]
|
|
@@ -43,8 +46,10 @@ class Toyota extends utils.Adapter {
|
|
|
43
46
|
this.updateInterval = null;
|
|
44
47
|
this.reLoginTimeout = null;
|
|
45
48
|
this.refreshTokenTimeout = null;
|
|
46
|
-
this.hostName = 'myt-agg.toyota-europe.com';
|
|
47
49
|
this.brand = 'T';
|
|
50
|
+
// Aligned with MyToyota APK 2.23.0
|
|
51
|
+
this.CLIENT_VERSION = '2.23.0';
|
|
52
|
+
this.API_VERSION = 'resource=2.1, protocol=1.0';
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
/**
|
|
@@ -65,7 +70,6 @@ class Toyota extends utils.Adapter {
|
|
|
65
70
|
if (this.config.type === 'lexus') {
|
|
66
71
|
this.log.info('Login to Lexus');
|
|
67
72
|
this.brand = 'L';
|
|
68
|
-
this.hostName = 'lexuslink-agg.toyota-europe.com';
|
|
69
73
|
}
|
|
70
74
|
if (!this.config.username || !this.config.password) {
|
|
71
75
|
this.log.error('No username or password set');
|
|
@@ -92,6 +96,7 @@ class Toyota extends utils.Adapter {
|
|
|
92
96
|
}, 3500 * 1000);
|
|
93
97
|
}
|
|
94
98
|
}
|
|
99
|
+
|
|
95
100
|
async login() {
|
|
96
101
|
this.log.info('Login to Toyota');
|
|
97
102
|
const firstResponse = await this.requestClient({
|
|
@@ -101,7 +106,7 @@ class Toyota extends utils.Adapter {
|
|
|
101
106
|
headers: {
|
|
102
107
|
'x-osname': 'iOS',
|
|
103
108
|
'x-brand': this.brand,
|
|
104
|
-
accept: '
|
|
109
|
+
accept: 'application/json',
|
|
105
110
|
'x-channel': 'ONEAPP',
|
|
106
111
|
brand: this.brand,
|
|
107
112
|
'x-region': 'EU',
|
|
@@ -111,8 +116,8 @@ class Toyota extends utils.Adapter {
|
|
|
111
116
|
'accept-language': 'de-DE,de;q=0.9',
|
|
112
117
|
region: 'EU',
|
|
113
118
|
'user-agent': 'Toyota/134 CFNetwork/1410.0.3 Darwin/22.6.0',
|
|
114
|
-
'accept-api-version':
|
|
115
|
-
'x-appversion':
|
|
119
|
+
'accept-api-version': this.API_VERSION,
|
|
120
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
116
121
|
Cookie: 'route=e8e8b55de08efd3c4b34265c0069d319',
|
|
117
122
|
},
|
|
118
123
|
})
|
|
@@ -127,6 +132,7 @@ class Toyota extends utils.Adapter {
|
|
|
127
132
|
this.log.error(JSON.stringify(error.response.data));
|
|
128
133
|
}
|
|
129
134
|
});
|
|
135
|
+
|
|
130
136
|
const secondResponse = await this.requestClient({
|
|
131
137
|
method: 'post',
|
|
132
138
|
maxBodyLength: Infinity,
|
|
@@ -143,10 +149,10 @@ class Toyota extends utils.Adapter {
|
|
|
143
149
|
'x-brand': this.brand,
|
|
144
150
|
'accept-language': 'de-DE,de;q=0.9',
|
|
145
151
|
'x-correlationid': 'BDD02A22-CD76-4877-90A9-196EDA5DC695',
|
|
146
|
-
'x-appversion':
|
|
147
|
-
accept: '
|
|
152
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
153
|
+
accept: 'application/json',
|
|
148
154
|
'content-type': 'application/json',
|
|
149
|
-
'accept-api-version':
|
|
155
|
+
'accept-api-version': this.API_VERSION,
|
|
150
156
|
},
|
|
151
157
|
data: firstResponse,
|
|
152
158
|
})
|
|
@@ -161,10 +167,13 @@ class Toyota extends utils.Adapter {
|
|
|
161
167
|
this.log.error(JSON.stringify(error.response.data));
|
|
162
168
|
}
|
|
163
169
|
});
|
|
170
|
+
|
|
164
171
|
if (!secondResponse || !secondResponse.callbacks) {
|
|
165
172
|
this.log.error('No Second Response');
|
|
173
|
+
return;
|
|
166
174
|
}
|
|
167
175
|
secondResponse.callbacks[0].input[0].value = this.config.username;
|
|
176
|
+
|
|
168
177
|
const thirdResponse = await this.requestClient({
|
|
169
178
|
method: 'post',
|
|
170
179
|
maxBodyLength: Infinity,
|
|
@@ -181,10 +190,10 @@ class Toyota extends utils.Adapter {
|
|
|
181
190
|
'x-brand': this.brand,
|
|
182
191
|
'accept-language': 'de-DE,de;q=0.9',
|
|
183
192
|
'x-correlationid': 'BDD02A22-CD76-4877-90A9-196EDA5DC695',
|
|
184
|
-
'x-appversion':
|
|
185
|
-
accept: '
|
|
193
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
194
|
+
accept: 'application/json',
|
|
186
195
|
'content-type': 'application/json',
|
|
187
|
-
'accept-api-version':
|
|
196
|
+
'accept-api-version': this.API_VERSION,
|
|
188
197
|
},
|
|
189
198
|
data: secondResponse,
|
|
190
199
|
})
|
|
@@ -199,12 +208,15 @@ class Toyota extends utils.Adapter {
|
|
|
199
208
|
this.log.error(JSON.stringify(error.response.data));
|
|
200
209
|
}
|
|
201
210
|
});
|
|
211
|
+
|
|
202
212
|
if (!thirdResponse || !thirdResponse.callbacks) {
|
|
203
213
|
this.log.error('No Third Response');
|
|
214
|
+
return;
|
|
204
215
|
}
|
|
205
216
|
|
|
206
217
|
thirdResponse.callbacks[0].input[0].value = this.config.password;
|
|
207
|
-
|
|
218
|
+
|
|
219
|
+
await this.requestClient({
|
|
208
220
|
method: 'post',
|
|
209
221
|
maxBodyLength: Infinity,
|
|
210
222
|
url: 'https://b2c-login.toyota-europe.com/json/realms/root/realms/tme/authenticate?authIndexType=service&authIndexValue=oneapp',
|
|
@@ -220,10 +232,10 @@ class Toyota extends utils.Adapter {
|
|
|
220
232
|
'x-brand': this.brand,
|
|
221
233
|
'accept-language': 'de-DE,de;q=0.9',
|
|
222
234
|
'x-correlationid': 'BDD02A22-CD76-4877-90A9-196EDA5DC695',
|
|
223
|
-
'x-appversion':
|
|
224
|
-
accept: '
|
|
235
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
236
|
+
accept: 'application/json',
|
|
225
237
|
'content-type': 'application/json',
|
|
226
|
-
'accept-api-version':
|
|
238
|
+
'accept-api-version': this.API_VERSION,
|
|
227
239
|
},
|
|
228
240
|
data: thirdResponse,
|
|
229
241
|
})
|
|
@@ -239,10 +251,21 @@ class Toyota extends utils.Adapter {
|
|
|
239
251
|
}
|
|
240
252
|
});
|
|
241
253
|
|
|
254
|
+
// PKCE S256: random 64-byte verifier, base64url(SHA-256(verifier)) as challenge (APK 2.23.0)
|
|
255
|
+
// Keep verifier local so concurrent login() calls do not overwrite each other.
|
|
256
|
+
const codeVerifier = crypto.randomBytes(64).toString('base64url');
|
|
257
|
+
const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url');
|
|
258
|
+
const authorizeUrl =
|
|
259
|
+
'https://b2c-login.toyota-europe.com/oauth2/realms/root/realms/tme/authorize' +
|
|
260
|
+
'?response_type=code&realm=tme&redirect_uri=com.toyota.oneapp:/oauth2Callback' +
|
|
261
|
+
'&client_id=oneapp&scope=' +
|
|
262
|
+
encodeURIComponent('openid profile write') +
|
|
263
|
+
'&code_challenge_method=S256&code_challenge=' +
|
|
264
|
+
codeChallenge;
|
|
242
265
|
const tokenResponse = await this.requestClient({
|
|
243
266
|
method: 'get',
|
|
244
267
|
maxBodyLength: Infinity,
|
|
245
|
-
url:
|
|
268
|
+
url: authorizeUrl,
|
|
246
269
|
headers: {
|
|
247
270
|
'x-osname': 'iOS',
|
|
248
271
|
'x-brand': this.brand,
|
|
@@ -256,8 +279,8 @@ class Toyota extends utils.Adapter {
|
|
|
256
279
|
'accept-language': 'de-DE,de;q=0.9',
|
|
257
280
|
region: 'EU',
|
|
258
281
|
'user-agent': 'Toyota/134 CFNetwork/1410.0.3 Darwin/22.6.0',
|
|
259
|
-
'accept-api-version':
|
|
260
|
-
'x-appversion':
|
|
282
|
+
'accept-api-version': this.API_VERSION,
|
|
283
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
261
284
|
},
|
|
262
285
|
})
|
|
263
286
|
.then((res) => {
|
|
@@ -272,10 +295,12 @@ class Toyota extends utils.Adapter {
|
|
|
272
295
|
this.log.error(error);
|
|
273
296
|
error.response && this.log.error(JSON.stringify(error.response.data));
|
|
274
297
|
});
|
|
298
|
+
|
|
275
299
|
if (!tokenResponse || !tokenResponse.code) {
|
|
276
300
|
this.log.error('No Token Response');
|
|
277
301
|
return;
|
|
278
302
|
}
|
|
303
|
+
|
|
279
304
|
this.log.info('Start token exchange');
|
|
280
305
|
await this.requestClient({
|
|
281
306
|
method: 'post',
|
|
@@ -294,16 +319,16 @@ class Toyota extends utils.Adapter {
|
|
|
294
319
|
authorization: 'Basic b25lYXBwOm9uZWFwcA==',
|
|
295
320
|
'accept-language': 'de-DE,de;q=0.9',
|
|
296
321
|
'x-correlationid': 'E422A08C-1A04-415E-BB08-2386EE06CF90',
|
|
297
|
-
'x-appversion':
|
|
322
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
298
323
|
accept: '*/*',
|
|
299
324
|
'content-type': 'application/x-www-form-urlencoded',
|
|
300
|
-
'accept-api-version':
|
|
325
|
+
'accept-api-version': this.API_VERSION,
|
|
301
326
|
},
|
|
302
327
|
data: {
|
|
303
328
|
grant_type: 'authorization_code',
|
|
304
329
|
redirect_uri: 'com.toyota.oneapp:/oauth2Callback',
|
|
305
330
|
code: tokenResponse.code,
|
|
306
|
-
code_verifier:
|
|
331
|
+
code_verifier: codeVerifier,
|
|
307
332
|
client_id: 'oneapp',
|
|
308
333
|
},
|
|
309
334
|
})
|
|
@@ -326,6 +351,7 @@ class Toyota extends utils.Adapter {
|
|
|
326
351
|
}
|
|
327
352
|
});
|
|
328
353
|
}
|
|
354
|
+
|
|
329
355
|
async refreshToken() {
|
|
330
356
|
await this.requestClient({
|
|
331
357
|
method: 'post',
|
|
@@ -344,16 +370,15 @@ class Toyota extends utils.Adapter {
|
|
|
344
370
|
authorization: 'Basic b25lYXBwOm9uZWFwcA==',
|
|
345
371
|
'accept-language': 'de-DE,de;q=0.9',
|
|
346
372
|
'x-correlationid': 'E422A08C-1A04-415E-BB08-2386EE06CF90',
|
|
347
|
-
'x-appversion':
|
|
373
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
348
374
|
accept: '*/*',
|
|
349
375
|
'content-type': 'application/x-www-form-urlencoded',
|
|
350
|
-
'accept-api-version':
|
|
376
|
+
'accept-api-version': this.API_VERSION,
|
|
351
377
|
},
|
|
352
378
|
data: {
|
|
353
379
|
grant_type: 'refresh_token',
|
|
354
380
|
redirect_uri: 'com.toyota.oneapp:/oauth2Callback',
|
|
355
381
|
client_id: 'oneapp',
|
|
356
|
-
code_verifier: 'plain',
|
|
357
382
|
refresh_token: this.session.refresh_token,
|
|
358
383
|
},
|
|
359
384
|
})
|
|
@@ -369,6 +394,94 @@ class Toyota extends utils.Adapter {
|
|
|
369
394
|
}
|
|
370
395
|
});
|
|
371
396
|
}
|
|
397
|
+
|
|
398
|
+
generate_hmac_sha256(key, message) {
|
|
399
|
+
return crypto.createHmac('sha256', key).update(message).digest('hex');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Build the standard set of headers used for all ctpa-oneapi calls.
|
|
404
|
+
* @param {string} [vin] optional vin header for vehicle-scoped endpoints
|
|
405
|
+
*/
|
|
406
|
+
buildApiHeaders(vin) {
|
|
407
|
+
const headers = {
|
|
408
|
+
'x-appbrand': this.brand,
|
|
409
|
+
'x-device-timezone': 'CEST',
|
|
410
|
+
'x-osname': 'iOS',
|
|
411
|
+
guid: this.uuid,
|
|
412
|
+
'user-agent': 'Toyota/134 CFNetwork/1410.0.3 Darwin/22.6.0',
|
|
413
|
+
'x-guid': this.uuid,
|
|
414
|
+
region: 'EU',
|
|
415
|
+
brand: this.brand,
|
|
416
|
+
'x-channel': 'ONEAPP',
|
|
417
|
+
'x-osversion': '16.7.2',
|
|
418
|
+
'x-locale': 'de-DE',
|
|
419
|
+
'x-brand': this.brand,
|
|
420
|
+
authorization: 'Bearer ' + this.session.access_token,
|
|
421
|
+
'accept-language': 'de-DE,de;q=0.9',
|
|
422
|
+
accept: '*/*',
|
|
423
|
+
'x-user-region': 'DE',
|
|
424
|
+
'x-api-key': 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
425
|
+
API_KEY: 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
426
|
+
// x-client-ref: HMAC-SHA256 with the app version as key over the user GUID (APK 2.23.0)
|
|
427
|
+
'x-client-ref': this.generate_hmac_sha256(this.CLIENT_VERSION, this.uuid),
|
|
428
|
+
'x-correlationid': uuidv4(),
|
|
429
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
430
|
+
'x-region': 'EU',
|
|
431
|
+
};
|
|
432
|
+
if (vin) {
|
|
433
|
+
headers.vin = vin;
|
|
434
|
+
}
|
|
435
|
+
return headers;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Wake the car and trigger a fresh vehicle/climate/EV status pull.
|
|
440
|
+
* After ~20s the regular updateDevices() loop reads the now-current data.
|
|
441
|
+
* @param {string} vin
|
|
442
|
+
*/
|
|
443
|
+
async forceRefresh(vin) {
|
|
444
|
+
const refreshEndpoints = [
|
|
445
|
+
{ name: 'status', url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/remote/status' },
|
|
446
|
+
{
|
|
447
|
+
name: 'climate',
|
|
448
|
+
url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/remote/refresh-climate-status',
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
name: 'electric',
|
|
452
|
+
url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/global/remote/electric/realtime-status',
|
|
453
|
+
},
|
|
454
|
+
];
|
|
455
|
+
for (const ep of refreshEndpoints) {
|
|
456
|
+
await this.requestClient({
|
|
457
|
+
method: 'post',
|
|
458
|
+
url: ep.url,
|
|
459
|
+
headers: this.buildApiHeaders(vin),
|
|
460
|
+
})
|
|
461
|
+
.then((res) => {
|
|
462
|
+
this.log.debug(`force-refresh ${ep.name}: ${JSON.stringify(res.data)}`);
|
|
463
|
+
})
|
|
464
|
+
.catch((error) => {
|
|
465
|
+
// Non-EV cars typically answer the electric realtime-status request with 404 or 422 - log quietly.
|
|
466
|
+
// 401/403 must NOT be swallowed: they signal an auth problem and have to surface like for any other endpoint.
|
|
467
|
+
if (
|
|
468
|
+
ep.name === 'electric' &&
|
|
469
|
+
error.response &&
|
|
470
|
+
(error.response.status === 404 || error.response.status === 422)
|
|
471
|
+
) {
|
|
472
|
+
this.log.debug(`force-refresh electric not supported (${error.response.status})`);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
this.log.warn(`force-refresh ${ep.name} failed: ${error.message}`);
|
|
476
|
+
error.response && this.log.debug(JSON.stringify(error.response.data));
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
this.refreshTimeout && clearTimeout(this.refreshTimeout);
|
|
480
|
+
this.refreshTimeout = setTimeout(async () => {
|
|
481
|
+
await this.updateDevices();
|
|
482
|
+
}, 20 * 1000);
|
|
483
|
+
}
|
|
484
|
+
|
|
372
485
|
async getDeviceList() {
|
|
373
486
|
await this.requestClient({
|
|
374
487
|
method: 'get',
|
|
@@ -381,7 +494,6 @@ class Toyota extends utils.Adapter {
|
|
|
381
494
|
guid: this.uuid,
|
|
382
495
|
'user-agent': 'Toyota/134 CFNetwork/1410.0.3 Darwin/22.6.0',
|
|
383
496
|
'x-guid': this.uuid,
|
|
384
|
-
'x-region': 'EU',
|
|
385
497
|
region: 'EU',
|
|
386
498
|
brand: this.brand,
|
|
387
499
|
'x-channel': 'ONEAPP',
|
|
@@ -390,11 +502,15 @@ class Toyota extends utils.Adapter {
|
|
|
390
502
|
'x-brand': this.brand,
|
|
391
503
|
authorization: 'Bearer ' + this.session.access_token,
|
|
392
504
|
'accept-language': 'de-DE,de;q=0.9',
|
|
393
|
-
'x-correlationid': '7683DC30-D4DA-4FEC-850E-F3557A7DCEF4',
|
|
394
|
-
'x-appversion': '2.4.2',
|
|
395
505
|
accept: '*/*',
|
|
396
506
|
'x-user-region': 'DE',
|
|
397
507
|
'x-api-key': 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
508
|
+
API_KEY: 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
509
|
+
// x-client-ref: HMAC-SHA256 with the app version as key over the user GUID (APK 2.23.0)
|
|
510
|
+
'x-client-ref': this.generate_hmac_sha256(this.CLIENT_VERSION, this.uuid),
|
|
511
|
+
'x-correlationid': uuidv4(),
|
|
512
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
513
|
+
'x-region': 'EU',
|
|
398
514
|
},
|
|
399
515
|
})
|
|
400
516
|
.then(async (res) => {
|
|
@@ -437,7 +553,8 @@ class Toyota extends utils.Adapter {
|
|
|
437
553
|
|
|
438
554
|
const remoteArray = [
|
|
439
555
|
{ command: 'climate-control', name: 'True = Start, False = Stop' },
|
|
440
|
-
{ command: 'refresh', name: '
|
|
556
|
+
{ command: 'refresh', name: 'Re-poll cached status from cloud' },
|
|
557
|
+
{ command: 'force-refresh', name: 'Wake car and request fresh status, climate and EV data' },
|
|
441
558
|
{ command: 'door', name: 'True = Lock, False = Unlock' },
|
|
442
559
|
];
|
|
443
560
|
for (const remote of remoteArray) {
|
|
@@ -463,6 +580,8 @@ class Toyota extends utils.Adapter {
|
|
|
463
580
|
error.response && this.log.error(JSON.stringify(error.response.data));
|
|
464
581
|
});
|
|
465
582
|
}
|
|
583
|
+
|
|
584
|
+
// ...existing code...
|
|
466
585
|
async cleanOldObjects(vin) {
|
|
467
586
|
const remoteState = await this.getObjectAsync(vin + '.addtionalInfo');
|
|
468
587
|
if (remoteState) {
|
|
@@ -470,11 +589,12 @@ class Toyota extends utils.Adapter {
|
|
|
470
589
|
await this.delObjectAsync(vin, { recursive: true });
|
|
471
590
|
}
|
|
472
591
|
}
|
|
592
|
+
|
|
473
593
|
async updateDevices() {
|
|
474
594
|
const statusArray = [
|
|
475
595
|
{
|
|
476
596
|
path: 'status',
|
|
477
|
-
url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/
|
|
597
|
+
url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/vehicle/status',
|
|
478
598
|
desc: 'Status of the car',
|
|
479
599
|
},
|
|
480
600
|
{
|
|
@@ -484,9 +604,24 @@ class Toyota extends utils.Adapter {
|
|
|
484
604
|
},
|
|
485
605
|
{
|
|
486
606
|
path: 'climate',
|
|
487
|
-
url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/
|
|
607
|
+
url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/vehicle/climate-status',
|
|
488
608
|
desc: 'Climate of the car',
|
|
489
609
|
},
|
|
610
|
+
{
|
|
611
|
+
path: 'electric',
|
|
612
|
+
url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/global/remote/electric/status',
|
|
613
|
+
desc: 'Electric/PHEV status (battery, charging, range)',
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
path: 'location',
|
|
617
|
+
url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/location',
|
|
618
|
+
desc: 'Current vehicle location',
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
path: 'health',
|
|
622
|
+
url: 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/vehiclehealth/status',
|
|
623
|
+
desc: 'Vehicle health and service warnings',
|
|
624
|
+
},
|
|
490
625
|
];
|
|
491
626
|
|
|
492
627
|
const headers = {
|
|
@@ -496,7 +631,6 @@ class Toyota extends utils.Adapter {
|
|
|
496
631
|
guid: this.uuid,
|
|
497
632
|
'user-agent': 'Toyota/134 CFNetwork/1410.0.3 Darwin/22.6.0',
|
|
498
633
|
'x-guid': this.uuid,
|
|
499
|
-
'x-region': 'EU',
|
|
500
634
|
region: 'EU',
|
|
501
635
|
brand: this.brand,
|
|
502
636
|
'x-channel': 'ONEAPP',
|
|
@@ -505,11 +639,15 @@ class Toyota extends utils.Adapter {
|
|
|
505
639
|
'x-brand': this.brand,
|
|
506
640
|
authorization: 'Bearer ' + this.session.access_token,
|
|
507
641
|
'accept-language': 'de-DE,de;q=0.9',
|
|
508
|
-
'x-correlationid': '7683DC30-D4DA-4FEC-850E-F3557A7DCEF4',
|
|
509
|
-
'x-appversion': '2.4.2',
|
|
510
642
|
accept: '*/*',
|
|
511
643
|
'x-user-region': 'DE',
|
|
512
644
|
'x-api-key': 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
645
|
+
API_KEY: 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
646
|
+
// Updated client-ref generation using new key
|
|
647
|
+
'x-client-ref': this.generate_hmac_sha256(this.CLIENT_VERSION, this.uuid),
|
|
648
|
+
'x-correlationid': uuidv4(),
|
|
649
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
650
|
+
'x-region': 'EU',
|
|
513
651
|
};
|
|
514
652
|
for (const vin of this.deviceArray) {
|
|
515
653
|
for (const element of statusArray) {
|
|
@@ -583,11 +721,9 @@ class Toyota extends utils.Adapter {
|
|
|
583
721
|
'x-appbrand': this.brand,
|
|
584
722
|
'x-device-timezone': 'CEST',
|
|
585
723
|
'x-osname': 'iOS',
|
|
586
|
-
|
|
587
724
|
guid: this.uuid,
|
|
588
725
|
'user-agent': 'Toyota/134 CFNetwork/1410.0.3 Darwin/22.6.0',
|
|
589
726
|
'x-guid': this.uuid,
|
|
590
|
-
'x-region': 'EU',
|
|
591
727
|
region: 'EU',
|
|
592
728
|
brand: this.brand,
|
|
593
729
|
'x-channel': 'ONEAPP',
|
|
@@ -596,11 +732,15 @@ class Toyota extends utils.Adapter {
|
|
|
596
732
|
'x-brand': this.brand,
|
|
597
733
|
authorization: 'Bearer ' + this.session.access_token,
|
|
598
734
|
'accept-language': 'de-DE,de;q=0.9',
|
|
599
|
-
'x-correlationid': '7683DC30-D4DA-4FEC-850E-F3557A7DCEF4',
|
|
600
|
-
'x-appversion': '2.4.2',
|
|
601
735
|
accept: '*/*',
|
|
602
736
|
'x-user-region': 'DE',
|
|
603
737
|
'x-api-key': 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
738
|
+
API_KEY: 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
739
|
+
// Updated client-ref generation using new key
|
|
740
|
+
'x-client-ref': this.generate_hmac_sha256(this.CLIENT_VERSION, this.uuid),
|
|
741
|
+
'x-correlationid': uuidv4(),
|
|
742
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
743
|
+
'x-region': 'EU',
|
|
604
744
|
};
|
|
605
745
|
for (const vin of this.deviceArray) {
|
|
606
746
|
statusArray.forEach(async (element) => {
|
|
@@ -618,6 +758,12 @@ class Toyota extends utils.Adapter {
|
|
|
618
758
|
return;
|
|
619
759
|
}
|
|
620
760
|
const data = res.data.payload;
|
|
761
|
+
for (const trip of data.trips) {
|
|
762
|
+
delete trip.route;
|
|
763
|
+
}
|
|
764
|
+
for (const summary of data.summary) {
|
|
765
|
+
delete summary.histograms;
|
|
766
|
+
}
|
|
621
767
|
this.json2iob.parse(vin + '.' + element.path, data, {
|
|
622
768
|
forceIndex: true,
|
|
623
769
|
channelName: element.desc,
|
|
@@ -643,6 +789,7 @@ class Toyota extends utils.Adapter {
|
|
|
643
789
|
});
|
|
644
790
|
}
|
|
645
791
|
}
|
|
792
|
+
|
|
646
793
|
/**
|
|
647
794
|
* Is called when adapter shuts down - callback has to be called under any circumstances!
|
|
648
795
|
* @param {() => void} callback
|
|
@@ -656,7 +803,7 @@ class Toyota extends utils.Adapter {
|
|
|
656
803
|
this.updateInterval && clearInterval(this.updateInterval);
|
|
657
804
|
this.refreshTokenInterval && clearInterval(this.refreshTokenInterval);
|
|
658
805
|
callback();
|
|
659
|
-
} catch
|
|
806
|
+
} catch {
|
|
660
807
|
callback();
|
|
661
808
|
}
|
|
662
809
|
}
|
|
@@ -678,10 +825,14 @@ class Toyota extends utils.Adapter {
|
|
|
678
825
|
this.updateDevices();
|
|
679
826
|
return;
|
|
680
827
|
}
|
|
828
|
+
if (path === 'force-refresh') {
|
|
829
|
+
await this.forceRefresh(deviceId);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
681
832
|
const data = {};
|
|
682
833
|
let url = 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v1/global/remote/command';
|
|
683
834
|
if (path === 'climate-control') {
|
|
684
|
-
url = 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/
|
|
835
|
+
url = 'https://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io/v2/remote/climate-control';
|
|
685
836
|
data.command = state.val ? 'engine-start' : 'engine-stop';
|
|
686
837
|
}
|
|
687
838
|
if (path === 'door') {
|
|
@@ -697,25 +848,27 @@ class Toyota extends utils.Adapter {
|
|
|
697
848
|
'x-appbrand': this.brand,
|
|
698
849
|
'x-device-timezone': 'CEST',
|
|
699
850
|
'x-osname': 'iOS',
|
|
700
|
-
guid:
|
|
851
|
+
guid: this.uuid,
|
|
701
852
|
'user-agent': 'Toyota/134 CFNetwork/1410.0.3 Darwin/22.6.0',
|
|
702
|
-
'x-guid':
|
|
703
|
-
'x-region': 'EU',
|
|
853
|
+
'x-guid': this.uuid,
|
|
704
854
|
region: 'EU',
|
|
705
855
|
brand: this.brand,
|
|
706
856
|
'x-channel': 'ONEAPP',
|
|
707
|
-
vin:
|
|
857
|
+
vin: deviceId,
|
|
708
858
|
'x-osversion': '16.7.2',
|
|
709
859
|
'x-locale': 'de-DE',
|
|
710
860
|
'x-brand': this.brand,
|
|
711
861
|
authorization: 'Bearer ' + this.session.access_token,
|
|
712
862
|
'accept-language': 'de-DE,de;q=0.9',
|
|
713
|
-
'x-correlationid': 'D7F048C1-F0A1-4920-AA37-264C8A1FB4A3',
|
|
714
|
-
'x-appversion': '2.4.2',
|
|
715
863
|
accept: '*/*',
|
|
716
|
-
'content-type': 'application/json',
|
|
717
|
-
'x-api-key': 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
718
864
|
'x-user-region': 'DE',
|
|
865
|
+
'x-api-key': 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
866
|
+
API_KEY: 'tTZipv6liF74PwMfk9Ed68AQ0bISswwf3iHQdqcF',
|
|
867
|
+
// Updated client-ref generation using new key
|
|
868
|
+
'x-client-ref': this.generate_hmac_sha256(this.CLIENT_VERSION, this.uuid),
|
|
869
|
+
'x-correlationid': uuidv4(),
|
|
870
|
+
'x-appversion': this.CLIENT_VERSION,
|
|
871
|
+
'x-region': 'EU',
|
|
719
872
|
},
|
|
720
873
|
data: data,
|
|
721
874
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.toyota",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Adapter for myT Toyota/Lexus App",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TA2k",
|
|
@@ -23,21 +23,27 @@
|
|
|
23
23
|
"url": "https://github.com/TA2k/ioBroker.toyota"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@iobroker/adapter-core": "^3.
|
|
27
|
-
"axios": "^1.
|
|
28
|
-
"http-cookie-agent": "^
|
|
29
|
-
"json2iob": "^2.6.
|
|
30
|
-
"jsonwebtoken": "^9.0.
|
|
31
|
-
"qs": "^6.
|
|
32
|
-
"tough-cookie": "^
|
|
26
|
+
"@iobroker/adapter-core": "^3.4.1",
|
|
27
|
+
"axios": "^1.18.0",
|
|
28
|
+
"http-cookie-agent": "^8.0.0",
|
|
29
|
+
"json2iob": "^2.6.25",
|
|
30
|
+
"jsonwebtoken": "^9.0.3",
|
|
31
|
+
"qs": "^6.15.2",
|
|
32
|
+
"tough-cookie": "^6.0.1",
|
|
33
|
+
"uuid": "^14.0.1"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
37
|
-
"
|
|
38
|
-
"
|
|
36
|
+
"@eslint/js": "^10.0.1",
|
|
37
|
+
"@iobroker/testing": "^5.2.2",
|
|
38
|
+
"@types/node": "^26.0.0",
|
|
39
|
+
"eslint": "^10.5.0",
|
|
40
|
+
"globals": "^17.6.0",
|
|
41
|
+
"typescript": "~6.0.3"
|
|
39
42
|
},
|
|
40
43
|
"main": "main.js",
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=22.13.0"
|
|
46
|
+
},
|
|
41
47
|
"files": [
|
|
42
48
|
"admin{,/!(src)/**}/!(tsconfig|tsconfig.*).json",
|
|
43
49
|
"admin{,/!(src)/**}/*.{html,css,png,svg,jpg,js}",
|
|
@@ -60,4 +66,5 @@
|
|
|
60
66
|
"url": "https://github.com/TA2k/ioBroker.toyota/issues"
|
|
61
67
|
},
|
|
62
68
|
"readmeFilename": "README.md"
|
|
69
|
+
|
|
63
70
|
}
|