iobroker.toyota 0.0.4 → 0.2.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.
@@ -1,10 +1,8 @@
1
1
  <html>
2
-
3
- <head>
4
-
2
+ <head>
5
3
  <!-- Load ioBroker scripts and styles-->
6
4
  <link rel="stylesheet" type="text/css" href="../../css/adapter.css" />
7
- <link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css">
5
+ <link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css" />
8
6
 
9
7
  <script type="text/javascript" src="../../lib/js/jquery-3.2.1.min.js"></script>
10
8
  <script type="text/javascript" src="../../socket.io/socket.io.js"></script>
@@ -18,84 +16,85 @@
18
16
  <script type="text/javascript" src="words.js"></script>
19
17
 
20
18
  <script type="text/javascript">
21
- // This will be called by the admin adapter when the settings page loads
22
- function load(settings, onChange) {
23
- // example: select elements with id=key and class=value and insert value
24
- if (!settings) return;
25
- $('.value').each(function () {
26
- var $key = $(this);
27
- var id = $key.attr('id');
28
- if ($key.attr('type') === 'checkbox') {
29
- // do not call onChange direct, because onChange could expect some arguments
30
- $key.prop('checked', settings[id])
31
- .on('change', () => onChange())
32
- ;
33
- } else {
34
- // do not call onChange direct, because onChange could expect some arguments
35
- $key.val(settings[id])
36
- .on('change', () => onChange())
37
- .on('keyup', () => onChange())
38
- ;
39
- }
40
- });
41
- onChange(false);
42
- // reinitialize all the Materialize labels on the page if you are dynamically adding inputs:
43
- if (M) M.updateTextFields();
44
- }
45
-
46
- // This will be called by the admin adapter when the user presses the save button
47
- function save(callback) {
48
- // example: select elements with class=value and build settings object
49
- var obj = {};
50
- $('.value').each(function () {
51
- var $this = $(this);
52
- if ($this.attr('type') === 'checkbox') {
53
- obj[$this.attr('id')] = $this.prop('checked');
54
- } else if ($this.attr('type') === 'number') {
55
- obj[$this.attr('id')] = parseFloat($this.val());
56
- } else {
57
- obj[$this.attr('id')] = $this.val();
58
- }
59
- });
60
- callback(obj);
61
- }
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
+ }
41
+
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
+ }
62
58
  </script>
59
+ </head>
63
60
 
64
- </head>
65
-
66
- <body>
67
-
61
+ <body>
68
62
  <div class="m adapter-container">
69
-
70
- <div class="row">
71
- <div class="col s12 m4 l2">
72
- <img src="toyota.png" class="logo">
73
- </div>
63
+ <div class="row">
64
+ <div class="col s12 m4 l2">
65
+ <img src="toyota.png" class="logo" />
74
66
  </div>
67
+ </div>
75
68
 
76
- <!-- Put your content here -->
69
+ <!-- Put your content here -->
77
70
 
78
- <div class="row">
79
- <div class="col s6 input-field">
80
- <input type="text" class="value" id="username" />
81
- <label for="username" class="translate">App Email</label>
82
- </div>
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>
83
75
  </div>
84
- <div class="row">
85
- <div class="col s6 input-field">
86
- <input type="password" class="value" id="password" />
87
- <label for="password" class="translate">App Password</label>
88
- </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>
89
81
  </div>
90
-
91
- <div class="row">
92
- <div class="col s2 input-field">
93
- <input type="number" class="value" id="interval" />
94
- <label for="interval" class="translate">Update interval in minutes</label>
95
- </div>
82
+ </div>
83
+ <div class="row">
84
+ <div class="col s2 input-field">
85
+ <select id="type" class="value">
86
+ <option value="toyota">Toyota</option>
87
+ <option value="lexus">Lexus</option>
88
+ </select>
89
+ <label for="type" class="translate">App Toyota or Lexus</label>
90
+ </div>
91
+ </div>
92
+ <div class="row">
93
+ <div class="col s2 input-field">
94
+ <input type="number" class="value" id="interval" />
95
+ <label for="interval" class="translate">Update interval in minutes</label>
96
96
  </div>
