iobroker.openknx 0.1.9 → 0.1.13
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/README.md +230 -81
- package/admin/i18n/de/translations.json +11 -2
- package/admin/i18n/en/translations.json +11 -2
- package/admin/i18n/es/translations.json +7 -1
- package/admin/i18n/fr/translations.json +7 -1
- package/admin/i18n/it/translations.json +7 -1
- package/admin/i18n/nl/translations.json +7 -1
- package/admin/i18n/pl/translations.json +7 -1
- package/admin/i18n/pt/translations.json +7 -1
- package/admin/i18n/ru/translations.json +7 -1
- package/admin/i18n/zh-cn/translations.json +7 -1
- package/admin/index_m.html +439 -366
- package/admin/words.js +83 -206
- package/io-package.json +9 -4
- package/lib/doubleKeyedMap.js +56 -0
- package/lib/knx/package-lock.json +675 -0
- package/lib/knx/src/dptlib/dpt11.js +1 -1
- package/lib/knx/src/dptlib/dpt14.js +1 -1
- package/lib/knx/src/dptlib/dpt18.js +1 -1
- package/lib/knx/src/dptlib/dpt2.js +5 -3
- package/lib/knx/src/dptlib/dpt21.js +4 -2
- package/lib/knx/src/dptlib/dpt232.js +1 -1
- package/lib/knx/src/dptlib/dpt237.js +1 -1
- package/lib/knx/src/dptlib/dpt3.js +1 -1
- package/lib/knx/src/dptlib/dpt4.js +1 -1
- package/lib/knx/src/dptlib/dpt7.js +8 -1
- package/lib/projectImport.js +146 -48
- package/lib/projectImport.test.js +14 -7
- package/lib/tools.js +47 -26
- package/main.js +103 -104
- package/package.json +8 -20
- package/admin/exportGA.png +0 -0
package/admin/index_m.html
CHANGED
|
@@ -1,421 +1,494 @@
|
|
|
1
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
2
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/*
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
3
|
+
<head>
|
|
4
|
+
<!-- Load ioBroker scripts and styles-->
|
|
5
|
+
<link rel="stylesheet" type="text/css" href="../../css/adapter.css" />
|
|
6
|
+
<link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css" />
|
|
7
|
+
|
|
8
|
+
<link rel="stylesheet" type="text/css" href="../../lib/css/themes/jquery-ui/redmond/jquery-ui.min.css" />
|
|
9
|
+
|
|
10
|
+
<script type="text/javascript" src="../../lib/js/jquery-3.2.1.min.js"></script>
|
|
11
|
+
<script type="text/javascript" src="../../socket.io/socket.io.js"></script>
|
|
12
|
+
|
|
13
|
+
<script type="text/javascript" src="../../js/translate.js"></script>
|
|
14
|
+
<script type="text/javascript" src="../../lib/js/materialize.js"></script>
|
|
15
|
+
<script type="text/javascript" src="../../js/adapter-settings.js"></script>
|
|
16
|
+
|
|
17
|
+
<!-- Load our own files -->
|
|
18
|
+
<link rel="stylesheet" type="text/css" href="style.css" />
|
|
19
|
+
<script type="text/javascript" src="words.js"></script>
|
|
20
|
+
|
|
21
|
+
<style>
|
|
22
|
+
#progress {
|
|
23
|
+
display: none;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#drop-zone {
|
|
27
|
+
width: calc(100% - 10px);
|
|
28
|
+
height: calc(100% - 10px);
|
|
29
|
+
position: absolute;
|
|
30
|
+
opacity: 0.8;
|
|
31
|
+
top: 0;
|
|
32
|
+
left: 0;
|
|
33
|
+
background: #eee;
|
|
34
|
+
-webkit-border-radius: 15px;
|
|
35
|
+
-moz-border-radius: 15px;
|
|
36
|
+
border-radius: 15px;
|
|
37
|
+
z-index: 1;
|
|
38
|
+
font-size: 32px;
|
|
39
|
+
font-weight: bold;
|
|
40
|
+
text-align: center;
|
|
41
|
+
border: 5px dashed darkgray;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.dropZone-error {
|
|
45
|
+
background: #faa !important;
|
|
46
|
+
color: #f00;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Tooltip container */
|
|
50
|
+
.tooltip {
|
|
51
|
+
position: relative;
|
|
52
|
+
display: inline-block;
|
|
53
|
+
border-bottom: 1px dotted black;
|
|
54
|
+
/* If you want dots under the hoverable text */
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Tooltip text */
|
|
58
|
+
.tooltip .tooltiptext {
|
|
59
|
+
visibility: hidden;
|
|
60
|
+
width: 120px;
|
|
61
|
+
background-color: black;
|
|
62
|
+
color: #fff;
|
|
63
|
+
text-align: center;
|
|
64
|
+
padding: 5px 0;
|
|
65
|
+
border-radius: 6px;
|
|
66
|
+
|
|
67
|
+
/* Position the tooltip text */
|
|
68
|
+
position: absolute;
|
|
69
|
+
z-index: 1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Show the tooltip text when you mouse over the tooltip container */
|
|
73
|
+
.tooltip:hover .tooltiptext {
|
|
74
|
+
visibility: visible;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.instructions {
|
|
78
|
+
font-size: 16px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.page {
|
|
82
|
+
height: calc(100% - 120px) !important;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.modal-header {
|
|
86
|
+
padding: 16px 16px;
|
|
87
|
+
color: #fff;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.tab-active {
|
|
91
|
+
background-color: white !important;
|
|
92
|
+
color: #39a1f4 !important;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.dialog {
|
|
96
|
+
width: 100%;
|
|
97
|
+
height: calc(100% - 64px);
|
|
98
|
+
overflow: auto;
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
101
|
+
|
|
102
|
+
<script type="text/javascript">
|
|
103
|
+
var etsFile = '<input type="file" id="etsFile" style="display: inline-block"/>';
|
|
104
|
+
|
|
105
|
+
// This will be called by the admin adapter when the settings page loads
|
|
106
|
+
function load(settings, onChange) {
|
|
107
|
+
if (!settings) return;
|
|
108
|
+
|
|
109
|
+
// Check adapter is alive
|
|
110
|
+
window.isProcessingRequest = false
|
|
111
|
+
this.checkInterval = setInterval(() => {
|
|
112
|
+
|
|
113
|
+
this.getIsAdapterAlive( function (isAlive) {
|
|
114
|
+
if (isAlive && !window.isProcessingRequest) {
|
|
115
|
+
$("#onlyAddNewObjects").removeClass("disabled");
|
|
116
|
+
$(".file-field .btn").removeClass("disabled");
|
|
117
|
+
$(".file-field .file-path").prop("disabled", false);
|
|
118
|
+
$("#etsFile").prop("disabled", false);
|
|
119
|
+
$("#createAlias").removeClass("disabled");
|
|
120
|
+
} else {
|
|
121
|
+
$("#etsFile").prop("disabled", true);
|
|
122
|
+
$("#createAlias").addClass("disabled");
|
|
123
|
+
$(".file-field .btn").addClass("disabled");
|
|
124
|
+
$(".file-field .file-path").prop("disabled", true);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}, 1000)
|
|
128
|
+
if (settings.gwip === undefined) settings.gwip = "127.0.0.1";
|
|
129
|
+
if (settings.gwipport === undefined) settings.gwipport = 3671;
|
|
130
|
+
if (settings.debugLevel === undefined) settings.debugLevel = 0; //todo
|
|
131
|
+
if (settings.frameInterval === undefined) settings.frameInterval = 40;
|
|
132
|
+
if (settings.bind === undefined) settings.bind = ""; //local network interface
|
|
133
|
+
if (settings.eibadr === undefined) settings.eibadr = "1.1.1";
|
|
134
|
+
if (settings.onlyAddNewObjects === undefined) settings.onlyAddNewObjects = false;
|
|
135
|
+
|
|
136
|
+
//fill dropdown list bind
|
|
137
|
+
getIPs(function (ips) {
|
|
138
|
+
for (var i = 0; i < ips.length; i++) {
|
|
139
|
+
if (ips[i].family.indexOf("ipv4") > -1 && ips[i].address !== "0.0.0.0") {
|
|
140
|
+
$("#bind").append('<option value="' + ips[i].address + '">' + ips[i].name + "</option>");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
$("#bind.value").val(settings.bind).select();
|
|
144
|
+
});
|
|
79
145
|
|
|
80
|
-
.
|
|
81
|
-
height: calc(100% - 120px) !important;
|
|
82
|
-
}
|
|
146
|
+
fillSelectIPs("#adapterAddress", settings.adapterAddress, false, true);
|
|
83
147
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
148
|
+
showConfigDialog();
|
|
149
|
+
$("#progress").hide();
|
|
150
|
+
$("#progress2").hide();
|
|
88
151
|
|
|
89
|
-
.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
152
|
+
$(".value").each(function () {
|
|
153
|
+
var $key = $(this);
|
|
154
|
+
var id = $key.attr("id");
|
|
155
|
+
if ($key.attr("type") === "checkbox") {
|
|
156
|
+
// do not call onChange direct, because onChange could expect some arguments
|
|
157
|
+
$key.prop("checked", settings[id]).on("change", () => onChange());
|
|
158
|
+
} else {
|
|
159
|
+
// do not call onChange direct, because onChange could expect some arguments
|
|
160
|
+
$key.val(settings[id])
|
|
161
|
+
.on("change", () => onChange())
|
|
162
|
+
.on("keyup", () => onChange());
|
|
163
|
+
}
|
|
93
164
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
var knxprojFile = '<input type="file" id="knxprojFile" style="display: inline-block"/>';
|
|
103
|
-
|
|
104
|
-
// This will be called by the admin adapter when the settings page loads
|
|
105
|
-
function load(settings, onChange) {
|
|
106
|
-
if (!settings) return;
|
|
107
|
-
|
|
108
|
-
if (settings.gwip === undefined) settings.gwip = "127.0.0.1";
|
|
109
|
-
if (settings.gwipport === undefined) settings.gwipport = 3671;
|
|
110
|
-
if (settings.debugLevel === undefined) settings.debugLevel = 0; //todo
|
|
111
|
-
if (settings.frameInterval === undefined) settings.frameInterval = 40;
|
|
112
|
-
if (settings.bind === undefined) settings.bind = ""; //local network interface
|
|
113
|
-
if (settings.eibadr === undefined) settings.eibadr = "1.1.1";
|
|
114
|
-
if (settings.onlyAddNewObjects === undefined) settings.onlyAddNewObjects = false;
|
|
115
|
-
|
|
116
|
-
//fill dropdown list bind
|
|
117
|
-
getIPs(function (ips) {
|
|
118
|
-
for (var i = 0; i < ips.length; i++) {
|
|
119
|
-
if (ips[i].family.indexOf("ipv4") > -1 && ips[i].address !== "0.0.0.0") {
|
|
120
|
-
$("#bind").append('<option value="' + ips[i].address + '">' + ips[i].name + "</option>");
|
|
165
|
+
//add sanity checks
|
|
166
|
+
$key.val(settings[id]).focusout("change", function () {
|
|
167
|
+
if (id === "gwip") {
|
|
168
|
+
var ip1 = $("#gwip").val();
|
|
169
|
+
if (isIpValid(ip1)) {
|
|
170
|
+
$("#gwip").val(ip1);
|
|
171
|
+
} else {
|
|
172
|
+
alert("invalid IP address");
|
|
121
173
|
}
|
|
122
174
|
}
|
|
123
|
-
$("#bind.value").val(settings.bind).select();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
fillSelectIPs("#adapterAddress", settings.adapterAddress, false, true);
|
|
127
|
-
|
|
128
|
-
showConfigDialog();
|
|
129
|
-
|
|
130
|
-
$(".value").each(function () {
|
|
131
|
-
var $key = $(this);
|
|
132
|
-
var id = $key.attr("id");
|
|
133
|
-
if ($key.attr("type") === "checkbox") {
|
|
134
|
-
// do not call onChange direct, because onChange could expect some arguments
|
|
135
|
-
$key.prop("checked", settings[id]).on("change", () => onChange());
|
|
136
|
-
} else {
|
|
137
|
-
// do not call onChange direct, because onChange could expect some arguments
|
|
138
|
-
$key.val(settings[id])
|
|
139
|
-
.on("change", () => onChange())
|
|
140
|
-
.on("keyup", () => onChange());
|
|
141
|
-
}
|
|
142
175
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
} else {
|
|
150
|
-
alert("invalid IP address");
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (id === "gwipport") {
|
|
155
|
-
var gwipport1 = $("#gwipport").val();
|
|
156
|
-
if (ValidatePortaddress(gwipport1)) {
|
|
157
|
-
$("#gwipport").val(gwipport1);
|
|
158
|
-
} else {
|
|
159
|
-
alert("invalid port number");
|
|
160
|
-
}
|
|
176
|
+
if (id === "gwipport") {
|
|
177
|
+
var gwipport1 = $("#gwipport").val();
|
|
178
|
+
if (isPortValid(gwipport1)) {
|
|
179
|
+
$("#gwipport").val(gwipport1);
|
|
180
|
+
} else {
|
|
181
|
+
alert("invalid port number");
|
|
161
182
|
}
|
|
183
|
+
}
|
|
162
184
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
185
|
+
if (id === "eibadr") {
|
|
186
|
+
var eibadr1 = $("#eibadr").val();
|
|
187
|
+
if (isKnxAddressValid(eibadr1)) {
|
|
188
|
+
$("#eibadr").val(eibadr1);
|
|
189
|
+
} else {
|
|
190
|
+
alert("physical KNX address in format a/b/c not valid");
|
|
170
191
|
}
|
|
192
|
+
}
|
|
171
193
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
} else {
|
|
178
|
-
alert("min 1");
|
|
179
|
-
}
|
|
194
|
+
if (id === "frameInterval") {
|
|
195
|
+
var fI = $("#frameInterval").val();
|
|
196
|
+
if (!isNaN(fI * 1)) {
|
|
197
|
+
if (fI > 0) {
|
|
198
|
+
$("#frameInterval").val(fI);
|
|
180
199
|
} else {
|
|
181
|
-
alert("
|
|
200
|
+
alert("min 1");
|
|
182
201
|
}
|
|
202
|
+
} else {
|
|
203
|
+
alert("This is not a number");
|
|
183
204
|
}
|
|
184
|
-
|
|
185
|
-
if (id === "bind") {
|
|
186
|
-
var bindIP = $("#bind").val();
|
|
187
|
-
$("#bind").val(bindIP);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (id === "debugLevel") {
|
|
191
|
-
var dbgLevel = $("#debugLevel").val();
|
|
192
|
-
$("#debugLevel").val(dbgLevel);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
//if not alive disable buttons
|
|
198
|
-
getIsAdapterAlive(function (isAlive) {
|
|
199
|
-
if (isAlive) {
|
|
200
|
-
$("#knxprojFile").change(fileHandler);
|
|
201
|
-
} else {
|
|
202
|
-
$("#knxprojFile").prop("disabled", true);
|
|
203
|
-
$(".file-field .btn").addClass("disabled");
|
|
204
|
-
$(".file-field .file-path").prop("disabled", true);
|
|
205
205
|
}
|
|
206
|
-
});
|
|
207
206
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
207
|
+
if (id === "bind") {
|
|
208
|
+
var bindIP = $("#bind").val();
|
|
209
|
+
$("#bind").val(bindIP);
|
|
210
|
+
}
|
|
213
211
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
var obj = {};
|
|
218
|
-
$(".value").each(function () {
|
|
219
|
-
var $this = $(this);
|
|
220
|
-
if ($this.attr("type") === "checkbox") {
|
|
221
|
-
obj[$this.attr("id")] = $this.prop("checked");
|
|
222
|
-
} else if ($this.attr("type") === "number") {
|
|
223
|
-
obj[$this.attr("id")] = parseFloat($this.val());
|
|
224
|
-
} else {
|
|
225
|
-
obj[$this.attr("id")] = $this.val();
|
|
212
|
+
if (id === "debugLevel") {
|
|
213
|
+
var dbgLevel = $("#debugLevel").val();
|
|
214
|
+
$("#debugLevel").val(dbgLevel);
|
|
226
215
|
}
|
|
227
216
|
});
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
return false;
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
$("#etsFile").change(processXmlFile);
|
|
220
|
+
$("#createAlias").change(processAlias);
|
|
221
|
+
//if not alive disable buttons
|
|
222
|
+
getIsAdapterAlive(function (isAlive) {
|
|
223
|
+
if (!isAlive) {
|
|
224
|
+
$("#etsFile").prop("disabled", true);
|
|
225
|
+
$("#createAlias").addClass("disabled");
|
|
226
|
+
$(".file-field .btn").addClass("disabled");
|
|
227
|
+
$(".file-field .file-path").prop("disabled", true);
|
|
240
228
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
sendTo(null, "reset", null);
|
|
264
|
-
showToast(null, _("Restarting adapter"), null, 10000);
|
|
265
|
-
} else {
|
|
266
|
-
showMessage(_("Extracted %s states", result.count));
|
|
267
|
-
sendTo(null, "reset", null);
|
|
268
|
-
showToast(null, _("Restarting adapter"), null, 10000);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
$("#knxprojFile").prop("disabled", true);
|
|
272
|
-
$(".file-field .btn").addClass("disabled");
|
|
273
|
-
$(".file-field .file-path").prop("disabled", true);
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
reader.readAsText(file);
|
|
278
|
-
} else if (file.name.split(".").pop() == "knxproj") {
|
|
279
|
-
showMessage(_("KNXproj are not supported, please open in ETS the Group Adresses and right click on group addresses and then group adresse export"));
|
|
280
|
-
$("#onlyAddNewObjects").removeClass("disabled");
|
|
281
|
-
$(".file-field .btn").removeClass("disabled");
|
|
282
|
-
$(".file-field .file-path").prop("disabled", false);
|
|
283
|
-
$("#progress").hide();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
$('#createAlias').on('click', function () {
|
|
232
|
+
processAlias();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
//start with no changed settings, disable save button
|
|
236
|
+
onChange(false);
|
|
237
|
+
// reinitialize all the Materialize labels on the page if you are dynamically adding inputs:
|
|
238
|
+
if (M) M.updateTextFields();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// This will be called by the admin adapter when the user presses the save button
|
|
242
|
+
function save(callback) {
|
|
243
|
+
// example: select elements with class=value and build settings object
|
|
244
|
+
var obj = {};
|
|
245
|
+
$(".value").each(function () {
|
|
246
|
+
var $this = $(this);
|
|
247
|
+
if ($this.attr("type") === "checkbox") {
|
|
248
|
+
obj[$this.attr("id")] = $this.prop("checked");
|
|
249
|
+
} else if ($this.attr("type") === "number") {
|
|
250
|
+
obj[$this.attr("id")] = parseFloat($this.val());
|
|
284
251
|
} else {
|
|
285
|
-
|
|
286
|
-
$("#onlyAddNewObjects").removeClass("disabled");
|
|
287
|
-
$(".file-field .btn").removeClass("disabled");
|
|
288
|
-
$(".file-field .file-path").prop("disabled", false);
|
|
289
|
-
$("#progress").hide();
|
|
252
|
+
obj[$this.attr("id")] = $this.val();
|
|
290
253
|
}
|
|
254
|
+
});
|
|
255
|
+
sendTo(null, "reload", null);
|
|
256
|
+
callback(obj);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function processXmlFile(event) {
|
|
260
|
+
event.preventDefault();
|
|
261
|
+
var file = event.dataTransfer ? event.dataTransfer.files[0] : event.target.files[0];
|
|
262
|
+
if (!file) {
|
|
263
|
+
console.warn("invalid file object");
|
|
264
|
+
return false;
|
|
291
265
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
.on("change", function () {
|
|
324
|
-
var status = $(this).prop("checked");
|
|
325
|
-
$.ajax({
|
|
326
|
-
url: url,
|
|
327
|
-
type: "post",
|
|
328
|
-
data: { status: status },
|
|
266
|
+
|
|
267
|
+
if (file.name.split(".").pop() == "xml") {
|
|
268
|
+
$("#etsFile").prop("disabled", true);
|
|
269
|
+
$("#createAlias").addClass("disabled");
|
|
270
|
+
$(".file-field .btn").addClass("disabled");
|
|
271
|
+
$(".file-field .file-path").prop("disabled", true);
|
|
272
|
+
window.isProcessingRequest=true;
|
|
273
|
+
var reader = new FileReader();
|
|
274
|
+
reader.addEventListener("load", function readFile(event) {
|
|
275
|
+
$("#etsFile").replaceWith($(etsFile));
|
|
276
|
+
$("#etsFile").change(processXmlFile);
|
|
277
|
+
showToast(null, _("Import started..."), null, 3000);
|
|
278
|
+
$("#progress").show();
|
|
279
|
+
$("#onlyAddNewObjects").addClass("disabled");
|
|
280
|
+
sendTo(null, "import", { xml: event.target.result, onlyAddNewObjects: $("#onlyAddNewObjects").prop("checked") }, function (result) {
|
|
281
|
+
$("#onlyAddNewObjects").removeClass("disabled");
|
|
282
|
+
$("#progress").hide();
|
|
283
|
+
if (!result || result.error) {
|
|
284
|
+
let message = "Unknown error"
|
|
285
|
+
if (result && result.error) {
|
|
286
|
+
message = `Extracted ${result.count} states successfully<br/><br/>\n${result.error}`
|
|
287
|
+
}
|
|
288
|
+
showMessage(_(message));
|
|
289
|
+
sendTo(null, "reset", null);
|
|
290
|
+
showToast(null, _("Restarting adapter"), null, 10000);
|
|
291
|
+
} else {
|
|
292
|
+
showMessage(_("Extracted %s states successfully", result.count));
|
|
293
|
+
sendTo(null, "reset", null);
|
|
294
|
+
showToast(null, _("Restarting adapter"), null, 10000);
|
|
295
|
+
}
|
|
296
|
+
window.isProcessingRequest=false;
|
|
329
297
|
});
|
|
330
298
|
});
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
299
|
+
reader.readAsText(file);
|
|
300
|
+
} else if (file.name.split(".").pop() == "knxproj") {
|
|
301
|
+
showMessage(_("KNXproj are not supported, please open in ETS the Group Adresses and right click on group addresses and then group adresse export"));
|
|
302
|
+
} else {
|
|
303
|
+
showMessage(_("Unsupported file format"));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function processAlias() {
|
|
308
|
+
$("#etsFile").prop("disabled", true);
|
|
309
|
+
$("#createAlias").addClass("disabled");
|
|
310
|
+
$(".file-field .btn").addClass("disabled");
|
|
311
|
+
$(".file-field .file-path").prop("disabled", true);
|
|
312
|
+
$("#progress2").show();
|
|
313
|
+
window.isProcessingRequest = true;
|
|
314
|
+
sendTo(null, "createAlias", null, function (result) {
|
|
315
|
+
if (!result || result.error) {
|
|
316
|
+
showMessage(_("Error"));
|
|
317
|
+
sendTo(null, "reset", null);
|
|
318
|
+
showToast(null, _("Restarting adapter"), null, 10000);
|
|
319
|
+
} else {
|
|
320
|
+
showMessage(_("Generated %s aliases", result.count));
|
|
321
|
+
sendTo(null, "reset", null);
|
|
322
|
+
showToast(null, _("Restarting adapter"), null, 10000);
|
|
337
323
|
}
|
|
324
|
+
window.isProcessingRequest=false;
|
|
325
|
+
$("#progress2").hide();
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function isIpValid(inputText) {
|
|
330
|
+
var format = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$/;
|
|
331
|
+
return !!inputText.match(format);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function isPortValid(inputText) {
|
|
335
|
+
var format = /^([1-9][0-9]{0,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/;
|
|
336
|
+
return !!inputText.match(format);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function isKnxAddressValid(inputText) {
|
|
340
|
+
var format = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
341
|
+
return !!inputText.match(format);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function disableAllDialogs() {
|
|
345
|
+
$(".c-tab").removeClass("tab-active");
|
|
346
|
+
var x = document.getElementsByClassName("dialog");
|
|
347
|
+
for (var cnt = 0; cnt < x.length; cnt++) {
|
|
348
|
+
x[cnt].style.display = "none";
|
|
338
349
|
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function showConfigDialog() {
|
|
353
|
+
disableAllDialogs();
|
|
354
|
+
$(".dialog-config").addClass("tab-active");
|
|
355
|
+
var x = document.getElementById("configDialog");
|
|
356
|
+
x.style.display = "block";
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function showExtendedDialog() {
|
|
360
|
+
disableAllDialogs();
|
|
361
|
+
$('.dialog-extended').addClass('tab-active');
|
|
362
|
+
var x = document.getElementById("extendedDialog");
|
|
363
|
+
x.style.display = "block";
|
|
364
|
+
}
|
|
365
|
+
</script>
|
|
366
|
+
</head>
|
|
367
|
+
|
|
368
|
+
<body>
|
|
369
|
+
<!-- you have to put your config page in a div with id adapter-container -->
|
|
370
|
+
|
|
371
|
+
<div class="m adapter-container">
|
|
372
|
+
|
|
373
|
+
<nav>
|
|
374
|
+
<div class="row">
|
|
375
|
+
<div class="col s12 m4 l2">
|
|
376
|
+
<img src="openknx.png" class="logo">
|
|
377
|
+
</div>
|
|
378
|
+
</div>
|
|
379
|
+
</nav>
|
|
380
|
+
<div class="row">
|
|
381
|
+
<ul class="tabs">
|
|
382
|
+
<li class="tab col s5 dialog-config c-tab translate"><a onclick="showConfigDialog()">Settings and Import</a></li>
|
|
383
|
+
<li class="tab col s5 dialog-extended c-tab translate"><a onclick="showExtendedDialog()">Alias Generation</a></li>
|
|
384
|
+
</ul>
|
|
385
|
+
</div>
|
|
339
386
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
<div class="row">
|
|
356
|
-
<div class="col s6 l2 input-field">
|
|
357
|
-
<input class="value" id="gwip" type="text" />
|
|
358
|
-
<label for="gwip" class="translate">Gateway IP</label>
|
|
359
|
-
</div>
|
|
360
|
-
<div class="col s6 l2 input-field">
|
|
361
|
-
<input type="number" min="1025" max="65535" class="value" id="gwipport" />
|
|
362
|
-
<label for="gwipport" class="translate">Port</label>
|
|
363
|
-
</div>
|
|
364
|
-
<div class="col s6 l2 input-field">
|
|
365
|
-
<input id="frameInterval" class="value" type="number" min="20" max="1000" />
|
|
366
|
-
<label for="frameInterval" class="translate">Frames per second</label>
|
|
367
|
-
</div>
|
|
387
|
+
<div id="configDialog" class="dialog">
|
|
388
|
+
<div class="card">
|
|
389
|
+
<div class="card-content">
|
|
390
|
+
<div class="row">
|
|
391
|
+
<div class="col s6 l2 input-field">
|
|
392
|
+
<input class="value" id="gwip" type="text" />
|
|
393
|
+
<label for="gwip" class="translate">Gateway IP</label>
|
|
394
|
+
</div>
|
|
395
|
+
<div class="col s6 l1 input-field">
|
|
396
|
+
<input type="number" min="1025" max="65535" class="value" id="gwipport" />
|
|
397
|
+
<label for="gwipport" class="translate">Port</label>
|
|
398
|
+
</div>
|
|
399
|
+
<div class="col s6 l1 input-field">
|
|
400
|
+
<input id="frameInterval" class="value" type="number" min="20" max="1000" />
|
|
401
|
+
<label for="frameInterval" class="translate">Frames per second</label>
|
|
368
402
|
</div>
|
|
369
403
|
</div>
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
</div>
|
|
379
|
-
<div class="col s12 l2 input-field">
|
|
380
|
-
<input class="value" id="eibadr" type="text" />
|
|
381
|
-
<label for="eibadr" class="translate">physical KNX address</label>
|
|
382
|
-
</div>
|
|
404
|
+
<div class="row">
|
|
405
|
+
<div class="col s12 l4 input-field">
|
|
406
|
+
<select class="value" id="bind"></select>
|
|
407
|
+
<label class="translate" for="bind">local network interface</label>
|
|
408
|
+
</div>
|
|
409
|
+
<div class="col s12 l2 input-field">
|
|
410
|
+
<input class="value" id="eibadr" type="text" />
|
|
411
|
+
<label for="eibadr" class="translate">physical KNX address</label>
|
|
383
412
|
</div>
|
|
384
413
|
</div>
|
|
385
414
|
</div>
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
415
|
+
</div>
|
|
416
|
+
<div class="card">
|
|
417
|
+
<div class="card-content">
|
|
418
|
+
<div class="row">
|
|
419
|
+
<div style="display: flex">
|
|
420
|
+
<div class="col l6">
|
|
421
|
+
<div class="input-field">
|
|
392
422
|
<input class="value" id="onlyAddNewObjects" type="checkbox" />
|
|
393
423
|
<label class="translate" for="onlyAddNewObjects">add only new Objects</label>
|
|
394
424
|
</div>
|
|
395
|
-
|
|
396
|
-
<div class="col s6">
|
|
425
|
+
|
|
397
426
|
<div class="file-field input-field">
|
|
398
427
|
<div class="btn" id="fileUploadButton">
|
|
399
|
-
<span class="translate">
|
|
400
|
-
<input type="file" id="
|
|
428
|
+
<span class="translate">Import XML from ETS</span>
|
|
429
|
+
<input type="file" id="etsFile" />
|
|
401
430
|
</div>
|
|
402
431
|
<div class="file-path-wrapper">
|
|
403
432
|
<input class="file-path validate" type="text" />
|
|
404
433
|
</div>
|
|
405
434
|
</div>
|
|
406
|
-
|
|
407
435
|
<div class="progress" id="progress">
|
|
408
436
|
<div class="indeterminate" style="width: 70%"></div>
|
|
409
437
|
</div>
|
|
438
|
+
<a href="https://github.com/iobroker-community-adapters/ioBroker.openknx#adaptermigration" target="_blank"
|
|
439
|
+
><h6><div class="translate">Click here for a manual to migrate from knx.0 to openknx.0</div></h6></a
|
|
440
|
+
>
|
|
410
441
|
</div>
|
|
411
|
-
<div class="col
|
|
412
|
-
<
|
|
413
|
-
|
|
442
|
+
<div class="col l6">
|
|
443
|
+
<div class="input-field">
|
|
444
|
+
<h6 class="translate">How to export GA XML from ETS:</h6>
|
|
445
|
+
<img src="./exportGA.png" alt="exportGA" />
|
|
446
|
+
</div>
|
|
414
447
|
</div>
|
|
415
448
|
</div>
|
|
416
449
|
</div>
|
|
417
450
|
</div>
|
|
418
451
|
</div>
|
|
419
452
|
</div>
|
|
420
|
-
|
|
421
|
-
|
|
453
|
+
|
|
454
|
+
<div id="extendedDialog" class="dialog">
|
|
455
|
+
<div class="card">
|
|
456
|
+
<div class="card-content">
|
|
457
|
+
<div class="row">
|
|
458
|
+
<div class="col s12">
|
|
459
|
+
<h6><span class="translate">To merge Action and Status GA in one ioBroker Object you can let the Adapter generate</span><span> <a href="https://www.iobroker.net/#de/documentation/dev/aliases.md" target="_blank">Aliases</a></span></h6>
|
|
460
|
+
<div class="input-field col s6 m6 l5">
|
|
461
|
+
<input class="value" id="statusRegex" type="text" />
|
|
462
|
+
<label class="translate" for="statusRegex">Regex to identify Status GAs (ending with status, rm, rückmeldung..).</label>
|
|
463
|
+
|
|
464
|
+
</div>
|
|
465
|
+
<div class="input-field col s6 m6 l2">
|
|
466
|
+
<input class="value" id="regexSimil" type="number" />
|
|
467
|
+
<label class="translate" for="regexSimil">Minimum Similarity 0-1</label>
|
|
468
|
+
|
|
469
|
+
</div>
|
|
470
|
+
<div class="input-field col s6 m6 l2">
|
|
471
|
+
<input class="value" id="aliasPath" type="text" />
|
|
472
|
+
<label class="translate" for="aliasPath">Alias path</label>
|
|
473
|
+
</div>
|
|
474
|
+
<div class="col s12">
|
|
475
|
+
<a id="createAlias" class="waves-effect waves-light btn"><i
|
|
476
|
+
class="material-icons right">list</i><span class="translate">generate aliases</span></a>
|
|
477
|
+
</div>
|
|
478
|
+
<div class="input-field">
|
|
479
|
+
<input class="value" id="aliasRange" type="checkbox" />
|
|
480
|
+
<label class="translate" for="aliasRange">include group range in search (save first)</label>
|
|
481
|
+
</div>
|
|
482
|
+
<div class="progress" id="progress2">
|
|
483
|
+
<div class="indeterminate"></div>
|
|
484
|
+
</div>
|
|
485
|
+
|
|
486
|
+
</div>
|
|
487
|
+
</div>
|
|
488
|
+
</div>
|
|
489
|
+
</div>
|
|
490
|
+
|
|
491
|
+
</div>
|
|
492
|
+
</body>
|
|
493
|
+
|
|
494
|
+
</html>
|