node-red-contrib-knx-ultimate 4.0.4 → 4.0.6
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/CHANGELOG.md +6 -0
- package/nodes/knxUltimate-config.html +108 -18
- package/nodes/knxUltimate-config.js +66 -28
- package/nodes/knxUltimate.html +7 -4
- package/nodes/knxUltimateHueBattery.html +6 -3
- package/nodes/knxUltimateHueButton.html +30 -12
- package/nodes/knxUltimateHueContactSensor.html +6 -3
- package/nodes/knxUltimateHueLight.html +7 -3
- package/nodes/knxUltimateHueLightSensor.html +6 -3
- package/nodes/knxUltimateHueMotion.html +6 -3
- package/nodes/knxUltimateHueScene.html +18 -8
- package/nodes/knxUltimateHueTapDial.html +6 -3
- package/nodes/knxUltimateHueTemperatureSensor.html +6 -3
- package/nodes/knxUltimateHueZigbeeConnectivity.html +6 -3
- package/nodes/knxUltimateHuedevice_software_update.html +6 -3
- package/nodes/knxUltimateLoadControl.html +6 -4
- package/nodes/knxUltimateSceneController.html +18 -9
- package/nodes/locales/de/knxUltimate-config.json +2 -0
- package/nodes/locales/de-DE/knxUltimate-config.html +8 -3
- package/nodes/locales/en-US/knxUltimate-config.html +8 -3
- package/nodes/locales/en-US/knxUltimate-config.json +2 -0
- package/nodes/locales/it/knxUltimate-config.json +2 -0
- package/nodes/locales/it-IT/knxUltimate-config.html +8 -3
- package/nodes/locales/zh-CN/knxUltimate-config.html +8 -3
- package/nodes/locales/zh-CN/knxUltimate-config.json +2 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 4.0.6** - September 2025<br/>
|
|
10
|
+
- Fixed regression in automatic datapoint selection, based on group address DPT.<br/>
|
|
11
|
+
|
|
12
|
+
**Version 4.0.5** - September 2025<br/>
|
|
13
|
+
- NEW: You have now the choide to select multiple modes to authenticate to a KNX Gateway.<br/>
|
|
14
|
+
|
|
9
15
|
**Version 4.0.4** - September 2025<br/>
|
|
10
16
|
- NEW: you can now login to your secure gateway using only tunnel and password, without the keyring file.<br/>
|
|
11
17
|
|
|
@@ -25,11 +25,12 @@
|
|
|
25
25
|
tunnelIASelection: { value: "Auto" },
|
|
26
26
|
tunnelIA: { value: "" },
|
|
27
27
|
tunnelInterfaceIndividualAddress: { value: "" },
|
|
28
|
+
tunnelUserPassword: { value: "" },
|
|
29
|
+
tunnelUserId: { value: "" },
|
|
28
30
|
autoReconnect: { value: "yes" }
|
|
29
31
|
},
|
|
30
32
|
credentials: {
|
|
31
|
-
keyringFilePassword: { type: "password" }
|
|
32
|
-
tunnelUserPassword: { type: "password" }
|
|
33
|
+
keyringFilePassword: { type: "password" }
|
|
33
34
|
},
|
|
34
35
|
oneditprepare: function () {
|
|
35
36
|
// Go to the help panel
|
|
@@ -71,13 +72,13 @@
|
|
|
71
72
|
active: (node.knxSecureSelected === true || node.knxSecureSelected === 'true') ? 1 : 0,
|
|
72
73
|
activate: function (event, ui) {
|
|
73
74
|
node.knxSecureSelected = $(ui.newTab).index() === 1;
|
|
74
|
-
try { updateTunnelIAVisibility(); updatePhysAddrVisibility(); updateSecureMulticastHint(); } catch (e) { }
|
|
75
|
+
try { updateTunnelIAVisibility(); updatePhysAddrVisibility(); updateSecureMulticastHint(); enforceProtocolFromIP(); } catch (e) { }
|
|
75
76
|
}
|
|
76
77
|
});
|
|
77
78
|
// Ensure the correct tab is enforced after all UI init
|
|
78
79
|
try {
|
|
79
80
|
const initialActive = (node.knxSecureSelected === true || node.knxSecureSelected === 'true') ? 1 : 0;
|
|
80
|
-
setTimeout(() => { $("#tabsMain").tabs("option", "active", initialActive); updateTunnelIAVisibility(); updatePhysAddrVisibility(); updateSecureMulticastHint(); }, 0);
|
|
81
|
+
setTimeout(() => { $("#tabsMain").tabs("option", "active", initialActive); updateTunnelIAVisibility(); updatePhysAddrVisibility(); updateSecureMulticastHint(); enforceProtocolFromIP(); }, 0);
|
|
81
82
|
} catch (e) { }
|
|
82
83
|
|
|
83
84
|
// Keyring ACE editor setup
|
|
@@ -110,17 +111,85 @@
|
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
|
|
114
|
+
function isSecureTabActive() {
|
|
115
|
+
try {
|
|
116
|
+
return $("#tabsMain").tabs("option", "active") === 1;
|
|
117
|
+
} catch (e) {
|
|
118
|
+
return !!(typeof node.knxSecureSelected !== 'undefined' ? node.knxSecureSelected : false);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function parseIPv4Address(str) {
|
|
123
|
+
if (typeof str !== 'string') return null;
|
|
124
|
+
const parts = str.trim().split('.');
|
|
125
|
+
if (parts.length !== 4) return null;
|
|
126
|
+
const octets = [];
|
|
127
|
+
for (let i = 0; i < parts.length; i++) {
|
|
128
|
+
const part = parts[i];
|
|
129
|
+
if (!/^\d+$/.test(part)) return null;
|
|
130
|
+
const value = Number(part);
|
|
131
|
+
if (value < 0 || value > 255) return null;
|
|
132
|
+
octets.push(value);
|
|
133
|
+
}
|
|
134
|
+
return octets;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function isMulticastIPv4(octets) {
|
|
138
|
+
if (!Array.isArray(octets) || octets.length !== 4) return false;
|
|
139
|
+
const first = octets[0];
|
|
140
|
+
return first >= 224 && first <= 239;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function normalizeTunnelIAValue(value) {
|
|
144
|
+
if (typeof value !== 'string') return '';
|
|
145
|
+
const trimmed = value.trim();
|
|
146
|
+
return (trimmed && trimmed !== 'undefined') ? trimmed : '';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function setTunnelIAValue(value) {
|
|
150
|
+
const normalized = normalizeTunnelIAValue(value || '');
|
|
151
|
+
try { $("#node-config-input-tunnelIA").val(normalized); } catch (e) { }
|
|
152
|
+
try { $("#node-config-input-tunnelInterfaceIndividualAddress").val(normalized); } catch (e) { }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function syncTunnelIAFromManual() {
|
|
156
|
+
try { setTunnelIAValue($("#node-config-input-tunnelInterfaceIndividualAddress").val()); } catch (e) { }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function syncTunnelIAFromKeyring() {
|
|
160
|
+
try { setTunnelIAValue($("#node-config-input-tunnelIA").val()); } catch (e) { }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function enforceProtocolFromIP() {
|
|
164
|
+
try {
|
|
165
|
+
const ipTyped = String($("#node-config-input-host").val() || '').trim();
|
|
166
|
+
if (!ipTyped) return;
|
|
167
|
+
const octets = parseIPv4Address(ipTyped);
|
|
168
|
+
if (!octets || isMulticastIPv4(octets)) return;
|
|
169
|
+
const autoProto = isSecureTabActive() ? 'TunnelTCP' : 'TunnelUDP';
|
|
170
|
+
const $sel = $("#node-config-input-hostProtocol");
|
|
171
|
+
if ($sel.val() !== autoProto) {
|
|
172
|
+
$sel.val(autoProto);
|
|
173
|
+
updateTunnelIAVisibility();
|
|
174
|
+
updateSecureMulticastHint();
|
|
175
|
+
updatePhysAddrVisibility();
|
|
176
|
+
}
|
|
177
|
+
} catch (e) { }
|
|
178
|
+
}
|
|
179
|
+
|
|
113
180
|
function updateSecureCredentialMode() {
|
|
114
181
|
try {
|
|
115
182
|
const mode = getSecureCredentialsMode();
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
183
|
+
const showKeyringFields = (mode === 'keyring' || mode === 'combined');
|
|
184
|
+
const showKeyringIAControls = (mode === 'keyring');
|
|
185
|
+
$("#secureKeyringFields").toggle(showKeyringFields);
|
|
186
|
+
if (!showKeyringIAControls) {
|
|
119
187
|
$("#rowTunnelIASelection").hide();
|
|
120
188
|
$("#divTunnelIA").hide();
|
|
121
189
|
}
|
|
122
190
|
} catch (e) { }
|
|
123
191
|
updateTunnelIAVisibility();
|
|
192
|
+
enforceProtocolFromIP();
|
|
124
193
|
}
|
|
125
194
|
|
|
126
195
|
// Helper: show/hide Tunnel IA controls depending on mode
|
|
@@ -131,7 +200,9 @@
|
|
|
131
200
|
const ip = $("#node-config-input-host").val();
|
|
132
201
|
const isMulticast = (hostProtocol === 'Multicast') || (ip === '224.0.23.12');
|
|
133
202
|
const mode = getSecureCredentialsMode();
|
|
134
|
-
const
|
|
203
|
+
const keyringMode = (mode === 'keyring');
|
|
204
|
+
const manualMode = (mode === 'manual' || mode === 'combined');
|
|
205
|
+
const showTunnelIA = isSecure && !isMulticast && keyringMode;
|
|
135
206
|
if (showTunnelIA) {
|
|
136
207
|
$("#rowTunnelIASelection").show();
|
|
137
208
|
if ($("#node-config-input-tunnelIASelection").val() === 'Manual') {
|
|
@@ -143,9 +214,10 @@
|
|
|
143
214
|
$("#rowTunnelIASelection").hide();
|
|
144
215
|
$("#divTunnelIA").hide();
|
|
145
216
|
}
|
|
146
|
-
const showManualTunnelFields = isSecure && !isMulticast &&
|
|
217
|
+
const showManualTunnelFields = isSecure && !isMulticast && manualMode;
|
|
147
218
|
$("#rowTunnelInterfaceIndividualAddress").toggle(showManualTunnelFields);
|
|
148
219
|
$("#rowTunnelUserPassword").toggle(showManualTunnelFields);
|
|
220
|
+
$("#rowTunnelUserId").toggle(showManualTunnelFields);
|
|
149
221
|
if (!showManualTunnelFields) {
|
|
150
222
|
try {
|
|
151
223
|
$("#node-config-input-tunnelInterfaceIndividualAddress").removeClass('input-error');
|
|
@@ -237,7 +309,9 @@
|
|
|
237
309
|
let aTunnelIAs = [];
|
|
238
310
|
function populateTunnelIAList() {
|
|
239
311
|
try {
|
|
240
|
-
|
|
312
|
+
const mode = getSecureCredentialsMode();
|
|
313
|
+
const keyringMode = (mode === 'keyring');
|
|
314
|
+
if (!keyringMode) {
|
|
241
315
|
aTunnelIAs = [];
|
|
242
316
|
try {
|
|
243
317
|
const $ia = $("#node-config-input-tunnelIA");
|
|
@@ -275,8 +349,14 @@
|
|
|
275
349
|
|
|
276
350
|
// Secure: Tunnel IA selection
|
|
277
351
|
try {
|
|
352
|
+
const storedTunnelIA = (() => {
|
|
353
|
+
const manualStored = normalizeTunnelIAValue(node.tunnelInterfaceIndividualAddress);
|
|
354
|
+
const keyringStored = normalizeTunnelIAValue(node.tunnelIA);
|
|
355
|
+
return manualStored || keyringStored;
|
|
356
|
+
})();
|
|
357
|
+
setTunnelIAValue(storedTunnelIA);
|
|
278
358
|
$("#node-config-input-tunnelIASelection").val(typeof node.tunnelIASelection === 'undefined' ? 'Auto' : node.tunnelIASelection);
|
|
279
|
-
$("#node-config-input-tunnelIA").
|
|
359
|
+
$("#node-config-input-tunnelIA").on('change input', syncTunnelIAFromKeyring);
|
|
280
360
|
const toggleTunnelIA = () => {
|
|
281
361
|
if ($("#node-config-input-tunnelIASelection").val() === 'Manual') {
|
|
282
362
|
$("#divTunnelIA").show();
|
|
@@ -299,8 +379,8 @@
|
|
|
299
379
|
$("#node-config-input-tunnelIA").autocomplete({
|
|
300
380
|
minLength: 0,
|
|
301
381
|
source: function (request, response) { response(aTunnelIAs); },
|
|
302
|
-
focus: function (event, ui) {
|
|
303
|
-
select: function (event, ui) {
|
|
382
|
+
focus: function (event, ui) { setTunnelIAValue(ui.item.value); return false; },
|
|
383
|
+
select: function (event, ui) { setTunnelIAValue(ui.item.value); return false; }
|
|
304
384
|
}).on('focus click', function () {
|
|
305
385
|
// Show dropdown on focus/click
|
|
306
386
|
$(this).autocomplete('search', '');
|
|
@@ -310,7 +390,9 @@
|
|
|
310
390
|
|
|
311
391
|
try {
|
|
312
392
|
$("#node-config-input-secureCredentialsMode").val(typeof node.secureCredentialsMode === 'undefined' ? 'keyring' : node.secureCredentialsMode);
|
|
313
|
-
$("#node-config-input-tunnelInterfaceIndividualAddress").
|
|
393
|
+
$("#node-config-input-tunnelInterfaceIndividualAddress").on('change input', syncTunnelIAFromManual);
|
|
394
|
+
$("#node-config-input-tunnelUserPassword").val(typeof node.tunnelUserPassword === 'undefined' ? '' : node.tunnelUserPassword);
|
|
395
|
+
$("#node-config-input-tunnelUserId").val(typeof node.tunnelUserId === 'undefined' ? '' : node.tunnelUserId);
|
|
314
396
|
$("#node-config-input-secureCredentialsMode").on('change', function () {
|
|
315
397
|
updateSecureCredentialMode();
|
|
316
398
|
updateSecureMulticastHint();
|
|
@@ -508,9 +590,7 @@
|
|
|
508
590
|
// Abilita manualmente la lista dei protocolli quando l'utente modifica l'IP a mano
|
|
509
591
|
try {
|
|
510
592
|
$("#node-config-input-host").on('input', function () {
|
|
511
|
-
const isSecure = (
|
|
512
|
-
try { return $("#tabsMain").tabs("option", "active") === 1; } catch (e) { return !!node.knxSecureSelected; }
|
|
513
|
-
})();
|
|
593
|
+
const isSecure = isSecureTabActive();
|
|
514
594
|
const $sel = $("#node-config-input-hostProtocol");
|
|
515
595
|
// Abilita select
|
|
516
596
|
$sel.prop('disabled', false);
|
|
@@ -548,6 +628,8 @@
|
|
|
548
628
|
}
|
|
549
629
|
// If discovery knows protocol, preselect it (keep select enabled for manual override)
|
|
550
630
|
if (proto) { $("#node-config-input-hostProtocol").val(proto); }
|
|
631
|
+
const octets = parseIPv4Address(ipTyped);
|
|
632
|
+
if (octets && !isMulticastIPv4(octets)) enforceProtocolFromIP();
|
|
551
633
|
}
|
|
552
634
|
} catch (e) { }
|
|
553
635
|
});
|
|
@@ -614,6 +696,9 @@
|
|
|
614
696
|
node._csvEditor.destroy();
|
|
615
697
|
node._csvEditor = null;
|
|
616
698
|
}
|
|
699
|
+
try {
|
|
700
|
+
$("#node-config-input-tunnelIA").val($("#node-config-input-tunnelInterfaceIndividualAddress").val());
|
|
701
|
+
} catch (e) { }
|
|
617
702
|
} catch (e) { }
|
|
618
703
|
// Check if the csv file contains errors
|
|
619
704
|
if (($("#node-config-input-csv").val() != 'undefined' && $("#node-config-input-csv").val() != "") || ($("#node-config-input-keyring").val() != 'undefined' && $("#node-config-input-keyring").val() != "")) {
|
|
@@ -734,6 +819,7 @@
|
|
|
734
819
|
<select id="node-config-input-secureCredentialsMode" style="width:200px;">
|
|
735
820
|
<option value="keyring" data-i18n="knxUltimate-config.ets.secure_credentials_mode_keyring"></option>
|
|
736
821
|
<option value="manual" data-i18n="knxUltimate-config.ets.secure_credentials_mode_manual"></option>
|
|
822
|
+
<option value="combined" data-i18n="knxUltimate-config.ets.secure_credentials_mode_combined"></option>
|
|
737
823
|
</select>
|
|
738
824
|
</div>
|
|
739
825
|
<div id="secureKeyringFields">
|
|
@@ -762,9 +848,13 @@
|
|
|
762
848
|
<label for="node-config-input-tunnelInterfaceIndividualAddress"><i class="fa fa-map-marker"></i> <span data-i18n="knxUltimate-config.ets.tunnel_interface_individual_address"></span></label>
|
|
763
849
|
<input type="text" id="node-config-input-tunnelInterfaceIndividualAddress" style="width:150px;" data-i18n="[placeholder]knxUltimate-config.ets.tunnel_interface_individual_address_placeholder"/>
|
|
764
850
|
</div>
|
|
851
|
+
<div class="form-row" id="rowTunnelUserId" style="display:none;">
|
|
852
|
+
<label for="node-config-input-tunnelUserId"><i class="fa fa-id-badge"></i> <span data-i18n="knxUltimate-config.ets.tunnel_user_id"></span></label>
|
|
853
|
+
<input type="text" id="node-config-input-tunnelUserId" style="width:150px;" />
|
|
854
|
+
</div>
|
|
765
855
|
<div class="form-row" id="rowTunnelUserPassword" style="display:none;">
|
|
766
856
|
<label for="node-config-input-tunnelUserPassword"><i class="fa fa-lock"></i> <span data-i18n="knxUltimate-config.ets.tunnel_user_password"></span></label>
|
|
767
|
-
<input type="
|
|
857
|
+
<input type="text" id="node-config-input-tunnelUserPassword" style="width:200px;" />
|
|
768
858
|
</div>
|
|
769
859
|
</p>
|
|
770
860
|
</div>
|
|
@@ -101,8 +101,24 @@ module.exports = (RED) => {
|
|
|
101
101
|
node.secureCredentialsMode = typeof config.secureCredentialsMode === "undefined" ? "keyring" : config.secureCredentialsMode;
|
|
102
102
|
// 2025-09 Secure Tunnel Interface IA selection (Auto/Manual)
|
|
103
103
|
node.tunnelIASelection = typeof config.tunnelIASelection === "undefined" ? "Auto" : config.tunnelIASelection;
|
|
104
|
-
node.tunnelIA = typeof config.tunnelIA === "undefined" ? "" : config.tunnelIA;
|
|
105
|
-
node.tunnelInterfaceIndividualAddress = typeof config.tunnelInterfaceIndividualAddress === "undefined"
|
|
104
|
+
node.tunnelIA = typeof config.tunnelIA === "undefined" || config.tunnelIA === null ? "" : String(config.tunnelIA);
|
|
105
|
+
node.tunnelInterfaceIndividualAddress = typeof config.tunnelInterfaceIndividualAddress === "undefined" || config.tunnelInterfaceIndividualAddress === null
|
|
106
|
+
? ""
|
|
107
|
+
: String(config.tunnelInterfaceIndividualAddress);
|
|
108
|
+
const normalizedTunnelIA = (value) => {
|
|
109
|
+
if (typeof value !== "string") return "";
|
|
110
|
+
const trimmed = value.trim();
|
|
111
|
+
return trimmed === "undefined" ? "" : trimmed;
|
|
112
|
+
};
|
|
113
|
+
node.tunnelIA = normalizedTunnelIA(node.tunnelIA);
|
|
114
|
+
node.tunnelInterfaceIndividualAddress = normalizedTunnelIA(node.tunnelInterfaceIndividualAddress);
|
|
115
|
+
if (!node.tunnelInterfaceIndividualAddress && node.tunnelIA) {
|
|
116
|
+
node.tunnelInterfaceIndividualAddress = node.tunnelIA;
|
|
117
|
+
} else if (!node.tunnelIA && node.tunnelInterfaceIndividualAddress) {
|
|
118
|
+
node.tunnelIA = node.tunnelInterfaceIndividualAddress;
|
|
119
|
+
}
|
|
120
|
+
node.tunnelUserPassword = typeof config.tunnelUserPassword === "undefined" ? "" : config.tunnelUserPassword;
|
|
121
|
+
node.tunnelUserId = typeof config.tunnelUserId === "undefined" ? "" : config.tunnelUserId;
|
|
106
122
|
node.name = config.name === undefined || config.name === "" ? node.host : config.name; // 12/08/2021
|
|
107
123
|
node.timerKNXUltimateCheckState = null; // 08/10/2021 Check the state. If not connected and autoreconnect is true, retrig the connetion attempt.
|
|
108
124
|
node.knxConnectionProperties = null; // Retains the connection properties
|
|
@@ -128,7 +144,8 @@ module.exports = (RED) => {
|
|
|
128
144
|
) {
|
|
129
145
|
node.hostProtocol = "Multicast";
|
|
130
146
|
} else {
|
|
131
|
-
node.
|
|
147
|
+
const isSecure = node.knxSecureSelected === true || node.knxSecureSelected === "true";
|
|
148
|
+
node.hostProtocol = isSecure ? "TunnelTCP" : "TunnelUDP";
|
|
132
149
|
}
|
|
133
150
|
node.sysLogger?.info("IP Protocol AUTO SET to " + node.hostProtocol + ", based on IP " + node.host);
|
|
134
151
|
}
|
|
@@ -161,29 +178,40 @@ module.exports = (RED) => {
|
|
|
161
178
|
try {
|
|
162
179
|
if (node.knxSecureSelected) {
|
|
163
180
|
const secureMode = typeof node.secureCredentialsMode === "string" ? node.secureCredentialsMode : "keyring";
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
const useManual = secureMode === "manual" || secureMode === "combined";
|
|
182
|
+
const useKeyring = secureMode === "keyring" || secureMode === "combined";
|
|
183
|
+
|
|
184
|
+
const secureConfig = {};
|
|
185
|
+
const modeParts = [];
|
|
186
|
+
|
|
187
|
+
if (useManual) {
|
|
188
|
+
const manualIA = (node.tunnelInterfaceIndividualAddress || "").trim();
|
|
189
|
+
const manualUserId = (node.tunnelUserId || "").trim();
|
|
190
|
+
const manualPwd = node.tunnelUserPassword || "";
|
|
191
|
+
|
|
192
|
+
if (manualIA) {
|
|
193
|
+
secureConfig.tunnelInterfaceIndividualAddress = manualIA;
|
|
172
194
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
195
|
+
if (manualUserId) {
|
|
196
|
+
secureConfig.tunnelUserId = manualUserId;
|
|
197
|
+
}
|
|
198
|
+
// Always include password property so KNX library receives the intended value (even if empty)
|
|
199
|
+
secureConfig.tunnelUserPassword = manualPwd;
|
|
200
|
+
modeParts.push("manual tunnel credentials");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (useKeyring) {
|
|
204
|
+
secureConfig.knxkeys_file_path = node.keyringFileXML || "";
|
|
205
|
+
secureConfig.knxkeys_password = node.credentials?.keyringFilePassword || "";
|
|
206
|
+
|
|
182
207
|
try {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
208
|
+
const manualSelectionIA = normalizedTunnelIA(node.tunnelIA);
|
|
209
|
+
if (node.tunnelIASelection === "Manual" && manualSelectionIA) {
|
|
210
|
+
if (!secureConfig.tunnelInterfaceIndividualAddress) {
|
|
211
|
+
secureConfig.tunnelInterfaceIndividualAddress = manualSelectionIA;
|
|
212
|
+
}
|
|
213
|
+
} else if (!secureConfig.tunnelInterfaceIndividualAddress) {
|
|
214
|
+
secureConfig.tunnelInterfaceIndividualAddress = ""; // Auto (let KNX stack select)
|
|
187
215
|
}
|
|
188
216
|
} catch (e) { /* empty */ }
|
|
189
217
|
|
|
@@ -199,9 +227,18 @@ module.exports = (RED) => {
|
|
|
199
227
|
node.sysLogger?.error("KNX Secure: keyring validation failed: " + err.message);
|
|
200
228
|
// Keep secure enabled: KNXClient will emit detailed errors on connect
|
|
201
229
|
}
|
|
202
|
-
} else {
|
|
203
|
-
RED.log.info("KNX-Secure: secure mode selected. Using provided keyring and password.");
|
|
204
230
|
}
|
|
231
|
+
modeParts.push("keyring file/password");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (Object.keys(secureConfig).length > 0) {
|
|
235
|
+
node.secureTunnelConfig = secureConfig;
|
|
236
|
+
} else {
|
|
237
|
+
node.secureTunnelConfig = undefined;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (modeParts.length > 0) {
|
|
241
|
+
RED.log.info(`KNX-Secure: secure mode selected (${modeParts.join(" + ")}). Node ${node.name || node.id}`);
|
|
205
242
|
}
|
|
206
243
|
} else {
|
|
207
244
|
RED.log.info("KNX-Unsecure: connection to insecure interface/router using node " + (node.name || node.id));
|
|
@@ -765,7 +802,8 @@ module.exports = (RED) => {
|
|
|
765
802
|
_dest = _datagram.cEMIMessage.dstAddress.toString();
|
|
766
803
|
|
|
767
804
|
if (_evt === null || _src === null || _dest === null) {
|
|
768
|
-
node.sysLogger?.
|
|
805
|
+
node.sysLogger?.warn(`HandleBusEvent: unable to parse telegram, ignored (evt=${_evt || 'n/a'} src=${_src || 'n/a'} dest=${_dest || 'n/a'})`);
|
|
806
|
+
return;
|
|
769
807
|
};
|
|
770
808
|
|
|
771
809
|
_echoed = _echoed || false;
|
|
@@ -1494,7 +1532,7 @@ module.exports = (RED) => {
|
|
|
1494
1532
|
try {
|
|
1495
1533
|
jsValue = dptlib.fromBuffer(_Rawvalue, dpt);
|
|
1496
1534
|
if (jsValue === null) {
|
|
1497
|
-
node.sysLogger?.
|
|
1535
|
+
node.sysLogger?.warn(
|
|
1498
1536
|
"buildInputMessage: received a wrong datagram form KNX BUS, from device " +
|
|
1499
1537
|
_srcGA +
|
|
1500
1538
|
" Destination " +
|
package/nodes/knxUltimate.html
CHANGED
|
@@ -417,9 +417,12 @@
|
|
|
417
417
|
try { sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim(); } catch (error) { }
|
|
418
418
|
$('#node-input-name').val(sDevName);
|
|
419
419
|
var optVal = $("#node-input-dpt option:contains('" + (ui.item.dpt || '').trim() + "')").attr('value');
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
420
|
+
var $dptSelect = $("#node-input-dpt");
|
|
421
|
+
if (optVal !== undefined && optVal !== null) {
|
|
422
|
+
$dptSelect.val(optVal).trigger('change');
|
|
423
|
+
} else {
|
|
424
|
+
$dptSelect.trigger('change');
|
|
425
|
+
}
|
|
423
426
|
// Persist secure flag for dynamic icon
|
|
424
427
|
try {
|
|
425
428
|
$("#node-input-gaSecure").val(ui.item.isSecure ? 'true' : 'false');
|
|
@@ -946,4 +949,4 @@
|
|
|
946
949
|
</div>
|
|
947
950
|
</div>
|
|
948
951
|
<br /><br />
|
|
949
|
-
</script>
|
|
952
|
+
</script>
|
|
@@ -106,8 +106,12 @@
|
|
|
106
106
|
}
|
|
107
107
|
$('#node-input-namebatterysensor').val(sDevName);
|
|
108
108
|
var optVal = $("#node-input-dptbatterysensor option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
var $dptSelect = $("#node-input-dptbatterysensor");
|
|
110
|
+
if (optVal !== undefined && optVal !== null) {
|
|
111
|
+
$dptSelect.val(optVal).trigger('change');
|
|
112
|
+
} else {
|
|
113
|
+
$dptSelect.trigger('change');
|
|
114
|
+
}
|
|
111
115
|
}
|
|
112
116
|
}).focus(function () {
|
|
113
117
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -243,4 +247,3 @@
|
|
|
243
247
|
|
|
244
248
|
</script>
|
|
245
249
|
|
|
246
|
-
|
|
@@ -144,8 +144,12 @@
|
|
|
144
144
|
}
|
|
145
145
|
$('#node-input-nameDim').val(sDevName);
|
|
146
146
|
var optVal = $("#node-input-dptrepeat option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
var $dptSelect = $("#node-input-dptrepeat");
|
|
148
|
+
if (optVal !== undefined && optVal !== null) {
|
|
149
|
+
$dptSelect.val(optVal).trigger('change');
|
|
150
|
+
} else {
|
|
151
|
+
$dptSelect.trigger('change');
|
|
152
|
+
}
|
|
149
153
|
}
|
|
150
154
|
}).focus(function () {
|
|
151
155
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -194,8 +198,12 @@
|
|
|
194
198
|
}
|
|
195
199
|
$('#node-input-nameshort_release').val(sDevName);
|
|
196
200
|
var optVal = $("#node-input-dptshort_release option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
197
|
-
|
|
198
|
-
|
|
201
|
+
var $dptSelect = $("#node-input-dptshort_release");
|
|
202
|
+
if (optVal !== undefined && optVal !== null) {
|
|
203
|
+
$dptSelect.val(optVal).trigger('change');
|
|
204
|
+
} else {
|
|
205
|
+
$dptSelect.trigger('change');
|
|
206
|
+
}
|
|
199
207
|
}
|
|
200
208
|
}).focus(function () {
|
|
201
209
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -227,8 +235,12 @@
|
|
|
227
235
|
}
|
|
228
236
|
$('#node-input-nameshort_releaseStatus').val(sDevName);
|
|
229
237
|
var optVal = $("#node-input-dptshort_releaseStatus option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
230
|
-
|
|
231
|
-
|
|
238
|
+
var $dptSelect = $("#node-input-dptshort_releaseStatus");
|
|
239
|
+
if (optVal !== undefined && optVal !== null) {
|
|
240
|
+
$dptSelect.val(optVal).trigger('change');
|
|
241
|
+
} else {
|
|
242
|
+
$dptSelect.trigger('change');
|
|
243
|
+
}
|
|
232
244
|
}
|
|
233
245
|
}).focus(function () {
|
|
234
246
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -261,8 +273,12 @@
|
|
|
261
273
|
}
|
|
262
274
|
$('#node-input-namedouble_short_release').val(sDevName);
|
|
263
275
|
var optVal = $("#node-input-dptdouble_short_release option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
264
|
-
|
|
265
|
-
|
|
276
|
+
var $dptSelect = $("#node-input-dptdouble_short_release");
|
|
277
|
+
if (optVal !== undefined && optVal !== null) {
|
|
278
|
+
$dptSelect.val(optVal).trigger('change');
|
|
279
|
+
} else {
|
|
280
|
+
$dptSelect.trigger('change');
|
|
281
|
+
}
|
|
266
282
|
}
|
|
267
283
|
}).focus(function () {
|
|
268
284
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -294,8 +310,12 @@
|
|
|
294
310
|
}
|
|
295
311
|
$('#node-input-namedouble_short_releaseStatus').val(sDevName);
|
|
296
312
|
var optVal = $("#node-input-dptdouble_short_releaseStatus option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
297
|
-
|
|
298
|
-
|
|
313
|
+
var $dptSelect = $("#node-input-dptdouble_short_releaseStatus");
|
|
314
|
+
if (optVal !== undefined && optVal !== null) {
|
|
315
|
+
$dptSelect.val(optVal).trigger('change');
|
|
316
|
+
} else {
|
|
317
|
+
$dptSelect.trigger('change');
|
|
318
|
+
}
|
|
299
319
|
}
|
|
300
320
|
}).focus(function () {
|
|
301
321
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -460,5 +480,3 @@
|
|
|
460
480
|
|
|
461
481
|
|
|
462
482
|
</script>
|
|
463
|
-
|
|
464
|
-
|
|
@@ -115,8 +115,12 @@
|
|
|
115
115
|
}
|
|
116
116
|
$('#node-input-namecontact').val(sDevName)
|
|
117
117
|
var optVal = $('#node-input-dptcontact option:contains(\'' + ui.item.label.split('#')[2].trim() + '\')').attr('value')
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
var $dptSelect = $('#node-input-dptcontact')
|
|
119
|
+
if (optVal !== undefined && optVal !== null) {
|
|
120
|
+
$dptSelect.val(optVal).trigger('change')
|
|
121
|
+
} else {
|
|
122
|
+
$dptSelect.trigger('change')
|
|
123
|
+
}
|
|
120
124
|
},
|
|
121
125
|
}).focus(function () {
|
|
122
126
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -241,4 +245,3 @@
|
|
|
241
245
|
<br />
|
|
242
246
|
</script>
|
|
243
247
|
|
|
244
|
-
|
|
@@ -233,8 +233,13 @@
|
|
|
233
233
|
} catch (error) { }
|
|
234
234
|
$(_destinationWidgetName).val(sDevName);
|
|
235
235
|
var optVal = $(_destinationWidgetDPT + " option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr("value");
|
|
236
|
-
|
|
237
|
-
|
|
236
|
+
const $dptSelect = $(_destinationWidgetDPT);
|
|
237
|
+
if (optVal !== undefined && optVal !== null) {
|
|
238
|
+
$dptSelect.val(optVal).trigger('change');
|
|
239
|
+
} else {
|
|
240
|
+
// Ensure downstream widgets refresh even when the DPT is missing
|
|
241
|
+
$dptSelect.trigger('change');
|
|
242
|
+
}
|
|
238
243
|
},
|
|
239
244
|
}).focus(function () {
|
|
240
245
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -1485,4 +1490,3 @@
|
|
|
1485
1490
|
</script>
|
|
1486
1491
|
|
|
1487
1492
|
|
|
1488
|
-
|
|
@@ -105,8 +105,12 @@
|
|
|
105
105
|
}
|
|
106
106
|
$('#node-input-namelightsensor').val(sDevName);
|
|
107
107
|
var optVal = $("#node-input-dptlightsensor option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
var $dptSelect = $("#node-input-dptlightsensor");
|
|
109
|
+
if (optVal !== undefined && optVal !== null) {
|
|
110
|
+
$dptSelect.val(optVal).trigger('change');
|
|
111
|
+
} else {
|
|
112
|
+
$dptSelect.trigger('change');
|
|
113
|
+
}
|
|
110
114
|
}
|
|
111
115
|
}).focus(function () {
|
|
112
116
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -245,4 +249,3 @@
|
|
|
245
249
|
</script>
|
|
246
250
|
|
|
247
251
|
|
|
248
|
-
|
|
@@ -104,8 +104,12 @@
|
|
|
104
104
|
}
|
|
105
105
|
$('#node-input-namemotion').val(sDevName);
|
|
106
106
|
var optVal = $("#node-input-dptmotion option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
var $dptSelect = $("#node-input-dptmotion");
|
|
108
|
+
if (optVal !== undefined && optVal !== null) {
|
|
109
|
+
$dptSelect.val(optVal).trigger('change');
|
|
110
|
+
} else {
|
|
111
|
+
$dptSelect.trigger('change');
|
|
112
|
+
}
|
|
109
113
|
}
|
|
110
114
|
}).focus(function () {
|
|
111
115
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -233,4 +237,3 @@
|
|
|
233
237
|
|
|
234
238
|
</script>
|
|
235
239
|
|
|
236
|
-
|
|
@@ -147,8 +147,12 @@
|
|
|
147
147
|
}
|
|
148
148
|
$('#node-input-namescene').val(sDevName);
|
|
149
149
|
var optVal = $("#node-input-dptscene option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
var $dptSelect = $("#node-input-dptscene");
|
|
151
|
+
if (optVal !== undefined && optVal !== null) {
|
|
152
|
+
$dptSelect.val(optVal).trigger('change');
|
|
153
|
+
} else {
|
|
154
|
+
$dptSelect.trigger('change');
|
|
155
|
+
}
|
|
152
156
|
ShowHideValScene();
|
|
153
157
|
}
|
|
154
158
|
}).focus(function () {
|
|
@@ -184,8 +188,12 @@
|
|
|
184
188
|
}
|
|
185
189
|
$('#node-input-namesceneStatus').val(sDevName);
|
|
186
190
|
var optVal = $("#node-input-dptsceneStatus option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
187
|
-
|
|
188
|
-
|
|
191
|
+
var $dptSelect = $("#node-input-dptsceneStatus");
|
|
192
|
+
if (optVal !== undefined && optVal !== null) {
|
|
193
|
+
$dptSelect.val(optVal).trigger('change');
|
|
194
|
+
} else {
|
|
195
|
+
$dptSelect.trigger('change');
|
|
196
|
+
}
|
|
189
197
|
ShowHideValScene();
|
|
190
198
|
}
|
|
191
199
|
}).focus(function () {
|
|
@@ -221,8 +229,12 @@
|
|
|
221
229
|
}
|
|
222
230
|
$('#node-input-namesceneMulti').val(sDevName);
|
|
223
231
|
var optVal = $("#node-input-dptsceneMulti option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
224
|
-
|
|
225
|
-
|
|
232
|
+
var $dptSelect = $("#node-input-dptsceneMulti");
|
|
233
|
+
if (optVal !== undefined && optVal !== null) {
|
|
234
|
+
$dptSelect.val(optVal).trigger('change');
|
|
235
|
+
} else {
|
|
236
|
+
$dptSelect.trigger('change');
|
|
237
|
+
}
|
|
226
238
|
ShowHideValScene();
|
|
227
239
|
}
|
|
228
240
|
}).focus(function () {
|
|
@@ -589,5 +601,3 @@
|
|
|
589
601
|
</div> <!-- // End TABS -->
|
|
590
602
|
|
|
591
603
|
</script>
|
|
592
|
-
|
|
593
|
-
|
|
@@ -107,8 +107,12 @@
|
|
|
107
107
|
}
|
|
108
108
|
$('#node-input-namerepeat').val(sDevName);
|
|
109
109
|
var optVal = $("#node-input-dptrepeat option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
var $dptSelect = $("#node-input-dptrepeat");
|
|
111
|
+
if (optVal !== undefined && optVal !== null) {
|
|
112
|
+
$dptSelect.val(optVal).trigger('change');
|
|
113
|
+
} else {
|
|
114
|
+
$dptSelect.trigger('change');
|
|
115
|
+
}
|
|
112
116
|
}
|
|
113
117
|
}).focus(function () {
|
|
114
118
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -235,4 +239,3 @@
|
|
|
235
239
|
|
|
236
240
|
</script>
|
|
237
241
|
|
|
238
|
-
|
|
@@ -105,8 +105,12 @@
|
|
|
105
105
|
}
|
|
106
106
|
$('#node-input-nametemperaturesensor').val(sDevName);
|
|
107
107
|
var optVal = $("#node-input-dpttemperaturesensor option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
var $dptSelect = $("#node-input-dpttemperaturesensor");
|
|
109
|
+
if (optVal !== undefined && optVal !== null) {
|
|
110
|
+
$dptSelect.val(optVal).trigger('change');
|
|
111
|
+
} else {
|
|
112
|
+
$dptSelect.trigger('change');
|
|
113
|
+
}
|
|
110
114
|
}
|
|
111
115
|
}).focus(function () {
|
|
112
116
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -243,4 +247,3 @@
|
|
|
243
247
|
|
|
244
248
|
</script>
|
|
245
249
|
|
|
246
|
-
|
|
@@ -106,8 +106,12 @@
|
|
|
106
106
|
}
|
|
107
107
|
$('#node-input-namezigbeeconnectivity').val(sDevName);
|
|
108
108
|
var optVal = $("#node-input-dptzigbeeconnectivity option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
var $dptSelect = $("#node-input-dptzigbeeconnectivity");
|
|
110
|
+
if (optVal !== undefined && optVal !== null) {
|
|
111
|
+
$dptSelect.val(optVal).trigger('change');
|
|
112
|
+
} else {
|
|
113
|
+
$dptSelect.trigger('change');
|
|
114
|
+
}
|
|
111
115
|
}
|
|
112
116
|
}).focus(function () {
|
|
113
117
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -243,4 +247,3 @@
|
|
|
243
247
|
|
|
244
248
|
</script>
|
|
245
249
|
|
|
246
|
-
|
|
@@ -106,8 +106,12 @@
|
|
|
106
106
|
}
|
|
107
107
|
$('#node-input-namedevice_software_update').val(sDevName);
|
|
108
108
|
var optVal = $("#node-input-dptdevice_software_update option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
var $dptSelect = $("#node-input-dptdevice_software_update");
|
|
110
|
+
if (optVal !== undefined && optVal !== null) {
|
|
111
|
+
$dptSelect.val(optVal).trigger('change');
|
|
112
|
+
} else {
|
|
113
|
+
$dptSelect.trigger('change');
|
|
114
|
+
}
|
|
111
115
|
}
|
|
112
116
|
}).focus(function () {
|
|
113
117
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -243,4 +247,3 @@
|
|
|
243
247
|
|
|
244
248
|
</script>
|
|
245
249
|
|
|
246
|
-
|
|
@@ -141,9 +141,12 @@
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
var optVal = $("#node-input-dpt option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
var $dptSelect = $("#node-input-" + _DPT);
|
|
145
|
+
if (optVal !== undefined && optVal !== null) {
|
|
146
|
+
$dptSelect.val(optVal).trigger('change');
|
|
147
|
+
} else {
|
|
148
|
+
$dptSelect.trigger('change');
|
|
149
|
+
}
|
|
147
150
|
}
|
|
148
151
|
};
|
|
149
152
|
return paramAutoComplete;
|
|
@@ -358,4 +361,3 @@
|
|
|
358
361
|
</br>
|
|
359
362
|
</script>
|
|
360
363
|
|
|
361
|
-
|
|
@@ -97,9 +97,12 @@
|
|
|
97
97
|
}
|
|
98
98
|
$('#node-input-name').val("Recall: " + sDevName + "/" + $('#node-input-name').val().split("/")[1]);
|
|
99
99
|
var optVal = $("#node-input-dpt option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
var $dptSelect = $("#node-input-dpt");
|
|
101
|
+
if (optVal !== undefined && optVal !== null) {
|
|
102
|
+
$dptSelect.val(optVal).trigger('change');
|
|
103
|
+
} else {
|
|
104
|
+
$dptSelect.trigger('change');
|
|
105
|
+
}
|
|
103
106
|
}
|
|
104
107
|
}).focus(function () {
|
|
105
108
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -222,9 +225,12 @@
|
|
|
222
225
|
}
|
|
223
226
|
$('#node-input-name').val($('#node-input-name').val().split("/")[0] + "/Save: " + sDevName);
|
|
224
227
|
var optVal = $("#node-input-dptSave option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
+
var $dptSelect = $("#node-input-dptSave");
|
|
229
|
+
if (optVal !== undefined && optVal !== null) {
|
|
230
|
+
$dptSelect.val(optVal).trigger('change');
|
|
231
|
+
} else {
|
|
232
|
+
$dptSelect.trigger('change');
|
|
233
|
+
}
|
|
228
234
|
}
|
|
229
235
|
}).focus(function () {
|
|
230
236
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -363,7 +369,12 @@
|
|
|
363
369
|
} catch (error) {
|
|
364
370
|
}
|
|
365
371
|
var optVal = $(".rowRuleDPT option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
366
|
-
oDPTField
|
|
372
|
+
var $dptSelect = oDPTField;
|
|
373
|
+
if (optVal !== undefined && optVal !== null) {
|
|
374
|
+
$dptSelect.val(optVal).trigger('change');
|
|
375
|
+
} else {
|
|
376
|
+
$dptSelect.trigger('change');
|
|
377
|
+
}
|
|
367
378
|
}
|
|
368
379
|
}).focus(function () {
|
|
369
380
|
$(this).autocomplete('search', $(this).val() + 'exactmatch');
|
|
@@ -493,5 +504,3 @@
|
|
|
493
504
|
</div>
|
|
494
505
|
|
|
495
506
|
</script>
|
|
496
|
-
|
|
497
|
-
|
|
@@ -88,8 +88,10 @@
|
|
|
88
88
|
"secure_credentials_mode": "Quelle für Secure-Zugangsdaten",
|
|
89
89
|
"secure_credentials_mode_keyring": "ETS-Keyring-Datei",
|
|
90
90
|
"secure_credentials_mode_manual": "Manuelle Zugangsdaten",
|
|
91
|
+
"secure_credentials_mode_combined": "Keyring + manuelles Tunnel-Passwort",
|
|
91
92
|
"tunnel_interface_individual_address": "Individuelle Adresse der Tunnel-Schnittstelle",
|
|
92
93
|
"tunnel_interface_individual_address_placeholder": "1.1.1",
|
|
94
|
+
"tunnel_user_id": "Tunnel-Benutzer-ID",
|
|
93
95
|
"tunnel_user_password": "Tunnel-Benutzerpasswort",
|
|
94
96
|
"ga_list_label": "ETS-Gruppenadressliste"
|
|
95
97
|
},
|
|
@@ -19,9 +19,14 @@ Dieser Node stellt die Verbindung zu deinem KNX/IP‑Gateway her.
|
|
|
19
19
|
| KNX Physical Address | Physikalische KNX‑Adresse, z. B. `1.1.200`. Standard: `15.15.22`. |
|
|
20
20
|
| Bind to local interface | Lokales Netzwerk‑Interface für die Kommunikation. "Auto" wählt automatisch. Bei mehreren Interfaces (Ethernet/WLAN) ist eine manuelle Auswahl empfehlenswert, damit keine UDP‑Telegramme verloren gehen. |
|
|
21
21
|
| Automatically connect to KNX BUS at start | Automatisch beim Start verbinden. Standard: "Yes". |
|
|
22
|
-
| Secure credentials source |
|
|
23
|
-
| Tunnel interface individual address | Sichtbar
|
|
24
|
-
| Tunnel user
|
|
22
|
+
| Secure credentials source | Leg fest, wie KNX Secure Daten bereitgestellt werden: **ETS-Keyring-Datei** (Data-Secure-Schlüssel und ggf. Tunnel-Zugang aus dem Keyring), **Manuelle Zugangsdaten** (nur KNX IP Tunnelling Secure mit manuell eingetragenem Benutzer) oder **Keyring + manuelles Tunnel-Passwort** (Data-Secure-Schlüssel aus dem Keyring, Tunnel-Benutzer/-Passwort manuell). Achtung: KNX Data Secure Telegramme benötigen immer einen Keyring. |
|
|
23
|
+
| Tunnel interface individual address | Sichtbar, sobald die gewählte Option manuelle Zugangsdaten enthält (Manuelle Zugangsdaten oder Keyring + manuelles Tunnel-Passwort). Optionale KNX-Individualadresse der Tunnel-Schnittstelle (z. B. `1.1.1`); leer lassen, damit KNX Ultimate automatisch verhandelt. |
|
|
24
|
+
| Tunnel user ID | Sichtbar bei manuellen Zugangsdaten. Optionale Kennung des KNX Secure Tunnel-Benutzers aus ETS. |
|
|
25
|
+
| Tunnel user password | Sichtbar bei manuellen Zugangsdaten. Passwort des KNX Secure Tunnel-Benutzers aus ETS. |
|
|
26
|
+
|
|
27
|
+
> **KNX Secure im Überblick**
|
|
28
|
+
> • *KNX Data Secure* schützt Gruppenadress-Telegramme und benötigt stets eine Keyring-Datei mit den Gruppenschlüsseln.
|
|
29
|
+
> • *KNX IP Tunnelling Secure* schützt den Verbindungsaufbau mithilfe eines Commissioning-Passworts. Dieses kann – je nach Modus – aus dem Keyring kommen oder manuell eingetragen werden.
|
|
25
30
|
|
|
26
31
|
<br/>
|
|
27
32
|
|
|
@@ -19,9 +19,14 @@
|
|
|
19
19
|
| KNX Physical Address | The physical KNX address, example 1.1.200. Default is "15.15.22".|
|
|
20
20
|
| Bind to local interface | The Node will use this local interface for communications. Leave "Auto" for automatic selection. If you have more than one lan connection, for example Ethernet and Wifi, it's strongly recommended to manually select the interface, otherwise not all UDP telegram will reach your computer, thus the Node may not work as expected. Default is "Auto". |
|
|
21
21
|
| Automatically connect to KNX BUS at start | Auto connect to the bus at start. Default is "Yes". |
|
|
22
|
-
| Secure credentials source |
|
|
23
|
-
| Tunnel interface individual address | Visible
|
|
24
|
-
| Tunnel user
|
|
22
|
+
| Secure credentials source | Choose how KNX Secure data is provided: **ETS keyring file** (Data Secure keys and, if available, tunnelling credentials come from the keyring), **Manual credentials** (only KNX IP Tunnelling Secure with a manually entered user) or **Keyring + manual tunnel password** (Data Secure keys from the keyring while the secure tunnel uses the manual user/password). Remember: KNX Data Secure telegrams always require a keyring. |
|
|
23
|
+
| Tunnel interface individual address | Visible whenever the selected mode includes manual credentials (Manual or Keyring + manual tunnel password). Optional KNX individual address for the secure tunnel interface (for example `1.1.1`); leave empty to let KNX Ultimate negotiate it automatically. |
|
|
24
|
+
| Tunnel user ID | Visible when manual credentials are used. Optional KNX Secure tunnel user identifier defined in ETS. |
|
|
25
|
+
| Tunnel user password | Visible when manual credentials are used. Password of the secure tunnelling user configured in ETS. |
|
|
26
|
+
|
|
27
|
+
> **KNX Secure at a glance**
|
|
28
|
+
> • *KNX Data Secure* protects group-address telegrams and **always** requires a keyring file containing the group keys.
|
|
29
|
+
> • *KNX IP Tunnelling Secure* protects the connection handshake using a commissioning password. The password can come from the keyring or be entered manually depending on the selected mode.
|
|
25
30
|
|
|
26
31
|
<br/>
|
|
27
32
|
|
|
@@ -85,8 +85,10 @@
|
|
|
85
85
|
"secure_credentials_mode": "Secure credentials source",
|
|
86
86
|
"secure_credentials_mode_keyring": "ETS keyring file",
|
|
87
87
|
"secure_credentials_mode_manual": "Manual credentials",
|
|
88
|
+
"secure_credentials_mode_combined": "Keyring + manual tunnel password",
|
|
88
89
|
"tunnel_interface_individual_address": "Tunnel interface individual address",
|
|
89
90
|
"tunnel_interface_individual_address_placeholder": "1.1.1",
|
|
91
|
+
"tunnel_user_id": "Tunnel user ID",
|
|
90
92
|
"tunnel_user_password": "Tunnel user password",
|
|
91
93
|
"ga_list_label": "ETS group address list"
|
|
92
94
|
},
|
|
@@ -89,8 +89,10 @@
|
|
|
89
89
|
"secure_credentials_mode": "Origine credenziali KNX Secure",
|
|
90
90
|
"secure_credentials_mode_keyring": "File keyring ETS",
|
|
91
91
|
"secure_credentials_mode_manual": "Credenziali manuali",
|
|
92
|
+
"secure_credentials_mode_combined": "File keyring + password tunnel manuale",
|
|
92
93
|
"tunnel_interface_individual_address": "Indirizzo individuale interfaccia tunnel",
|
|
93
94
|
"tunnel_interface_individual_address_placeholder": "1.1.1",
|
|
95
|
+
"tunnel_user_id": "ID utente tunnel",
|
|
94
96
|
"tunnel_user_password": "Password utente tunnel",
|
|
95
97
|
"ga_list_label": "Lista indirizzi di gruppo ETS"
|
|
96
98
|
},
|
|
@@ -19,9 +19,14 @@ Questo nodo si connette al tuo KNX/IP Gateway.
|
|
|
19
19
|
| KNX Physical Address | Indirizzo fisico KNX, es. `1.1.200`. Default: `15.15.22`. |
|
|
20
20
|
| Bind to local interface | Interfaccia di rete locale usata dal nodo. Lascia "Auto" per selezione automatica. Se hai più interfacce (Ethernet/Wi‑Fi), è consigliato impostarla manualmente per evitare perdita di telegrammi UDP. Default: "Auto". |
|
|
21
21
|
| Automatically connect to KNX BUS at start | Connessione automatica al BUS all’avvio. Default: "Yes". |
|
|
22
|
-
| Secure credentials source | Scegli **File keyring ETS** (
|
|
23
|
-
| Tunnel interface individual address | Visibile
|
|
24
|
-
| Tunnel user
|
|
22
|
+
| Secure credentials source | Scegli come fornire i dati KNX Secure: **File keyring ETS** (le chiavi Data Secure e, se presenti, le credenziali di tunnelling arrivano dal keyring), **Credenziali manuali** (solo KNX IP Tunnelling Secure con utente inserito a mano) oppure **File keyring + password tunnel manuale** (le chiavi Data Secure dal keyring e l’utente/password del tunnel impostati manualmente). Ricorda: i telegrammi KNX Data Secure richiedono sempre un keyring. |
|
|
23
|
+
| Tunnel interface individual address | Visibile quando la modalità selezionata prevede credenziali manuali (Credenziali manuali o File keyring + password tunnel manuale). Indirizzo individuale opzionale dell’interfaccia tunnel sicura (es. `1.1.1`); lascia vuoto per negoziazione automatica da parte di KNX Ultimate. |
|
|
24
|
+
| Tunnel user ID | Visibile quando sono attive credenziali manuali. ID opzionale dell’utente tunnel KNX Secure definito in ETS. |
|
|
25
|
+
| Tunnel user password | Visibile quando sono attive credenziali manuali. Password dell’utente tunnel KNX Secure configurata in ETS. |
|
|
26
|
+
|
|
27
|
+
> **Nota su KNX Secure**
|
|
28
|
+
> • *KNX Data Secure* protegge i telegrammi sugli indirizzi di gruppo e richiede sempre un file keyring con le chiavi di gruppo.
|
|
29
|
+
> • *KNX IP Tunnelling Secure* protegge l’handshake di connessione tramite una password di commissioning, che può essere letta dal keyring oppure inserita manualmente in base alla modalità scelta.
|
|
25
30
|
|
|
26
31
|
<br/>
|
|
27
32
|
|
|
@@ -19,9 +19,14 @@
|
|
|
19
19
|
| KNX Physical Address | 物理地址,如 `1.1.200`。默认 `15.15.22`。|
|
|
20
20
|
| Bind to local interface | 使用的本地网络接口。"Auto" 自动选择。若有多网卡(以太网/无线),建议手动指定,避免 UDP 丢包。|
|
|
21
21
|
| Automatically connect to KNX BUS at start | 启动时自动连接总线。默认 "Yes"。|
|
|
22
|
-
| Secure credentials source |
|
|
23
|
-
| Tunnel interface individual address |
|
|
24
|
-
| Tunnel user
|
|
22
|
+
| Secure credentials source | 选择如何提供 KNX Secure 数据:**ETS 密钥环文件**(Data Secure 密钥以及—若存在—隧道凭据来自密钥环)、**手动凭据**(仅启用 KNX IP 安全隧道,手动输入用户)或 **密钥环 + 手动隧道密码**(Data Secure 由密钥环提供,隧道用户/密码手动输入)。注意:KNX Data Secure 报文始终需要密钥环文件。|
|
|
23
|
+
| Tunnel interface individual address | 当所选模式包含手动凭据时显示(手动凭据或密钥环 + 手动隧道密码)。可选的安全隧道 KNX 个人地址(如 `1.1.1`);留空则由 KNX Ultimate 自动协商。|
|
|
24
|
+
| Tunnel user ID | 启用手动凭据时显示。可选的 KNX Secure 隧道用户 ID(在 ETS 中配置)。|
|
|
25
|
+
| Tunnel user password | 启用手动凭据时显示。输入 ETS 中配置的 KNX Secure 隧道用户密码。|
|
|
26
|
+
|
|
27
|
+
> **KNX Secure 概览**
|
|
28
|
+
> • *KNX Data Secure* 用于保护组地址报文,**始终** 需要包含组密钥的密钥环文件。
|
|
29
|
+
> • *KNX IP Tunnelling Secure* 通过调试密码保护连接握手,密码可以根据模式从密钥环中读取,或在界面中手动输入。
|
|
25
30
|
|
|
26
31
|
<br/>
|
|
27
32
|
|
|
@@ -84,8 +84,10 @@
|
|
|
84
84
|
"secure_credentials_mode": "安全凭据来源",
|
|
85
85
|
"secure_credentials_mode_keyring": "ETS 密钥环文件",
|
|
86
86
|
"secure_credentials_mode_manual": "手动凭据",
|
|
87
|
+
"secure_credentials_mode_combined": "密钥环 + 手动隧道密码",
|
|
87
88
|
"tunnel_interface_individual_address": "隧道接口个人地址",
|
|
88
89
|
"tunnel_interface_individual_address_placeholder": "1.1.1",
|
|
90
|
+
"tunnel_user_id": "隧道用户 ID",
|
|
89
91
|
"tunnel_user_password": "隧道用户密码",
|
|
90
92
|
"ga_list_label": "ETS 组地址列表"
|
|
91
93
|
},
|
package/package.json
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=20.18.1"
|
|
5
5
|
},
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.6",
|
|
7
7
|
"description": "Control your KNX and KNX Secure intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control and ETS group address importer. Easy to use and highly configurable.",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"binary-parser": "2.2.1",
|
|
10
10
|
"crypto-js": "4.2.0",
|
|
11
11
|
"dns-sync": "0.2.1",
|
|
12
12
|
"js-yaml": "4.1.0",
|
|
13
|
-
"knxultimate": "5.1.
|
|
13
|
+
"knxultimate": "5.1.1",
|
|
14
14
|
"lodash": "4.17.21",
|
|
15
15
|
"mkdirp": "3.0.1",
|
|
16
16
|
"node-color-log": "12.0.1",
|