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 +1 -1
- package/nodes/hue-config.js +92 -62
- package/nodes/knxUltimate-config.js +2 -19
- package/nodes/knxUltimateHueBattery.js +2 -2
- package/nodes/knxUltimateHueButton.js +2 -1
- package/nodes/knxUltimateHueLight.html +376 -382
- package/nodes/knxUltimateHueLight.js +3 -4
- package/nodes/knxUltimateHueLightSensor.js +2 -1
- package/nodes/knxUltimateHueMotion.js +2 -1
- package/nodes/knxUltimateHueScene.js +2 -5
- package/nodes/knxUltimateHueTapDial.js +2 -1
- package/nodes/utils/hueEngine.js +23 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
-
<b>Version 2.2.
|
|
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/>
|
package/nodes/hue-config.js
CHANGED
|
@@ -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
|
-
//
|
|
71
|
-
|
|
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.
|
|
75
|
-
|
|
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
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
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.
|
|
279
|
-
|
|
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
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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: "
|
|
299
|
-
text: "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
82
|
+
if (!node.initializingAtStart) return;
|
|
82
83
|
if (!_event.hasOwnProperty("button") || _event.button.last_event === undefined) return;
|
|
83
84
|
|
|
84
85
|
const knxMsgPayload = {};
|