node-red-contrib-knx-ultimate 3.3.2 → 3.3.3
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 +5 -0
- package/nodes/commonFunctions.js +1 -23
- package/nodes/knxUltimate-config.html +75 -25
- package/nodes/knxUltimate-config.js +8 -8
- package/nodes/utils/hueEngine.js +1 -1
- package/nodes/utils/utils.js +27 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 3.3.3** - November 2024<br/>
|
|
10
|
+
- KNX Config Node: Automatic KNX Gateway discover in the gateway node config window.<br/>
|
|
11
|
+
- KNX Engine: new: new telegram sequencer waiter, for more accurate timing in slow or sliggish computers.<br/>
|
|
12
|
+
- KNX Engine: bunp 4.0.0-beta.7 .<br/>
|
|
13
|
+
|
|
9
14
|
**Version 3.3.0** - November 2024<br/>
|
|
10
15
|
- KNX Engine: explicitly set the local port of the unicast socket on 3671 and the local IP of the multicast to 0.0.0.0.<br/>
|
|
11
16
|
- KNX Engine: many engine adaptation for the upcoming KNX-Secure implementation.<br/>
|
package/nodes/commonFunctions.js
CHANGED
|
@@ -310,29 +310,7 @@ module.exports = (RED) => {
|
|
|
310
310
|
|
|
311
311
|
// 14/08/2019 Endpoint for retrieving the ethernet interfaces
|
|
312
312
|
RED.httpAdmin.get("/knxUltimateDiscoverKNXGateways", RED.auth.needsPermission("knxUltimate-config.read"), async function (req, res) {
|
|
313
|
-
|
|
314
|
-
async function search() {
|
|
315
|
-
let jRet = [];
|
|
316
|
-
try {
|
|
317
|
-
const knxGateways = await KNXClient.discover();
|
|
318
|
-
// For each discovered gateway, get all possible device descriptions (usually only one)
|
|
319
|
-
// A description is a JSON object containing all details of the device and also what type of connection (Multicast, unicast, etc), it suppports
|
|
320
|
-
for (let index = 0; index < knxGateways.length; index++) {
|
|
321
|
-
const element = knxGateways[index];
|
|
322
|
-
const [ip, port] = element.split(':')
|
|
323
|
-
const descriptionsJSON = await KNXClient.getGatewayDescription(ip, port, 5000)
|
|
324
|
-
for (let index = 0; index < descriptionsJSON.length; index++) {
|
|
325
|
-
const element = descriptionsJSON[index];
|
|
326
|
-
jRet.push({ ip: ip, port: port, name: element.deviceInfo.name, physAddr: element.deviceInfo.formattedAddress });
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
res.json(jRet);
|
|
330
|
-
} catch (error) { }
|
|
331
|
-
}
|
|
332
|
-
search();
|
|
333
|
-
} catch (error) {
|
|
334
|
-
res.json({ error: error.stack });
|
|
335
|
-
}
|
|
313
|
+
res.json(require("./utils/utils").aDiscoveredknxGateways);
|
|
336
314
|
});
|
|
337
315
|
|
|
338
316
|
// 12/08/2021 Endpoint for deleting the GA persistent file for the current gateway
|
|
@@ -34,6 +34,32 @@
|
|
|
34
34
|
} catch (error) { }
|
|
35
35
|
|
|
36
36
|
var node = this;
|
|
37
|
+
// TIMER BLINK ####################################################
|
|
38
|
+
let blinkStatus = 2;
|
|
39
|
+
let timerBlinkBackground;
|
|
40
|
+
function blinkBackgroundArray(_arrayElementIDwithHashAtTheBeginning) {
|
|
41
|
+
if (timerBlinkBackground !== undefined) clearInterval(timerBlinkBackground);
|
|
42
|
+
timerBlinkBackground = setInterval(() => {
|
|
43
|
+
for (let index = 0; index < _arrayElementIDwithHashAtTheBeginning.length; index++) {
|
|
44
|
+
const _elementIDwithHashAtTheBeginning = _arrayElementIDwithHashAtTheBeginning[index];
|
|
45
|
+
if (isEven(blinkStatus)) $(_elementIDwithHashAtTheBeginning).css("background-color", "lightgreen");
|
|
46
|
+
if (!isEven(blinkStatus)) $(_elementIDwithHashAtTheBeginning).css("background-color", "");
|
|
47
|
+
}
|
|
48
|
+
blinkStatus += 1;
|
|
49
|
+
if (blinkStatus >= 14) {
|
|
50
|
+
clearInterval(timerBlinkBackground);
|
|
51
|
+
blinkStatus = 2;
|
|
52
|
+
for (let index = 0; index < _arrayElementIDwithHashAtTheBeginning.length; index++) {
|
|
53
|
+
const _elementIDwithHashAtTheBeginning = _arrayElementIDwithHashAtTheBeginning[index];
|
|
54
|
+
$(_elementIDwithHashAtTheBeginning).css("background-color", "");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}, 100);
|
|
58
|
+
}
|
|
59
|
+
function isEven(n) {
|
|
60
|
+
return (n % 2 == 0);
|
|
61
|
+
}
|
|
62
|
+
// ################################################################
|
|
37
63
|
|
|
38
64
|
// 22/07/2021 Main tab
|
|
39
65
|
$("#tabsMain").tabs({
|
|
@@ -44,28 +70,52 @@
|
|
|
44
70
|
});
|
|
45
71
|
|
|
46
72
|
// Autocomplete with KNX IP Interfaces
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
let aKNXInterfaces = [];
|
|
74
|
+
$.getJSON("knxUltimateDiscoverKNXGateways?" + { _: new Date().getTime() }, (data) => {
|
|
75
|
+
for (let index = 0; index < data.length; index++) {
|
|
76
|
+
const element = data[index];
|
|
77
|
+
const [ip, port, name, address] = element.split(':');
|
|
78
|
+
// Aggiungi l'elemento con descrizione e valore
|
|
79
|
+
aKNXInterfaces.push({
|
|
80
|
+
label: `${name} -> ${ip}:${port} phys addr:${address}`, // Testo visibile nella lista
|
|
81
|
+
value: element // Valore selezionato
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
$("#interfaces-count").text(`${aKNXInterfaces.length} interfaces found.`);
|
|
85
|
+
// Configura l'autocompletamento per il campo di input
|
|
86
|
+
$("#node-config-input-host").autocomplete({
|
|
87
|
+
minLength: 0, // Mostra suggerimenti subito
|
|
88
|
+
source: aKNXInterfaces, // Dati per il completamento
|
|
89
|
+
select: function (event, ui) {
|
|
90
|
+
// Quando l'utente seleziona un elemento, aggiorna il valore del campo
|
|
91
|
+
const [ip, port, name, address] = ui.item.value.split(':');
|
|
92
|
+
$("#node-config-input-host").val(ip);
|
|
93
|
+
$("#node-config-input-port").val(port);
|
|
94
|
+
$("#node-config-input-name").val(name);
|
|
95
|
+
$("#node-config-input-physAddr").val(address.split(".")[0] + '.' + address.split(".")[1] + '.' + Math.floor(Math.random() * 256));
|
|
96
|
+
blinkBackgroundArray(["#node-config-input-host", "#node-config-input-port", "#node-config-input-name", "#node-config-input-physAddr"]);
|
|
97
|
+
return false; // Evita il comportamento predefinito del browser
|
|
98
|
+
},
|
|
99
|
+
focus: function (event, ui) {
|
|
100
|
+
// Mantieni il valore corrente durante il focus, ma non cambiare il valore effettivo
|
|
101
|
+
$("#node-config-input-host").val(ui.item.value.split(":"[0]));
|
|
102
|
+
return false; // Evita di aggiornare il campo con il valore selezionato
|
|
103
|
+
}
|
|
104
|
+
}).on("focus", function () {
|
|
105
|
+
// Apri l'autocomplete quando il campo riceve il focus
|
|
106
|
+
$(this).autocomplete("search", "");
|
|
107
|
+
}).on("click", function () {
|
|
108
|
+
// Apri l'autocomplete quando il campo riceve il focus
|
|
109
|
+
$(this).autocomplete("search", "");
|
|
110
|
+
}).autocomplete("instance")._renderItem = function (ul, item) {
|
|
111
|
+
// Personalizza l'aspetto degli elementi della lista
|
|
112
|
+
const [ip, port, name, address] = item.value.split(':');
|
|
113
|
+
const color = (ip === "224.0.23.12") ? "gray" : "green"; // Condizione
|
|
114
|
+
return $("<li>")
|
|
115
|
+
.append(`<div style="color: ${color};"><b>${ip}:${port}</b> -> ${name} - Address:${address}</div>`) // Mostra la descrizione completa
|
|
116
|
+
.appendTo(ul);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
69
119
|
|
|
70
120
|
|
|
71
121
|
$("#node-config-input-KNXEthInterface").append($("<option></option>")
|
|
@@ -220,9 +270,9 @@
|
|
|
220
270
|
<input type="text" id="node-config-input-name" style="width: 200px">
|
|
221
271
|
</div>
|
|
222
272
|
<div class="form-row">
|
|
223
|
-
<label for="node-config-input-host" style="width: 200px">
|
|
224
|
-
<
|
|
225
|
-
|
|
273
|
+
<label for="node-config-input-host" style="width: 200px"><i class="fa fa-server"></i> IP/Hostname</label>
|
|
274
|
+
<input type="text" id="node-config-input-host" style="width: 200px"><br/>
|
|
275
|
+
<span id="interfaces-count" style="font-size: 12px; color:#377e00 ; margin-top: 2px;"></span>
|
|
226
276
|
</div>
|
|
227
277
|
|
|
228
278
|
<!-- KNX Secure / Unsecure tabbed selector-->
|
|
@@ -13,7 +13,7 @@ const dptlib = require('knxultimate').dptlib;
|
|
|
13
13
|
const loggerClass = require('./utils/sysLogger')
|
|
14
14
|
// const { Server } = require('http')
|
|
15
15
|
const payloadRounder = require("./utils/payloadManipulation");
|
|
16
|
-
|
|
16
|
+
const utils = require('./utils/utils');
|
|
17
17
|
|
|
18
18
|
// DATAPONT MANIPULATION HELPERS
|
|
19
19
|
// ####################
|
|
@@ -119,6 +119,9 @@ module.exports = (RED) => {
|
|
|
119
119
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("IP Protocol AUTO SET to " + node.hostProtocol + ", based on IP " + node.host);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
// Gather infos about all interfaces on the lan and provides a static variable utils.aDiscoveredknxGateways
|
|
123
|
+
utils.DiscoverKNXGateways()
|
|
124
|
+
|
|
122
125
|
node.setAllClientsStatus = (_status, _color, _text) => {
|
|
123
126
|
node.nodeClients.forEach((oClient) => {
|
|
124
127
|
try {
|
|
@@ -525,7 +528,8 @@ module.exports = (RED) => {
|
|
|
525
528
|
isSecureKNXEnabled: node.knxSecureSelected,
|
|
526
529
|
jKNXSecureKeyring: node.jKNXSecureKeyring,
|
|
527
530
|
localIPAddress: "", // Riempito da KNXEngine
|
|
528
|
-
KNXQueueSendIntervalMilliseconds: Number(node.delaybetweentelegrams)
|
|
531
|
+
KNXQueueSendIntervalMilliseconds: Number(node.delaybetweentelegrams),
|
|
532
|
+
connectionKeepAliveTimeout: 30 // Every 30 seconds, send a connectionstatus_request
|
|
529
533
|
};
|
|
530
534
|
// 11/07/2022 Test if the IP is a valid one or is a DNS Name
|
|
531
535
|
switch (net.isIP(node.host)) {
|
|
@@ -647,11 +651,7 @@ module.exports = (RED) => {
|
|
|
647
651
|
node.Disconnect("Disconnected by error " + (err.message === undefined ? err : err.message), "red");
|
|
648
652
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("Disconnected by: " + (err.message === undefined ? err : err.message));
|
|
649
653
|
});
|
|
650
|
-
|
|
651
|
-
// node.knxConnection.on(knx.KNXClientEvents.discover, info => {
|
|
652
|
-
// const [ip, port] = info.split(":");
|
|
653
|
-
// discoverCB(ip, port);
|
|
654
|
-
// });
|
|
654
|
+
|
|
655
655
|
node.knxConnection.on(knx.KNXClientEvents.disconnected, (info) => {
|
|
656
656
|
if (node.linkStatus !== "disconnected") {
|
|
657
657
|
node.linkStatus = "disconnected";
|
|
@@ -1838,7 +1838,7 @@ module.exports = (RED) => {
|
|
|
1838
1838
|
);
|
|
1839
1839
|
// node.initKNXConnection();
|
|
1840
1840
|
}
|
|
1841
|
-
},
|
|
1841
|
+
}, 30000);
|
|
1842
1842
|
|
|
1843
1843
|
node.Disconnect = async (_sNodeStatus = "", _sColor = "grey") => {
|
|
1844
1844
|
if (node.linkStatus === "disconnected") {
|
package/nodes/utils/hueEngine.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const { EventEmitter } = require("events");
|
|
3
3
|
const EventSource = require("eventsource");
|
|
4
4
|
const http = require("./http");
|
|
5
|
-
const
|
|
5
|
+
const { setTimeout: pleaseWait } = require('timers/promises');
|
|
6
6
|
//const { forEach } = require("lodash");
|
|
7
7
|
// Configura il rate limiter
|
|
8
8
|
//const limiter = new RateLimiter({ tokensPerInterval: 1, interval: 150 }); // HUE telegram interval
|
package/nodes/utils/utils.js
CHANGED
|
@@ -58,4 +58,31 @@ module.exports.fetchFromObject = function fetchFromObject(
|
|
|
58
58
|
const DEFAULTTRANSLATIONINPUT =
|
|
59
59
|
"on:true\noff:false\nactive:true\ninactive:false\nopen:true\nclosed:false\nclose:false\n1:true\n0:false\ntrue:true\nfalse:false\nhome:true\nnot_home:false\nnormal:false\nviolated:true";
|
|
60
60
|
|
|
61
|
+
// 14/08/2019 Endpoint for retrieving the ethernet interfaces
|
|
61
62
|
|
|
63
|
+
module.exports.DiscoverKNXGateways = async function DiscoverKNXGateways() {
|
|
64
|
+
if (bDiscoverKNXGatewaysRunning) return;
|
|
65
|
+
bDiscoverKNXGatewaysRunning = true;
|
|
66
|
+
const KNXClient = require('knxultimate');
|
|
67
|
+
try {
|
|
68
|
+
if (this.aDiscoveredknxGateways === undefined) {
|
|
69
|
+
this.aDiscoveredknxGateways = await KNXClient.KNXClient.discover(2000);
|
|
70
|
+
this.aDiscoveredknxGateways.push('224.0.23.12:3671:Multicast Address:15.15.199')
|
|
71
|
+
bDiscoverKNXGatewaysRunning = false;
|
|
72
|
+
return this.aDiscoveredknxGateways;
|
|
73
|
+
} else {
|
|
74
|
+
bDiscoverKNXGatewaysRunning = false;
|
|
75
|
+
return this.aDiscoveredknxGateways;
|
|
76
|
+
}
|
|
77
|
+
} catch (error) { bDiscoverKNXGatewaysRunning = false; this.aDiscoveredknxGateways = []; return this.aDiscoveredknxGateways; }
|
|
78
|
+
}
|
|
79
|
+
let bDiscoverKNXGatewaysRunning = false;
|
|
80
|
+
module.exports.aDiscoveredknxGateways;
|
|
81
|
+
|
|
82
|
+
module.exports.getDiscoveredknxGateways = function () {
|
|
83
|
+
return module.exports.aDiscoveredknxGateways;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
module.exports.setDiscoveredknxGateways = function (value) {
|
|
87
|
+
module.exports.aDiscoveredknxGateways = value;
|
|
88
|
+
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=16.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "3.3.
|
|
6
|
+
"version": "3.3.3",
|
|
7
7
|
"description": "Control your KNX 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",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"dns-sync": "0.2.1",
|
|
12
12
|
"eventsource": "2.0.2",
|
|
13
13
|
"js-yaml": "4.1.0",
|
|
14
|
-
"knxultimate": "4.
|
|
14
|
+
"knxultimate": "4.1.0-beta.1",
|
|
15
15
|
"lodash": "4.17.21",
|
|
16
16
|
"node-color-log": "12.0.1",
|
|
17
17
|
"mkdirp": "3.0.1",
|