97
+ </div>
97
98
  </div>
98
-
99
- </body>
100
-
101
- </html>
99
+ </body>
100
+ </html>
package/io-package.json CHANGED
@@ -1,8 +1,16 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "toyota",
4
- "version": "0.0.4",
4
+ "version": "0.2.0",
5
5
  "news": {
6
+ "0.2.0": {
7
+ "en": "added Lexus support",
8
+ "de": "Lexus Unterstützung hinzugefügt"
9
+ },
10
+ "0.1.0": {
11
+ "en": "added new Charging API endpoints and AC Remote Control",
12
+ "de": "hinzugefügt neue API-Endpunkte für das Laden und starten der Klimaanlage Remote Control"
13
+ },
6
14
  "0.0.4": {
7
15
  "en": "updated new API endpoints",
8
16
  "de": "aktualisierte neue API-Endpunkte"
@@ -20,33 +28,33 @@
20
28
  "zh-cn": "首次出版"
21
29
  }
22
30
  },
23
- "title": "MyT Toyota",
31
+ "title": "myT Toyota/Lexus",
24
32
  "titleLang": {
25
- "en": "MyT Toyota",
26
- "de": "MyT Toyota",
27
- "ru": "MyT Toyota",
28
- "pt": "MyT Toyota",
33
+ "en": "myT Toyota/Lexus",
34
+ "de": "myT Toyota/Lexus",
35
+ "ru": "myT Toyota/Lexus",
36
+ "pt": "myT Toyota/Lexus",
29
37
  "nl": "MijnT Toyota",
30
- "fr": "MyT Toyota",
31
- "it": "MyT Toyota",
32
- "es": "MyT Toyota",
33
- "pl": "MyT Toyota",
38
+ "fr": "myT Toyota/Lexus",
39
+ "it": "myT Toyota/Lexus",
40
+ "es": "myT Toyota/Lexus",
41
+ "pl": "myT Toyota/Lexus",
34
42
  "zh-cn": "丰田"
35
43
  },
36
44
  "desc": {
37
- "en": "Adapter for myT Toyota App",
38
- "de": "Adapter für myT Toyota App",
39
- "ru": "Адаптер для приложения myT Toyota",
40
- "pt": "Adaptador para myT Toyota App",
41
- "nl": "Adapter voor myT Toyota-app",
42
- "fr": "Adaptateur pour l'application myT Toyota",
43
- "it": "Adattatore per app myT Toyota",
44
- "es": "Adaptador para la aplicación myT Toyota",
45
- "pl": "Adapter do aplikacji myT Toyota",
46
- "zh-cn": "适用于 myT Toyota App 的适配器"
45
+ "en": "Adapter for myT Toyota/Lexus App",
46
+ "de": "Adapter für myT Toyota/Lexus App",
47
+ "ru": "Адаптер для приложения myT Toyota/Lexus",
48
+ "pt": "Adaptador para myT Toyota/Lexus App",
49
+ "nl": "Adapter voor myT Toyota/Lexus-app",
50
+ "fr": "Adaptateur pour l'application myT Toyota/Lexus",
51
+ "it": "Adattatore per app myT Toyota/Lexus",
52
+ "es": "Adaptador para la aplicación myT Toyota/Lexus",
53
+ "pl": "Adapter do aplikacji myT Toyota/Lexus",
54
+ "zh-cn": "适用于 myT Toyota/Lexus App 的适配器"
47
55
  },
48
56
  "authors": ["TA2k <tombox2020@gmail.com>"],
49
- "keywords": ["toyota", "myt"],
57
+ "keywords": ["toyota", "myt", "lexus"],
50
58
  "license": "MIT",
51
59
  "platform": "Javascript/Node.js",
