node-red-contrib-knx-ultimate 2.2.10 → 2.2.12

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,7 +6,7 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
- <b>Version 2.2.10</b> - November 2023<br/>
9
+ <b>Version 2.2.12</b> - November 2023<br/>
10
10
  <p>
11
11
  - NEW: Hue Light: you can now enable the input/output PINs and send/receive commands to/from the light, via the msg flow, like msg.on={"on":true}. The option is "Node Input/Output PINs".<br/>
12
12
  - NEW: Hue Scene: you can now enable the input/output PINs and send/receive commands to/from the light, via the msg flow. The option is "Node Input/Output PINs".<br/>
@@ -55,27 +55,46 @@ module.exports = (RED) => {
55
55
  const node = this;
56
56
  node.host = config.host;
57
57
  node.nodeClients = []; // Stores the registered clients
58
- node.nodeClientsAwaitingInit = []; // Stores the nodes client to be initialized
59
58
  node.loglevel = config.loglevel !== undefined ? config.loglevel : "error"; // 18/02/2020 Loglevel default error
60
59
  node.sysLogger = null;
61
60
  node.hueAllResources = undefined;
61
+ node.timerHUEConfigCheckState = null; // Timer that check the connection to the hue bridge every xx seconds
62
+ node.linkStatus = "disconnected";
62
63
  try {
63
64
  node.sysLogger = loggerEngine.get({ loglevel: node.loglevel }); // New logger to adhere to the loglevel selected in the config-window
64
65
  } catch (error) {
65
66
  /* empty */
66
67
  }
67
-
68
68
  node.name = config.name === undefined || config.name === "" ? node.host : config.name;
69
69
 
70
- // Init HUE Utility
71
- node.hueManager = new HueClass(node.host, node.credentials.username, node.credentials.clientkey, config.bridgeid, node.sysLogger);
70
+ // Call the connect function of all hue-config nodes.
71
+ // function callinitHUEConnectionOfAllHUEServers() {
72
+ // RED.nodes.eachNode((_node) => {
73
+ // if (_node.type === 'hue-config') {
74
+ // try {
75
+ // RED.nodes.getNode(_node.id).initHUEConnection();
76
+ // } catch (error) {
77
+ // if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("callinitHUEConnectionOfAllHUEServers: Node " + _node.name + " " + error.message);
78
+ // }
79
+ // }
80
+ // });
81
+ // }
72
82
 
73
83
  // Connect to Bridge and get the resources
74
- node.ConnectToHueBridge = async () => {
75
- await node.hueManager.Connect();
84
+ node.initHUEConnection = async () => {
85
+ try {
86
+ if (node.hueManager !== undefined) node.hueManager.close();
87
+ } catch (error) { }
88
+ try {
89
+ if (node.hueManager !== undefined) node.hueManager.removeAllListeners();
90
+ } catch (error) { }
76
91
  // Handle events
77
92
  try {
78
- node.hueManager.removeAllListeners();
93
+ try {
94
+ // Init HUE Utility
95
+ node.hueManager = new HueClass(node.host, node.credentials.username, node.credentials.clientkey, config.bridgeid, node.sysLogger);
96
+ } catch (error) { }
97
+ await node.hueManager.Connect();
79
98
  } catch (error) {
80
99
  /* empty */
81
100
  }
@@ -91,50 +110,58 @@ module.exports = (RED) => {
91
110
  });
92
111
  // Connected
93
112
  node.hueManager.on("connected", () => {
94
- setTimeout(() => {
95
- (async () => {
96
- try {
97
- await node.loadResourcesFromHUEBridge(); // Then, you can use node.getResources, that works locally and doesn't query the HUE Bridge.
98
- } catch (error) {
99
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("hue-Config node.hueManager.on('connected' " + error.message);
100
- }
101
- })();
102
- }, 10000);
113
+ node.linkStatus = "connected";
114
+ // Start the timer to do initial read.
115
+ if (node.timerDoInitialRead !== null) clearTimeout(node.timerDoInitialRead);
116
+ node.timerDoInitialRead = setTimeout(() => {
117
+ node.loadResourcesFromHUEBridge();
118
+ }, 6000); // 17/02/2020 Do initial read of all nodes requesting initial read
103
119
  });
104
120
  };
105
121
 
122
+ node.startWatchdogTimer = () => {
123
+ node.timerHUEConfigCheckState = setTimeout(() => {
124
+ (async () => {
125
+ if (node.linkStatus === "disconnected") {
126
+ await node.initHUEConnection();
127
+ } else {
128
+ // Check wether the hue connection is still alive
129
+ const ret = await node.hueManager.isConnected();
130
+ if (!ret) node.linkStatus = "disconnected";
131
+ }
132
+ node.startWatchdogTimer();
133
+ })();
134
+ }, 10000);
135
+ };
136
+ node.startWatchdogTimer();
137
+
106
138
  // Query the HUE Bridge to return the resources
107
139
  node.loadResourcesFromHUEBridge = () => {
108
140
  (async () => {
109
141
  // °°°°°° Load ALL resources
110
142
  try {
111
143
  node.hueAllResources = await node.hueManager.hueApiV2.get("/resource");
112
- node.hueAllRooms = node.hueAllResources.filter((a) => a.type === "room");
113
- // Update all KNX State of the nodes with the new hue device values
114
- if (node.nodeClientsAwaitingInit !== undefined) {
115
- // Because the whole process is async, if the function await node.hueManager.hueApiV2.get("/resource") has not jet been called or is late,
116
- // the node/nodes belonging to this server, has been previously added to the nodeClientsAwaitingInit list.
117
- node.nodeClientsAwaitingInit.forEach((_node) => {
118
- node.nodeClients.push(_node);
144
+ if (node.hueAllResources !== undefined) {
145
+ node.hueAllRooms = node.hueAllResources.filter((a) => a.type === "room");
146
+ // Update all KNX State of the nodes with the new hue device values
147
+ node.nodeClients.forEach((_node) => {
148
+ if (_node.hueDevice !== undefined && node.hueAllResources !== undefined) {
149
+ const oHUEDevice = node.hueAllResources.filter((a) => a.id === _node.hueDevice)[0];
150
+ if (oHUEDevice !== undefined) {
151
+ // Add _Node to the clients array
152
+ _node.setNodeStatusHue({
153
+ fill: "green",
154
+ shape: "ring",
155
+ text: "Ready :-)",
156
+ });
157
+ _node.currentHUEDevice = oHUEDevice;
158
+ if (_node.initializingAtStart === true) _node.handleSendHUE(oHUEDevice);
159
+ }
160
+ }
119
161
  });
120
- node.nodeClientsAwaitingInit = [];
162
+ } else {
163
+ // The config node cannot read the resources. Signalling disconnected
121
164
  }
122
- node.nodeClients.forEach((_node) => {
123
- if (_node.hueDevice !== undefined && node.hueAllResources !== undefined) {
124
- const oHUEDevice = node.hueAllResources.filter((a) => a.id === _node.hueDevice)[0];
125
- if (oHUEDevice !== undefined) {
126
- // Add _Node to the clients array
127
- _node.setNodeStatusHue({
128
- fill: "green",
129
- shape: "ring",
130
- text: "Ready from awaiting list :-)",
131
- });
132
- oHUEDevice.initializingAtStart = true; // Signalling first connection after restart.
133
- _node.currentHUEDevice = oHUEDevice;
134
- _node.handleSendHUE(oHUEDevice);
135
- }
136
- }
137
- });
138
165
  } catch (error) {
139
166
  if (this.sysLogger !== undefined && this.sysLogger !== null) {
140
167
  this.sysLogger.error(`KNXUltimatehueEngine: loadResourcesFromHUEBridge: ${error.message}`);
@@ -275,28 +302,27 @@ module.exports = (RED) => {
275
302
 
276
303
  node.addClient = (_Node) => {
277
304
  // Update the node hue device, as soon as a node register itself to hue-config nodeClients
278
- if (node.hueAllResources !== undefined && node.hueAllResources !== null) {
279
- if (node.nodeClients.filter((x) => x.id === _Node.id).length === 0) { // At first start, due to the async method for retrieving hueAllResources, hueAllResources is still null. The first start is handled in node.hueManager.on("connected")
305
+ if (node.nodeClients.filter((x) => x.id === _Node.id).length === 0) {
306
+ node.nodeClients.push(_Node);
307
+ if (node.hueAllResources !== undefined && node.hueAllResources !== null && _Node.initializingAtStart === true) {
280
308
  const oHUEDevice = node.hueAllResources.filter((a) => a.id === _Node.hueDevice)[0];
281
- oHUEDevice.initializingAtStart = true; // Signalling first connection after restart.
282
- _Node.currentHUEDevice = oHUEDevice;
283
- _Node.handleSendHUE(oHUEDevice);
284
- node.nodeClients.push(_Node);
309
+ if (oHUEDevice !== undefined) {
310
+ _Node.currentHUEDevice = oHUEDevice;
311
+ _Node.handleSendHUE(oHUEDevice);
312
+ // Add _Node to the clients array
313
+ _Node.setNodeStatusHue({
314
+ fill: "yellow",
315
+ shape: "dot",
316
+ text: "Initializing. Please Wait.",
317
+ });
318
+ }
319
+ } else {
320
+ node.linkStatus = "disconnected";
285
321
  // Add _Node to the clients array
286
- _Node.setNodeStatusHue({
287
- fill: "green",
288
- shape: "ring",
289
- text: "Ready",
290
- });
291
- }
292
- } else {
293
- if (node.nodeClientsAwaitingInit.filter((x) => x.id === _Node.id).length === 0) {
294
- // Put the node in the waiting list
295
- node.nodeClientsAwaitingInit.push(_Node);
296
322
  _Node.setNodeStatusHue({
297
323
  fill: "grey",
298
- shape: "dot",
299
- text: "I'm gointo to init awaiting list.",
324
+ shape: "ring",
325
+ text: "Waiting for connection",
300
326
  });
301
327
  }
302
328
  }
@@ -346,14 +372,18 @@ module.exports = (RED) => {
346
372
  // °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
347
373
  const serverNode = RED.nodes.getNode(req.query.nodeID); // Retrieve node.id of the config node.
348
374
  const jRet = serverNode.getResources(req.query.rtype);
349
- res.json(jRet);
375
+ if (jRet !== undefined) {
376
+ res.json(jRet);
377
+ } else {
378
+ res.json({ devices: [{ name: "I'm still connecting...Try in some seconds" }] });
379
+ }
350
380
  // °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
351
381
  } catch (error) {
352
382
  RED.log.error(`Errore KNXUltimateGetResourcesHUE non gestito ${error.message}`);
353
383
  res.json({ devices: error.message });
354
- (async () => {
355
- await node.ConnectToHueBridge();
356
- })();
384
+ // (async () => {
385
+ // await node.initHUEConnection();
386
+ // })();
357
387
  }
358
388
  });
359
389
 
@@ -115,13 +115,9 @@ return msg;`,
115
115
  node.KNXEthInterfaceManuallyInput = typeof config.KNXEthInterfaceManuallyInput === "undefined" ? "" : config.KNXEthInterfaceManuallyInput; // If you manually set the interface name, it will be wrote here
116
116
  node.telegramsQueue = []; // 02/01/2020 Queue containing telegrams
117
117
  node.timerSendTelegramFromQueue = null;
118
- node.delaybetweentelegramsfurtherdelayREAD =
119
- typeof config.delaybetweentelegramsfurtherdelayREAD === "undefined" || Number(config.delaybetweentelegramsfurtherdelayREAD < 1)
120
- ? 1
121
- : Number(config.delaybetweentelegramsfurtherdelayREAD); // 18/05/2020 delay multiplicator only for "read" telegrams.
118
+ node.delaybetweentelegramsfurtherdelayREAD = typeof config.delaybetweentelegramsfurtherdelayREAD === "undefined" || Number(config.delaybetweentelegramsfurtherdelayREAD < 1) ? 1 : Number(config.delaybetweentelegramsfurtherdelayREAD); // 18/05/2020 delay multiplicator only for "read" telegrams.
122
119
  node.delaybetweentelegramsREADCount = 0; // 18/05/2020 delay multiplicator only for "read" telegrams.
123
120
  node.timerDoInitialRead = null; // 17/02/2020 Timer (timeout) to do initial read of all nodes requesting initial read, after all nodes have been registered to the sercer
124
- node.timerCallConnectToHueBridgeOfAllHUEServers = null; // // Timer for the callConnectToHueBridgeOfAllHUEServers function
125
121
  node.stopETSImportIfNoDatapoint = typeof config.stopETSImportIfNoDatapoint === "undefined" ? "stop" : config.stopETSImportIfNoDatapoint; // 09/01/2020 Stop, Import Fake or Skip the import if a group address has unset datapoint
126
122
  node.csv = readCSV(config.csv); // Array from ETS CSV Group Addresses {ga:group address, dpt: datapoint, devicename: full device name with main and subgroups}
127
123
  node.localEchoInTunneling = typeof config.localEchoInTunneling !== "undefined" ? config.localEchoInTunneling : true;
@@ -678,18 +674,7 @@ return msg;`,
678
674
  });
679
675
  } catch (error) { }
680
676
  }
681
- // Call the connect function of all hue-config nodes.
682
- function callConnectToHueBridgeOfAllHUEServers() {
683
- RED.nodes.eachNode((_node) => {
684
- if (_node.type === 'hue-config') {
685
- try {
686
- RED.nodes.getNode(_node.id).ConnectToHueBridge();
687
- } catch (error) {
688
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("callConnectToHueBridgeOfAllHUEServers: Node " + _node.name + " " + error.message);
689
- }
690
- }
691
- });
692
- }
677
+
693
678
  // 01/02/2020 Dinamic change of the KNX Gateway IP, Port and Physical Address
694
679
  // This new thing has been requested by proServ RealKNX staff.
695
680
  node.setGatewayConfig = (
@@ -947,9 +932,7 @@ return msg;`,
947
932
  if (node.timerDoInitialRead !== null) clearTimeout(node.timerDoInitialRead);
948
933
  node.timerDoInitialRead = setTimeout(() => {
949
934
  DoInitialReadFromKNXBusOrFile();
950
- callConnectToHueBridgeOfAllHUEServers();
951
935
  }, 6000); // 17/02/2020 Do initial read of all nodes requesting initial read
952
- //node.timerCallConnectToHueBridgeOfAllHUEServers = setTimeout(callConnectToHueBridgeOfAllHUEServers, 6000); // connects all hue-config nodes to the HUE Bridge.
953
936
  const t = setTimeout(() => {
954
937
  // 21/03/2022 fixed possible memory leak. Previously was setTimeout without "let t = ".
955
938
  node.setAllClientsStatus("Connected.", "green", "On duty.");
@@ -23,7 +23,7 @@ module.exports = function (RED) {
23
23
  node.formatnegativevalue = 'leave';
24
24
  node.formatdecimalsvalue = 2;
25
25
  node.hueDevice = config.hueDevice;
26
-
26
+ node.initializingAtStart = !((config.readStatusAtStartup === undefined || config.readStatusAtStartup === "no"));
27
27
  // Used to call the status update from the config node.
28
28
  node.setNodeStatus = ({
29
29
  fill, shape, text, payload,
@@ -49,7 +49,7 @@ module.exports = function (RED) {
49
49
  if (_event.id === config.hueDevice) {
50
50
 
51
51
  // IMPORTANT: exit if no event presen.
52
- if (_event.initializingAtStart === true && (config.readStatusAtStartup === undefined || config.readStatusAtStartup === "no")) return;
52
+ if (!node.initializingAtStart) return;
53
53
  if (!_event.hasOwnProperty("power_state") || _event.power_state.battery_level === undefined) return;
54
54
 
55
55
  const knxMsgPayload = {};
@@ -27,6 +27,7 @@ module.exports = function (RED) {
27
27
  node.short_releaseValue = false;
28
28
  node.isTimerDimStopRunning = false;
29
29
  node.hueDevice = config.hueDevice;
30
+ node.initializingAtStart = false;
30
31
 
31
32
  // Used to call the status update from the config node.
32
33
  node.setNodeStatus = ({
@@ -78,7 +79,7 @@ module.exports = function (RED) {
78
79
  if (_event.id === config.hueDevice) {
79
80
 
80
81
  // IMPORTANT: exit if no button last_event present.
81
- if (_event.initializingAtStart === true) return;
82
+ if (!node.initializingAtStart) return;
82
83
  if (!_event.hasOwnProperty("button") || _event.button.last_event === undefined) return;
83
84
 
84
85
  const knxMsgPayload = {};