node-red-contrib-knx-ultimate 3.3.2 → 3.3.4

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 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/>
@@ -61,6 +61,14 @@ module.exports = (RED) => {
61
61
  function commonFunctions() {
62
62
  var node = this;
63
63
 
64
+ // Gather infos about all interfaces on the lan and provides a static variable utils.aDiscoveredknxGateways
65
+ try {
66
+ require('./utils/utils').DiscoverKNXGateways()
67
+ } catch (error) {
68
+
69
+ }
70
+
71
+
64
72
 
65
73
  // 11/03/2020 Delete scene saved file, from html
66
74
  RED.httpAdmin.get('/knxultimateCheckHueConnected', (req, res) => {
@@ -310,29 +318,7 @@ module.exports = (RED) => {
310
318
 
311
319
  // 14/08/2019 Endpoint for retrieving the ethernet interfaces
312
320
  RED.httpAdmin.get("/knxUltimateDiscoverKNXGateways", RED.auth.needsPermission("knxUltimate-config.read"), async function (req, res) {
313
- try {
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
- }
321
+ res.json(require("./utils/utils").aDiscoveredknxGateways);
336
322
  });
337
323
 
338
324
  // 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
- // let aKNXInterfaces = [];
48
- // $.getJSON("knxUltimateDiscoverKNXGateways?" + { _: new Date().getTime() }, (data) => {
49
- // for (let index = 0; index < data.length; index++) {
50
- // const element = data[index];
51
- // aKNXInterfaces.push({
52
- // name: value.ip + " # " + value.name + " " + value.physAddr,
53
- // value: value.ip,
54
- // });
55
- // }
56
- // alert("IK")
57
- // alert(aKNXInterfaces[0].name)
58
- // $("#node-config-input-host").autocomplete({
59
- // minLength: 0,
60
- // source: aKNXInterfaces,
61
- // select: function (event, ui) {
62
- // $("#node-config-input-host").val(ui.item.value);
63
- // },
64
- // focus: function (event, ui) {
65
- // $(this).autocomplete('search', $(this).val() + 'exactmatch');
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
- <i class="fa fa-server"></i> IP/Hostname</label>
225
- <input type="text" id="node-config-input-host" style="width: 200px">
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,7 @@ 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
+
122
123
  node.setAllClientsStatus = (_status, _color, _text) => {
123
124
  node.nodeClients.forEach((oClient) => {
124
125
  try {
@@ -525,7 +526,8 @@ module.exports = (RED) => {
525
526
  isSecureKNXEnabled: node.knxSecureSelected,
526
527
  jKNXSecureKeyring: node.jKNXSecureKeyring,
527
528
  localIPAddress: "", // Riempito da KNXEngine
528
- KNXQueueSendIntervalMilliseconds: Number(node.delaybetweentelegrams)
529
+ KNXQueueSendIntervalMilliseconds: Number(node.delaybetweentelegrams),
530
+ connectionKeepAliveTimeout: 30 // Every 30 seconds, send a connectionstatus_request
529
531
  };
530
532
  // 11/07/2022 Test if the IP is a valid one or is a DNS Name
531
533
  switch (net.isIP(node.host)) {
@@ -647,11 +649,7 @@ module.exports = (RED) => {
647
649
  node.Disconnect("Disconnected by error " + (err.message === undefined ? err : err.message), "red");
648
650
  if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("Disconnected by: " + (err.message === undefined ? err : err.message));
649
651
  });
650
- // Call discoverCB when a knx gateway has been discovered.
651
- // node.knxConnection.on(knx.KNXClientEvents.discover, info => {
652
- // const [ip, port] = info.split(":");
653
- // discoverCB(ip, port);
654
- // });
652
+
655
653
  node.knxConnection.on(knx.KNXClientEvents.disconnected, (info) => {
656
654
  if (node.linkStatus !== "disconnected") {
657
655
  node.linkStatus = "disconnected";
@@ -1838,7 +1836,7 @@ module.exports = (RED) => {
1838
1836
  );
1839
1837
  // node.initKNXConnection();
1840
1838
  }
1841
- }, 5000);
1839
+ }, 30000);
1842
1840
 
1843
1841
  node.Disconnect = async (_sNodeStatus = "", _sColor = "grey") => {
1844
1842
  if (node.linkStatus === "disconnected") {
@@ -2,7 +2,7 @@
2
2
  const { EventEmitter } = require("events");
3
3
  const EventSource = require("eventsource");
4
4
  const http = require("./http");
5
- const pleaseWait = t => new Promise((resolve, reject) => setTimeout(resolve, t))
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
@@ -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.2",
6
+ "version": "3.3.4",
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.0.0-beta.6",
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",