52
60
  "main": "main.js",
@@ -82,6 +90,7 @@
82
90
  "native": {
83
91
  "username": "",
84
92
  "password": "",
93
+ "type": "toyota",
85
94
  "interval": 10
86
95
  },
87
96
  "objects": [],
package/main.js CHANGED
@@ -7,8 +7,8 @@
7
7
  // The adapter-core module gives you access to the core ioBroker functions
8
8
  // you need to create an adapter
9
9
  const utils = require("@iobroker/adapter-core");
10
- const axios = require("axios");
11
- const Json2iob = require("./lib/json2iob");
10
+ const axios = require("axios").default;
11
+ const Json2iob = require("json2iob");
12
12
 
13
13
  class Toyota extends utils.Adapter {
14
14
  /**
@@ -30,6 +30,8 @@ class Toyota extends utils.Adapter {
30
30
  this.updateInterval = null;
31
31
  this.reLoginTimeout = null;
32
32
  this.refreshTokenTimeout = null;
33
+ this.hostName = "" + this.hostName + "";
34
+ this.brand = "TOYOTA";
33
35
  }
34
36
 
35
37
  /**
@@ -43,7 +45,11 @@ class Toyota extends utils.Adapter {
43
45
  this.config.interval = 0.5;
44
46
  }
45
47
  this.subscribeStates("*");
46
-
48
+ if (this.config.type === "lexus") {
49
+ this.log.info("Login to Lexus");
50
+ this.brand = "LEXUS";
51
+ this.hostName = "lexuslink-agg.toyota-europe.com";
52
+ }
47
53
  await this.login();
48
54
 
49
55
  if (this.token && this.uuid) {
@@ -60,14 +66,14 @@ class Toyota extends utils.Adapter {
60
66
  async login() {
61
67
  this.session_data = await this.requestClient({
62
68
  method: "post",
63
- url: "https://myt-agg.toyota-europe.com/cma/api/user/login",
69
+ url: "https://" + this.hostName + "/cma/api/user/login",
64
70
  headers: {
65
71
  accept: "*/*",
66
72
  "content-type": "application/json",
67
73
  "x-tme-locale": "en-gb",
68
- "x-tme-brand": "TOYOTA",
69
- "x-tme-app-version": "4.10.0",
70
- "user-agent": "MyT/4.10.0 iPhone10,5 iOS/14.8 CFNetwork/1240.0.4 Darwin/20.6.0",
74
+ "x-tme-brand": this.brand,
75
+ "x-tme-app-version": "4.18.1",
76
+ "user-agent": "MyT/4.18.1 iPhone10,5 iOS/14.8 CFNetwork/1240.0.4 Darwin/20.6.0",
71
77
  "accept-language": "de-DE",
72
78
  },
