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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.renault",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "Adapter for Renault and Renault",
5
5
  "author": {
6
6
  "name": "TA2k",
@@ -14,6 +14,7 @@
14
14
  "homepage": "https://github.com/TA2k/ioBroker.renault",
15
15
  "license": "MIT",
16
16
  "keywords": [
17
+ "ioBroker",
17
18
  "renault",
18
19
  "Renault",
19
20
  "dacia",
@@ -24,31 +25,33 @@
24
25
  "url": "https://github.com/TA2k/ioBroker.renault"
25
26
  },
26
27
  "dependencies": {
27
- "@iobroker/adapter-core": "^2.6.8",
28
- "axios": "^1.4.0",
28
+ "@iobroker/adapter-core": "^3.3.2",
29
+ "axios": "^1.16.1",
29
30
  "json-bigint": "^1.0.0",
30
- "json2iob": "^2.4.5",
31
- "qs": "^6.11.2"
31
+ "json2iob": "^2.6.22",
32
+ "qs": "^6.15.2"
32
33
  },
33
34
  "devDependencies": {
34
- "@iobroker/testing": "^4.1.0",
35
- "@types/chai": "^4.3.5",
36
- "@types/chai-as-promised": "^7.1.5",
37
- "@types/mocha": "^10.0.1",
38
- "@types/node": "^18.16.19",
39
- "@types/proxyquire": "^1.3.28",
40
- "@types/sinon": "^10.0.15",
41
- "@types/sinon-chai": "^3.2.9",
42
- "chai": "^4.3.7",
43
- "chai-as-promised": "^7.1.1",
44
- "eslint": "^8.44.0",
45
- "mocha": "^10.2.0",
46
- "proxyquire": "^2.1.3",
47
- "sinon": "^15.2.0",
48
- "sinon-chai": "^3.7.0",
49
- "typescript": "^5.1.6"
35
+ "@alcalzone/release-script": "^5.2.0",
36
+ "@alcalzone/release-script-plugin-iobroker": "^5.2.0",
37
+ "@alcalzone/release-script-plugin-license": "^5.2.0",
38
+ "@alcalzone/release-script-plugin-manual-review": "^5.2.0",
39
+ "@eslint/eslintrc": "^3.3.5",
40
+ "@eslint/js": "^10.0.1",
41
+ "@iobroker/testing": "^5.2.2",
42
+ "@tsconfig/node18": "^18.2.6",
43
+ "@types/node": "^25.9.1",
44
+ "eslint": "^10.4.0",
45
+ "eslint-config-prettier": "^10.1.8",
46
+ "eslint-plugin-prettier": "^5.5.5",
47
+ "globals": "^17.6.0",
48
+ "prettier": "^3.8.3",
49
+ "typescript": "~6.0.3"
50
50
  },
51
51
  "main": "main.js",
52
+ "engines": {
53
+ "node": ">=20"
54
+ },
52
55
  "files": [
53
56
  "admin{,/!(src)/**}/!(tsconfig|tsconfig.*).json",
54
57
  "admin{,/!(src)/**}/*.{html,css,png,svg,jpg,js}",
@@ -61,11 +64,13 @@
61
64
  "scripts": {
62
65
  "test:js": "mocha --config test/mocharc.custom.json \"{!(node_modules|test)/**/*.test.js,*.test.js,test/**/test!(PackageFiles|Startup).js}\"",
63
66
  "test:package": "mocha test/package --exit",
64
- "test:unit": "mocha test/unit --exit",
65
67
  "test:integration": "mocha test/integration --exit",
68
+ "test:unit": "mocha test/unit --exit",
66
69
  "test": "npm run test:js && npm run test:package",
67
70
  "check": "tsc --noEmit -p tsconfig.check.json",
68
- "lint": "eslint"
71
+ "lint": "eslint .",
72
+ "translate": "translate-adapter",
73
+ "release": "release-script --all"
69
74
  },
70
75
  "bugs": {
71
76
  "url": "https://github.com/TA2k/ioBroker.renault/issues"
@@ -1,105 +0,0 @@
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" />
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>
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>
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>
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
- }
40
-
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>
59
-
60
- <body>
61
- <div class="m adapter-container">
62
- <div class="row">
63
- <div class="col s12 m4 l2">
64
- <img src="renault.png" class="logo" />
65
- </div>
66
- </div>
67
-
68
- <!-- Put your content here -->
69
-
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
-
84
- <div class="row">
85
- <div class="col s2 input-field">
86
- <input type="number" class="value" id="interval" />
87
- <label for="interval" class="translate">Update interval in minutes</label>
88
- </div>
89
- </div>
90
- <div class="row">
91
- <div class="col s6 input-field">
92
- <input type="text" class="value" id="country" />
93
- <label for="country" class="translate">Country</label>
94
- </div>
95
- </div>
96
- <div class="row">
97
- <div class="col s6 input-field">
98
- <input type="text" class="value" id="apiKeyUpdate" />
99
- <label for="apiKeyUpdate" class="translate">API Key. Wenn leer wird es automatisch gesetzt.</label>
100
- </div>
101
- <a href="https://github.com/db-EV/ZoePHP/blob/main/src/api-keys.php" target="_blank" class="translate">Click here for Current API Key</a>
102
- </div>
103
- </div>
104
- </body>
105
- </html>
package/admin/style.css DELETED
@@ -1,32 +0,0 @@
1
- /* You can delete those if you want. I just found them very helpful */
2
- * {
3
- box-sizing: border-box
4
- }
5
- .m {
6
- /* Don't cut off dropdowns! */
7
- overflow: initial;
8
- }
9
- .m.adapter-container,
10
- .m.adapter-container > div.App {
11
- /* Fix layout/scrolling issues with tabs */
12
- height: 100%;
13
- width: 100%;
14
- position: relative;
15
- }
16
- .m .select-wrapper + label {
17
- /* The positioning for dropdown labels is messed up */
18
- transform: none !important;
19
- }
20
-
21
- label > i[title] {
22
- /* Display the help cursor for the tooltip icons and fix their positioning */
23
- cursor: help;
24
- margin-left: 0.25em;
25
- }
26
-
27
- .dropdown-content {
28
- /* Don't wrap text in dropdowns */
29
- white-space: nowrap;
30
- }
31
-
32
- /* Add your styles here */
package/admin/words.js DELETED
@@ -1,65 +0,0 @@
1
- /*global systemDictionary:true */
2
- "use strict";
3
-
4
- systemDictionary = {
5
- "renault adapter settings": {
6
- en: "Adapter settings for renault",
7
- de: "Adaptereinstellungen für renault",
8
- ru: "Настройки адаптера для renault",
9
- pt: "Configurações do adaptador para renault",
10
- nl: "Adapterinstellingen voor renault",
11
- fr: "Paramètres d'adaptateur pour renault",
12
- it: "Impostazioni dell'adattatore per renault",
13
- es: "Ajustes del adaptador para renault",
14
- pl: "Ustawienia adaptera dla renault",
15
- "zh-cn": "renault的适配器设置",
16
- },
17
- "App Email": {
18
- en: "App Email",
19
- de: "App-E-Mail",
20
- ru: "Электронная почта приложения",
21
- pt: "Email do aplicativo",
22
- nl: "App-e-mail",
23
- fr: "Courriel de l'application",
24
- it: "E-mail dell'app",
25
- es: "Correo electrónico de la aplicación",
26
- pl: "E-mail aplikacji",
27
- "zh-cn": "应用电子邮件",
28
- },
29
- "App Password": {
30
- en: "App Password",
31
- de: "App-Passwort",
32
- ru: "Пароль приложения",
33
- pt: "Senha de app",
34
- nl: "App-wachtwoord",
35
- fr: "Mot de passe de l'application",
36
- it: "Password dell'app",
37
- es: "Contraseña de la aplicación",
38
- pl: "Hasło do aplikacji",
39
- "zh-cn": "应用密码",
40
- },
41
- "Update interval (in minutes)": {
42
- en: "Update interval (in minutes)",
43
- de: "Aktualisierungsintervall (in Minuten)",
44
- ru: "Интервал обновления (в минутах)",
45
- pt: "Intervalo de atualização (em minutos)",
46
- nl: "Update-interval (in minuten)",
47
- fr: "Intervalle de mise à jour (en minutes)",
48
- it: "Intervallo di aggiornamento (in minuti)",
49
- es: "Intervalo de actualización (en minutos)",
50
- pl: "Interwał aktualizacji (w minutach)",
51
- "zh-cn": "更新间隔(分钟)",
52
- },
53
- Country: {
54
- en: "Country",
55
- de: "Land",
56
- ru: "Страна",
57
- pt: "País",
58
- nl: "Land",
59
- fr: "Pays",
60
- it: "Nazione",
61
- es: "País",
62
- pl: "Kraj",
63
- "zh-cn": "国家",
64
- },
65
- };
package/lib/json2iob.js DELETED
@@ -1,254 +0,0 @@
1
- //v1.1 custom renault
2
- /*
3
- options:
4
- write
5
- forceIndex
6
- channelName
7
- preferedArrayName
8
- noAutoCast (true false)
9
- descriptions: Object of names for states
10
- */
11
- const JSONbig = require("json-bigint")({ storeAsString: true });
12
- module.exports = class Json2iob {
13
- constructor(adapter) {
14
- this.adapter = adapter;
15
- this.alreadyCreatedObjects = {};
16
- }
17
-
18
- async parse(path, element, options) {
19
- try {
20
- if (element === null || element === undefined) {
21
- this.adapter.log.debug("Cannot extract empty: " + path);
22
- return;
23
- }
24
-
25
- const objectKeys = Object.keys(element);
26
-
27
- if (!options || !options.write) {
28
- if (!options) {
29
- options = { write: false };
30
- } else {
31
- options["write"] = false;
32
- }
33
- }
34
-
35
- if (typeof element === "string" || typeof element === "number") {
36
- let name = element;
37
- if (typeof element === "number") {
38
- name = element.toString();
39
- }
40
- if (!this.alreadyCreatedObjects[path]) {
41
- await this.adapter
42
- .setObjectNotExistsAsync(path, {
43
- type: "state",
44
- common: {
45
- name: name,
46
- role: this.getRole(element, options.write),
47
- type: element !== null ? typeof element : "mixed",
48
- write: options.write,
49
- read: true,
50
- },
51
- native: {},
52
- })
53
- .then(() => {
54
- this.alreadyCreatedObjects[path] = true;
55
- })
56
- .catch((error) => {
57
- this.adapter.log.error(error);
58
- });
59
- }
60
-
61
- this.adapter.setState(path, element, true);
62
-
63
- return;
64
- }
65
- if (!this.alreadyCreatedObjects[path]) {
66
- await this.adapter
67
- .setObjectNotExistsAsync(path, {
68
- type: "channel",
69
- common: {
70
- name: options.channelName || "",
71
- write: false,
72
- read: true,
73
- },
74
- native: {},
75
- })
76
- .then(() => {
77
- this.alreadyCreatedObjects[path] = true;
78
- })
79
- .catch((error) => {
80
- this.adapter.log.error(error);
81
- });
82
- }
83
- if (Array.isArray(element)) {
84
- this.extractArray(element, "", path, options);
85
- return;
86
- }
87
- objectKeys.forEach(async (key) => {
88
- // if (this.isJsonString(element[key]) && !options.noAutoCast) {
89
- // element[key] = JSONbig.parse(element[key]);
90
- // }
91
-
92
- if (Array.isArray(element[key])) {
93
- this.extractArray(element, key, path, options);
94
- } else if (element[key] !== null && typeof element[key] === "object") {
95
- this.parse(path + "." + key, element[key], options);
96
- } else {
97
- if (!this.alreadyCreatedObjects[path + "." + key]) {
98
- let objectName = key;
99
- if (options.descriptions && options.descriptions[key]) {
100
- objectName = options.descriptions[key];
101
- }
102
- let type = element[key] !== null ? typeof element[key] : "mixed";
103
- if (key === "gpsLatitude" || key === "gpsLongitude") {
104
- type = "mixed";
105
- }
106
- await this.adapter
107
- .setObjectNotExistsAsync(path + "." + key, {
108
- type: "state",
109
- common: {
110
- name: objectName,
111
- role: this.getRole(element[key], options.write),
112
- type: type,
113
- write: options.write,
114
- read: true,
115
- },
116
- native: {},
117
- })
118
- .then(() => {
119
- this.alreadyCreatedObjects[path + "." + key] = true;
120
- })
121
- .catch((error) => {
122
- this.adapter.log.error(error);
123
- });
124
- }
125
- this.adapter.setState(path + "." + key, element[key], true);
126
- }
127
- });
128
- } catch (error) {
129
- this.adapter.log.error("Error extract keys: " + path + " " + JSON.stringify(element));
130
- this.adapter.log.error(error);
131
- }
132
- }
133
- extractArray(element, key, path, options) {
134
- try {
135
- if (key) {
136
- element = element[key];
137
- }
138
- element.forEach(async (arrayElement, index) => {
139
- index = index + 1;
140
- if (index < 10) {
141
- index = "0" + index;
142
- }
143
- let arrayPath = key + index;
144
- if (typeof arrayElement === "string") {
145
- this.parse(path + "." + key + "." + arrayElement, arrayElement, options);
146
- return;
147
- }
148
- if (typeof arrayElement[Object.keys(arrayElement)[0]] === "string") {
149
- arrayPath = arrayElement[Object.keys(arrayElement)[0]];
150
- }
151
- Object.keys(arrayElement).forEach((keyName) => {
152
- if (keyName.endsWith("Id") && arrayElement[keyName] !== null) {
153
- if (arrayElement[keyName] && arrayElement[keyName].replace) {
154
- arrayPath = arrayElement[keyName].replace(/\./g, "");
155
- } else {
156
- arrayPath = arrayElement[keyName];
157
- }
158
- }
159
- });
160
- Object.keys(arrayElement).forEach((keyName) => {
161
- if (keyName.endsWith("Name")) {
162
- arrayPath = arrayElement[keyName];
163
- }
164
- });
165
-
166
- if (arrayElement.id) {
167
- if (arrayElement.id.replace) {
168
- arrayPath = arrayElement.id.replace(/\./g, "");
169
- } else {
170
- arrayPath = arrayElement.id;
171
- }
172
- }
173
- if (arrayElement.name) {
174
- arrayPath = arrayElement.name.replace(/\./g, "");
175
- }
176
- if (arrayElement.start_date_time) {
177
- arrayPath = arrayElement.start_date_time.replace(/\./g, "");
178
- }
179
- if (options.preferedArrayName && arrayElement[options.preferedArrayName]) {
180
- arrayPath = arrayElement[options.preferedArrayName].replace(/\./g, "");
181
- }
182
-
183
- if (options.forceIndex) {
184
- arrayPath = key + index;
185
- }
186
- //special case array with 2 string objects
187
- if (
188
- Object.keys(arrayElement).length === 2 &&
189
- typeof Object.keys(arrayElement)[0] === "string" &&
190
- typeof Object.keys(arrayElement)[1] === "string" &&
191
- typeof arrayElement[Object.keys(arrayElement)[0]] !== "object" &&
192
- typeof arrayElement[Object.keys(arrayElement)[1]] !== "object" &&
193
- arrayElement[Object.keys(arrayElement)[0]] !== "null"
194
- ) {
195
- let subKey = arrayElement[Object.keys(arrayElement)[0]];
196
- const subValue = arrayElement[Object.keys(arrayElement)[1]];
197
- const subName = Object.keys(arrayElement)[0] + " " + Object.keys(arrayElement)[1];
198
- if (key) {
199
- subKey = key + "." + subKey;
200
- }
201
- if (!this.alreadyCreatedObjects[path + "." + subKey]) {
202
- await this.adapter
203
- .setObjectNotExistsAsync(path + "." + subKey, {
204
- type: "state",
205
- common: {
206
- name: subName,
207
- role: this.getRole(subValue, options.write),
208
- type: subValue !== null ? typeof subValue : "mixed",
209
- write: options.write,
210
- read: true,
211
- },
212
- native: {},
213
- })
214
- .then(() => {
215
- this.alreadyCreatedObjects[path + "." + subKey] = true;
216
- });
217
- }
218
- this.adapter.setState(path + "." + subKey, subValue, true);
219
- return;
220
- }
221
- this.parse(path + "." + arrayPath, arrayElement, options);
222
- });
223
- } catch (error) {
224
- this.adapter.log.error("Cannot extract array " + path);
225
- this.adapter.log.error(error);
226
- }
227
- }
228
- isJsonString(str) {
229
- try {
230
- JSON.parse(str);
231
- } catch (e) {
232
- return false;
233
- }
234
- return true;
235
- }
236
- getRole(element, write) {
237
- if (typeof element === "boolean" && !write) {
238
- return "indicator";
239
- }
240
- if (typeof element === "boolean" && write) {
241
- return "switch";
242
- }
243
- if (typeof element === "number" && !write) {
244
- return "value";
245
- }
246
- if (typeof element === "number" && write) {
247
- return "level";
248
- }
249
- if (typeof element === "string") {
250
- return "text";
251
- }
252
- return "state";
253
- }
254
- };
package/lib/tools.js DELETED
@@ -1,99 +0,0 @@
1
- const axios = require("axios").default;
2
-
3
- /**
4
- * Tests whether the given variable is a real object and not an Array
5
- * @param {any} it The variable to test
6
- * @returns {it is Record<string, any>}
7
- */
8
- function isObject(it) {
9
- // This is necessary because:
10
- // typeof null === 'object'
11
- // typeof [] === 'object'
12
- // [] instanceof Object === true
13
- return Object.prototype.toString.call(it) === "[object Object]";
14
- }
15
-
16
- /**
17
- * Tests whether the given variable is really an Array
18
- * @param {any} it The variable to test
19
- * @returns {it is any[]}
20
- */
21
- function isArray(it) {
22
- if (typeof Array.isArray === "function") return Array.isArray(it);
23
- return Object.prototype.toString.call(it) === "[object Array]";
24
- }
25
-
26
- /**
27
- * Translates text to the target language. Automatically chooses the right translation API.
28
- * @param {string} text The text to translate
29
- * @param {string} targetLang The target languate
30
- * @param {string} [yandexApiKey] The yandex API key. You can create one for free at https://translate.yandex.com/developers
31
- * @returns {Promise<string>}
32
- */
33
- async function translateText(text, targetLang, yandexApiKey) {
34
- if (targetLang === "en") {
35
- return text;
36
- } else if (!text) {
37
- return "";
38
- }
39
- if (yandexApiKey) {
40
- return translateYandex(text, targetLang, yandexApiKey);
41
- } else {
42
- return translateGoogle(text, targetLang);
43
- }
44
- }
45
-
46
- /**
47
- * Translates text with Yandex API
48
- * @param {string} text The text to translate
49
- * @param {string} targetLang The target languate
50
- * @param {string} apiKey The yandex API key. You can create one for free at https://translate.yandex.com/developers
51
- * @returns {Promise<string>}
52
- */
53
- async function translateYandex(text, targetLang, apiKey) {
54
- if (targetLang === "zh-cn") {
55
- targetLang = "zh";
56
- }
57
- try {
58
- const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${apiKey}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`;
59
- const response = await axios({url, timeout: 15000});
60
- if (response.data && response.data.text && isArray(response.data.text)) {
61
- return response.data.text[0];
62
- }
63
- throw new Error("Invalid response for translate request");
64
- } catch (e) {
65
- throw new Error(`Could not translate to "${targetLang}": ${e}`);
66
- }
67
- }
68
-
69
- /**
70
- * Translates text with Google API
71
- * @param {string} text The text to translate
72
- * @param {string} targetLang The target languate
73
- * @returns {Promise<string>}
74
- */
75
- async function translateGoogle(text, targetLang) {
76
- try {
77
- const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`;
78
- const response = await axios({url, timeout: 15000});
79
- if (isArray(response.data)) {
80
- // we got a valid response
81
- return response.data[0][0][0];
82
- }
83
- throw new Error("Invalid response for translate request");
84
- } catch (e) {
85
- if (e.response && e.response.status === 429) {
86
- throw new Error(
87
- `Could not translate to "${targetLang}": Rate-limited by Google Translate`
88
- );
89
- } else {
90
- throw new Error(`Could not translate to "${targetLang}": ${e}`);
91
- }
92
- }
93
- }
94
-
95
- module.exports = {
96
- isArray,
97
- isObject,
98
- translateText
99
- };