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/LICENSE +1 -1
- package/README.md +42 -13
- package/admin/i18n/de/translations.json +14 -0
- package/admin/i18n/en/translations.json +14 -0
- package/admin/i18n/es/translations.json +14 -0
- package/admin/i18n/fr/translations.json +14 -0
- package/admin/i18n/it/translations.json +14 -0
- package/admin/i18n/nl/translations.json +14 -0
- package/admin/i18n/pl/translations.json +14 -0
- package/admin/i18n/pt/translations.json +14 -0
- package/admin/i18n/ru/translations.json +14 -0
- package/admin/i18n/uk/translations.json +14 -0
- package/admin/i18n/zh-cn/translations.json +14 -0
- package/admin/jsonConfig.json +99 -0
- package/io-package.json +97 -29
- package/main.js +235 -206
- package/package.json +28 -23
- package/admin/index_m.html +0 -105
- package/admin/style.css +0 -32
- package/admin/words.js +0 -65
- package/lib/json2iob.js +0 -254
- package/lib/tools.js +0 -99
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.renault",
|
|
3
|
-
"version": "0.0.
|
|
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": "^
|
|
28
|
-
"axios": "^1.
|
|
28
|
+
"@iobroker/adapter-core": "^3.3.2",
|
|
29
|
+
"axios": "^1.16.1",
|
|
29
30
|
"json-bigint": "^1.0.0",
|
|
30
|
-
"json2iob": "^2.
|
|
31
|
-
"qs": "^6.
|
|
31
|
+
"json2iob": "^2.6.22",
|
|
32
|
+
"qs": "^6.15.2"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
|
-
"@
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
41
|
-
"@
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"eslint": "^
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
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"
|
package/admin/index_m.html
DELETED
|
@@ -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
|
-
};
|