73
79
  data: JSON.stringify({
@@ -95,15 +101,15 @@ class Toyota extends utils.Adapter {
95
101
  async getDeviceList() {
96
102
  await this.requestClient({
97
103
  method: "get",
98
- url: "https://myt-agg.toyota-europe.com/cma/api/user/" + this.uuid + "/vehicle/details",
104
+ url: "https://" + this.hostName + "/cma/api/user/" + this.uuid + "/vehicle/details?allServices=true",
99
105
  headers: {
100
106
  cookie: "iPlanetDirectoryPro=" + this.token,
101
107
  accept: "*/*",
102
108
  "x-tme-locale": "de-de",
103
- "x-tme-app-version": "4.10.0",
104
- "user-agent": "MyT/4.10.0 iPhone10,5 iOS/14.8 CFNetwork/1240.0.4 Darwin/20.6.0",
109
+ "x-tme-app-version": "4.18.1",
110
+ "user-agent": "MyT/4.18.1 iPhone10,5 iOS/14.8 CFNetwork/1240.0.4 Darwin/20.6.0",
105
111
  "accept-language": "de-DE",
106
- "x-tme-brand": "TOYOTA",
112
+ "x-tme-brand": this.brand,
107
113
  },
108
114
  })
109
115
  .then(async (res) => {
@@ -116,6 +122,7 @@ class Toyota extends utils.Adapter {
116
122
  }
117
123
  this.deviceArray.push(device.vin);
118
124
  const name = device.alias;
125
+ this.log.info("Create vehicle " + device.vin + " " + name);
119
126
  await this.setObjectNotExistsAsync(device.vin, {
120
127
  type: "device",
121
128
  common: {
@@ -168,24 +175,29 @@ class Toyota extends utils.Adapter {
168
175
  const statusArray = [
169
176
  {
170
177
  path: "status",
171
- url: "https://myt-agg.toyota-europe.com/cma/api/users/" + this.uuid + "/vehicles/$vin/vehicleStatus",
178
+ url: "https://" + this.hostName + "/cma/api/users/" + this.uuid + "/vehicles/$vin/vehicleStatus",
172
179
  desc: "Status of the car",
173
180
  },
174
181
  {
175
182
  path: "addtionalInfo",
176
- url: "https://myt-agg.toyota-europe.com/cma/api/vehicle/$vin/addtionalInfo",
183
+ url: "https://" + this.hostName + "/cma/api/vehicle/$vin/addtionalInfo",
177
184
  desc: "AddtionalInfo of the car",
178
185
  },
179
186
  {
180
187
  path: "location",
181
- url: "https://myt-agg.toyota-europe.com/cma/api/users/" + this.uuid + "/vehicle/location",
188
+ url: "https://" + this.hostName + "/cma/api/users/" + this.uuid + "/vehicle/location",
182
189
  desc: "Location of the car",
183
190
  },
184
191
  {
185
192
  path: "parking",
186
- url: "https://myt-agg.toyota-europe.com/cma/api/users/" + this.uuid + "/vehicles/$vin/parking",
193
+ url: "https://" + this.hostName + "/cma/api/users/" + this.uuid + "/vehicles/$vin/parking",
187
194
  desc: "Parking of the car",
188
195
  },
196
+ {
197
+ path: "statusV2",
198
+ url: "https://" + this.hostName + "/cma/api/vehicles/$vin/remoteControl/status",
199
+ desc: "Additional Status Information",
200
+ },
189
201
  ];
190
202
 
191
203
  const headers = {
@@ -196,7 +208,7 @@ class Toyota extends utils.Adapter {
196
208
  "x-tme-app-version": "4.15.0",
197
209
  "user-agent": "MyT/4.15.0 iPhone10,5 iOS/14.8 CFNetwork/1240.0.4 Darwin/20.6.0",
198
210
  "accept-language": "de-DE",
199
- "x-tme-brand": "TOYOTA",
211
+ "x-tme-brand": this.brand,
200
212
  };
201
213
  this.deviceArray.forEach(async (vin) => {
202
214
  statusArray.forEach(async (element) => {
@@ -279,8 +291,27 @@ class Toyota extends utils.Adapter {
279
291
  if (path === "hvac-temperature") {
280
292
  return;
281
293
  }
282
- const data = {};
283
- const url = "https://myt-agg.toyota-europe.com/cma/api/user/" + this.uuid + "/vehicle/" + deviceId + "/remoteControl";
294
+ const hvacTemperatureState = await this.getStateAsync(deviceId + ".remote.hvac-temperature");
295
+ let hvacTemperature = 22;
296
+ if (hvacTemperatureState) {
297
+ hvacTemperature = hvacTemperatureState.val;
298
+ }
299
+
300
+ const data = {
301
+ RemoteHvac: {
302
+ Option: {
303
+ RearDefogger: 0,
304
+ FrontDefogger: 0,
305
+ },
306
+ Sw: state.val ? 1 : 0,
307
+ Temperature: {
308
+ TemperatureUnit: 1,
309
+ SettingType: 0,
310
+ SettingTemperature: hvacTemperature,
311
+ },
312
+ },
313
+ };
314
+ const url = "https://" + this.hostName + "/cma/api/user/" + this.uuid + "/vehicle/" + deviceId + "/remoteControl";
284
315
  this.log.debug(JSON.stringify(data));
285
316
  this.log.debug(url);
286
317
  await this.requestClient({
@@ -290,10 +321,10 @@ class Toyota extends utils.Adapter {
290
321
  cookie: "iPlanetDirectoryPro=" + this.token,
291
322
  accept: "*/*",
292
323
  "x-tme-locale": "de-de",
293
- "x-tme-app-version": "4.10.0",
294
- "user-agent": "MyT/4.10.0 iPhone10,5 iOS/14.8 CFNetwork/1240.0.4 Darwin/20.6.0",
324
+ "x-tme-app-version": "4.18.1",
325
+ "user-agent": "MyT/4.18.1 iPhone10,5 iOS/14.8 CFNetwork/1240.0.4 Darwin/20.6.0",
295
326
  "accept-language": "de-DE",
296
- "x-tme-brand": "TOYOTA",
327
+ "x-tme-brand": this.brand,
297
328
  },
298
329
  data: data,
299
330
  })
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "iobroker.toyota",
3
- "version": "0.0.4",
4
- "description": "Adapter for myT Toyota App",
3
+ "version": "0.2.0",
4
+ "description": "Adapter for myT Toyota/Lexus App",
5
5
  "author": {
6
6
  "name": "TA2k",
7
7
  "email": "tombox2020@gmail.com"
@@ -15,6 +15,7 @@
15
15
  "license": "MIT",
16
16
  "keywords": [
17
17
  "toyota",
18
+ "lexus",
18
19
  "myt"
19
20
  ],
20
21
  "repository": {
@@ -22,28 +23,28 @@
22
23
  "url": "https://github.com/TA2k/ioBroker.toyota"
23
24
  },
24
25
  "dependencies": {
25
- "@iobroker/adapter-core": "^2.6.7",
26
- "axios": "^1.3.4",
27
- "json-bigint": "^1.0.0"
26
+ "@iobroker/adapter-core": "^3.0.4",
27
+ "axios": "^1.5.1",
28
+ "json2iob": "^2.4.8"
28
29
  },
29
30
  "devDependencies": {
30
31
  "@iobroker/testing": "^4.1.0",
31
- "@types/chai": "^4.3.4",
32
- "@types/chai-as-promised": "^7.1.5",
33
- "@types/gulp": "^4.0.10",
34
- "@types/mocha": "^10.0.1",
35
- "@types/node": "^18.15.5",
36
- "@types/proxyquire": "^1.3.28",
37
- "@types/sinon": "^10.0.13",
38
- "@types/sinon-chai": "^3.2.9",
39
- "chai": "^4.3.7",
32
+ "@types/chai": "^4.3.9",
33
+ "@types/chai-as-promised": "^7.1.7",
34
+ "@types/gulp": "^4.0.16",
35
+ "@types/mocha": "^10.0.2",
36
+ "@types/node": "^20.8.6",
37
+ "@types/proxyquire": "^1.3.29",
38
+ "@types/sinon": "^10.0.19",
39
+ "@types/sinon-chai": "^3.2.10",
40
+ "chai": "^4.3.10",
40
41
  "chai-as-promised": "^7.1.1",
41
- "eslint": "^8.36.0",
42
+ "eslint": "^8.51.0",
42
43
  "mocha": "^10.2.0",
43
44
  "proxyquire": "^2.1.3",
44
- "sinon": "^15.0.2",
45
+ "sinon": "^15.2.0",
45
46
  "sinon-chai": "^3.7.0",
46
- "typescript": "~5.0.2"
47
+ "typescript": "~5.2.2"
47
48
  },
48
49
  "main": "main.js",
49
50
  "files": [