node-red-contrib-knx-ultimate 2.2.3 → 2.2.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 +3 -0
- package/nodes/hue-config.js +30 -17
- package/nodes/knxUltimateHueBattery.js +1 -1
- package/nodes/knxUltimateHueButton.js +1 -1
- package/nodes/knxUltimateHueLight.html +24 -4
- package/nodes/knxUltimateHueLight.js +26 -27
- package/nodes/knxUltimateHueLightSensor.js +1 -1
- package/nodes/knxUltimateHueMotion.js +4 -4
- package/nodes/knxUltimateHueScene.js +1 -1
- package/nodes/knxUltimateHueTapDial.js +1 -1
- package/nodes/knxUltimateHueTemperatureSensor.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
<b>Version 2.2.4</b> - October 2023<br/>
|
|
10
|
+
- HUE Light: fixed some status hiccups and better handling of async hue bridge functions.<br/>
|
|
11
|
+
</p>
|
|
9
12
|
<b>Version 2.2.3</b> - October 2023<br/>
|
|
10
13
|
- HUE Light: Again, rewrite of the DIM function to get rid of the dimming_delta.<br/>
|
|
11
14
|
</p>
|
package/nodes/hue-config.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-lonely-if */
|
|
1
2
|
/* eslint-disable no-param-reassign */
|
|
2
3
|
/* eslint-disable no-inner-declarations */
|
|
3
4
|
/* eslint-disable max-len */
|
|
@@ -54,6 +55,7 @@ module.exports = (RED) => {
|
|
|
54
55
|
const node = this;
|
|
55
56
|
node.host = config.host;
|
|
56
57
|
node.nodeClients = []; // Stores the registered clients
|
|
58
|
+
node.nodeClientsAwaitingInit = []; // Stores the nodes client to be initialized
|
|
57
59
|
node.loglevel = config.loglevel !== undefined ? config.loglevel : "error"; // 18/02/2020 Loglevel default error
|
|
58
60
|
node.sysLogger = null;
|
|
59
61
|
node.hueAllResources = null;
|
|
@@ -108,18 +110,20 @@ module.exports = (RED) => {
|
|
|
108
110
|
node.hueAllResources = await node.hueManager.hueApiV2.get("/resource");
|
|
109
111
|
node.hueAllRooms = node.hueAllResources.filter((a) => a.type === "room");
|
|
110
112
|
// Update all KNX State of the nodes with the new hue device values
|
|
113
|
+
if (node.nodeClientsAwaitingInit !== undefined) {
|
|
114
|
+
// Because the whole process is async, if the function await node.hueManager.hueApiV2.get("/resource") has not jet been called or is late,
|
|
115
|
+
// the node/nodes belonging to this server, has been previously added to the nodeClientsAwaitingInit list.
|
|
116
|
+
node.nodeClientsAwaitingInit.forEach((nodeClient) => {
|
|
117
|
+
node.nodeClients.push(nodeClient);
|
|
118
|
+
});
|
|
119
|
+
node.nodeClientsAwaitingInit = [];
|
|
120
|
+
}
|
|
111
121
|
node.nodeClients.forEach((nodeClient) => {
|
|
112
122
|
if (nodeClient.hueDevice !== undefined) {
|
|
113
123
|
const oHUEDevice = node.hueAllResources.filter((a) => a.id === nodeClient.hueDevice)[0];
|
|
114
124
|
if (oHUEDevice !== undefined) {
|
|
115
125
|
nodeClient.currentHUEDevice = oHUEDevice;
|
|
116
126
|
nodeClient.handleSendHUE(oHUEDevice);
|
|
117
|
-
// for (const [key, value] of Object.entries(oHUEDevice)) {
|
|
118
|
-
// // Update KNX State
|
|
119
|
-
// const oProperty = { id: oHUEDevice.id };
|
|
120
|
-
// oProperty[key] = value;
|
|
121
|
-
// nodeClient.handleSendHUE(oProperty);
|
|
122
|
-
// }
|
|
123
127
|
}
|
|
124
128
|
}
|
|
125
129
|
});
|
|
@@ -262,20 +266,29 @@ module.exports = (RED) => {
|
|
|
262
266
|
};
|
|
263
267
|
|
|
264
268
|
node.addClient = (_Node) => {
|
|
265
|
-
//
|
|
266
|
-
if (node.
|
|
267
|
-
|
|
268
|
-
_Node.setNodeStatusHue({
|
|
269
|
-
fill: "grey",
|
|
270
|
-
shape: "ring",
|
|
271
|
-
text: "Hue initialized.",
|
|
272
|
-
});
|
|
273
|
-
node.nodeClients.push(_Node);
|
|
274
|
-
// Update the node hue device, as soon as a node register itself to hue-config nodeClients
|
|
275
|
-
if (node.hueAllResources !== null) { // 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")
|
|
269
|
+
// Update the node hue device, as soon as a node register itself to hue-config nodeClients
|
|
270
|
+
if (node.hueAllResources !== null) {
|
|
271
|
+
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")
|
|
276
272
|
const oHUEDevice = node.hueAllResources.filter((a) => a.id === _Node.hueDevice)[0];
|
|
277
273
|
_Node.currentHUEDevice = oHUEDevice;
|
|
278
274
|
if (oHUEDevice !== undefined) _Node.handleSendHUE(oHUEDevice);
|
|
275
|
+
node.nodeClients.push(_Node);
|
|
276
|
+
// Add _Node to the clients array
|
|
277
|
+
_Node.setNodeStatusHue({
|
|
278
|
+
fill: "green",
|
|
279
|
+
shape: "ring",
|
|
280
|
+
text: "Ready",
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
if (node.nodeClientsAwaitingInit.filter((x) => x.id === _Node.id).length === 0) {
|
|
285
|
+
// Put the node in the waiting list
|
|
286
|
+
node.nodeClientsAwaitingInit.push(_Node);
|
|
287
|
+
_Node.setNodeStatusHue({
|
|
288
|
+
fill: "grey",
|
|
289
|
+
shape: "dot",
|
|
290
|
+
text: "Awaiting HUE Resources",
|
|
291
|
+
});
|
|
279
292
|
}
|
|
280
293
|
}
|
|
281
294
|
};
|
|
@@ -33,7 +33,7 @@ module.exports = function (RED) {
|
|
|
33
33
|
node.setNodeStatusHue = ({
|
|
34
34
|
fill, shape, text, payload,
|
|
35
35
|
}) => {
|
|
36
|
-
if (payload === undefined)
|
|
36
|
+
if (payload === undefined) payload = '';
|
|
37
37
|
const dDate = new Date();
|
|
38
38
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
39
39
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
@@ -37,7 +37,7 @@ module.exports = function (RED) {
|
|
|
37
37
|
node.setNodeStatusHue = ({
|
|
38
38
|
fill, shape, text, payload,
|
|
39
39
|
}) => {
|
|
40
|
-
if (payload === undefined)
|
|
40
|
+
if (payload === undefined) payload = '';
|
|
41
41
|
const dDate = new Date();
|
|
42
42
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
43
43
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
|
+
RED.events.on('nodes:add', function (node) {
|
|
3
|
+
if (node.type === 'uibuilder') {
|
|
4
|
+
// Keep a list of uib nodes in the editor
|
|
5
|
+
// may be different to the deployed list
|
|
6
|
+
editorInstances[node.id] = node.url
|
|
7
|
+
// -- IF uibuilderInstances <> editorInstances THEN there are undeployed instances. --
|
|
8
|
+
}
|
|
9
|
+
})
|
|
10
|
+
RED.events.on('nodes:change', function (node) {
|
|
11
|
+
if (node.type === 'uibuilder') {
|
|
12
|
+
mylog('nodes:change:', node)
|
|
13
|
+
editorInstances[node.id] = node.url
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
RED.events.on('nodes:remove', function (node) {
|
|
17
|
+
if (node.type === 'uibuilder') {
|
|
18
|
+
mylog('>> nodes:remove >>', node)
|
|
19
|
+
delete editorInstances[node.id]
|
|
20
|
+
}
|
|
21
|
+
})
|
|
2
22
|
RED.nodes.registerType("knxUltimateHueLight", {
|
|
3
23
|
category: "KNX Ultimate",
|
|
4
24
|
color: "#C0C7E9",
|
|
@@ -486,15 +506,15 @@
|
|
|
486
506
|
$("#getColorAtSwitchOnNightTimeButton").text("Get current");
|
|
487
507
|
});
|
|
488
508
|
});
|
|
489
|
-
|
|
509
|
+
|
|
490
510
|
// Fill options for minDimLevel and maxDimLevel
|
|
491
511
|
for (let index = 0; index <= 90; index++) {
|
|
492
|
-
if (index === 0){
|
|
512
|
+
if (index === 0) {
|
|
493
513
|
$("#node-input-minDimLevelLight").append($("<option>").val(index).text(index.toString() + "% (Switch Off)"));
|
|
494
|
-
}else{
|
|
514
|
+
} else {
|
|
495
515
|
$("#node-input-minDimLevelLight").append($("<option>").val(index).text(index.toString() + "%"));
|
|
496
516
|
}
|
|
497
|
-
|
|
517
|
+
|
|
498
518
|
}
|
|
499
519
|
$("#node-input-minDimLevelLight").val(node.minDimLevelLight);
|
|
500
520
|
for (let index = 100; index >= 10; index--) {
|
|
@@ -41,22 +41,13 @@ module.exports = function (RED) {
|
|
|
41
41
|
fill, shape, text, payload,
|
|
42
42
|
}) => { };
|
|
43
43
|
// Used to call the status update from the HUE config node.
|
|
44
|
-
node.setNodeStatusHue = ({
|
|
45
|
-
|
|
46
|
-
}) => {
|
|
47
|
-
if (payload === undefined) return;
|
|
44
|
+
node.setNodeStatusHue = ({ fill, shape, text, payload }) => {
|
|
45
|
+
if (payload === undefined) payload = '';
|
|
48
46
|
const dDate = new Date();
|
|
49
47
|
payload = typeof payload === "object" ? JSON.stringify(payload) : payload.toString();
|
|
50
48
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
51
49
|
};
|
|
52
50
|
|
|
53
|
-
node.setNodeStatusHue({
|
|
54
|
-
fill: "grey",
|
|
55
|
-
shape: "ring",
|
|
56
|
-
text: "Connecting to the Bridge...",
|
|
57
|
-
payload: "",
|
|
58
|
-
});
|
|
59
|
-
|
|
60
51
|
function getRandomIntInclusive(min, max) {
|
|
61
52
|
min = Math.ceil(min);
|
|
62
53
|
max = Math.floor(max);
|
|
@@ -67,9 +58,9 @@ module.exports = function (RED) {
|
|
|
67
58
|
node.handleSend = (msg) => {
|
|
68
59
|
if (node.currentHUEDevice === undefined) {
|
|
69
60
|
node.setNodeStatusHue({
|
|
70
|
-
fill: "
|
|
61
|
+
fill: "grey",
|
|
71
62
|
shape: "ring",
|
|
72
|
-
text: "
|
|
63
|
+
text: "Currently not ready.",
|
|
73
64
|
payload: "",
|
|
74
65
|
});
|
|
75
66
|
return;
|
|
@@ -448,26 +439,32 @@ module.exports = function (RED) {
|
|
|
448
439
|
node.currentHUEDevice.on.on = _event.on.on;
|
|
449
440
|
}
|
|
450
441
|
if (_event.hasOwnProperty("color")) {
|
|
451
|
-
|
|
452
|
-
|
|
442
|
+
if (_event.type !== 'grouped_light') {
|
|
443
|
+
// In grouped lights, there is group color, but each light has it's own color.
|
|
444
|
+
node.updateKNXLightColorState(_event.color);
|
|
445
|
+
node.currentHUEDevice.color = _event.color;
|
|
446
|
+
}
|
|
453
447
|
}
|
|
454
448
|
if (_event.hasOwnProperty("dimming") && _event.dimming.brightness !== undefined) {
|
|
455
449
|
// Every once on a time, the light transmit the brightness value of 0.39.
|
|
456
450
|
// To avoid wrongly turn light state on, exit
|
|
457
451
|
if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
|
|
458
|
-
if (node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0)
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
452
|
+
if (node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0) {
|
|
453
|
+
// Do nothing, because the light is off and the dimming also is 0
|
|
454
|
+
} else {
|
|
455
|
+
if (node.currentHUEDevice.on.on === false) node.updateKNXLightState(_event.dimming.brightness > 0);
|
|
456
|
+
node.updateKNXBrightnessState(_event.dimming.brightness);
|
|
457
|
+
// If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
|
|
458
|
+
if (_event.dimming.brightness === 0) {
|
|
459
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
460
|
+
node.hueDevice,
|
|
461
|
+
{ on: { on: false } },
|
|
462
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight",
|
|
463
|
+
);
|
|
464
|
+
node.currentHUEDevice.on.on = false;
|
|
465
|
+
}
|
|
466
|
+
node.currentHUEDevice.dimming.brightness = _event.dimming.brightness;
|
|
469
467
|
}
|
|
470
|
-
node.currentHUEDevice.dimming.brightness = _event.dimming.brightness;
|
|
471
468
|
}
|
|
472
469
|
if (_event.hasOwnProperty("color_temperature") && _event.color_temperature.mirek !== undefined) {
|
|
473
470
|
node.updateKNXLightHSVState(_event.color_temperature.mirek);
|
|
@@ -615,6 +612,8 @@ module.exports = function (RED) {
|
|
|
615
612
|
}
|
|
616
613
|
};
|
|
617
614
|
|
|
615
|
+
|
|
616
|
+
|
|
618
617
|
// On each deploy, unsubscribe+resubscribe
|
|
619
618
|
if (node.server) {
|
|
620
619
|
node.server.removeClient(node);
|
|
@@ -29,7 +29,7 @@ module.exports = function (RED) {
|
|
|
29
29
|
};
|
|
30
30
|
// Used to call the status update from the HUE config node.
|
|
31
31
|
node.setNodeStatusHue = ({ fill, shape, text, payload }) => {
|
|
32
|
-
if (payload === undefined)
|
|
32
|
+
if (payload === undefined) payload = '';
|
|
33
33
|
const dDate = new Date();
|
|
34
34
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
35
35
|
node.status({ fill, shape, text: text + ' ' + payload + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' });
|
|
@@ -24,17 +24,17 @@ module.exports = function (RED) {
|
|
|
24
24
|
node.formatdecimalsvalue = 2;
|
|
25
25
|
|
|
26
26
|
// Used to call the status update from the config node.
|
|
27
|
-
node.setNodeStatus = ({ fill, shape, text, payload }) => {};
|
|
27
|
+
node.setNodeStatus = ({ fill, shape, text, payload }) => { };
|
|
28
28
|
// Used to call the status update from the HUE config node.
|
|
29
29
|
node.setNodeStatusHue = ({ fill, shape, text, payload }) => {
|
|
30
|
-
if (payload === undefined)
|
|
30
|
+
if (payload === undefined) payload = '';
|
|
31
31
|
const dDate = new Date();
|
|
32
32
|
payload = typeof payload === "object" ? JSON.stringify(payload) : payload.toString();
|
|
33
33
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
// This function is called by the knx-ultimate config node, to output a msg.payload.
|
|
37
|
-
node.handleSend = (msg) => {};
|
|
37
|
+
node.handleSend = (msg) => { };
|
|
38
38
|
|
|
39
39
|
node.handleSendHUE = (_event) => {
|
|
40
40
|
try {
|
|
@@ -91,7 +91,7 @@ module.exports = function (RED) {
|
|
|
91
91
|
node.serverHue.addClient(node);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
node.on("input", (msg) => {});
|
|
94
|
+
node.on("input", (msg) => { });
|
|
95
95
|
|
|
96
96
|
node.on("close", (done) => {
|
|
97
97
|
if (node.server) {
|
|
@@ -31,7 +31,7 @@ module.exports = function (RED) {
|
|
|
31
31
|
};
|
|
32
32
|
// Used to call the status update from the HUE config node.
|
|
33
33
|
node.setNodeStatusHue = ({ fill, shape, text, payload }) => {
|
|
34
|
-
if (payload === undefined)
|
|
34
|
+
if (payload === undefined) payload = '';
|
|
35
35
|
const dDate = new Date();
|
|
36
36
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
37
37
|
node.status({ fill, shape, text: text + ' ' + payload + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' });
|
|
@@ -35,7 +35,7 @@ module.exports = function (RED) {
|
|
|
35
35
|
node.setNodeStatusHue = ({
|
|
36
36
|
fill, shape, text, payload,
|
|
37
37
|
}) => {
|
|
38
|
-
if (payload === undefined)
|
|
38
|
+
if (payload === undefined) payload = '';
|
|
39
39
|
const dDate = new Date();
|
|
40
40
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
41
41
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
@@ -33,7 +33,7 @@ module.exports = function (RED) {
|
|
|
33
33
|
node.setNodeStatusHue = ({
|
|
34
34
|
fill, shape, text, payload,
|
|
35
35
|
}) => {
|
|
36
|
-
if (payload === undefined)
|
|
36
|
+
if (payload === undefined) payload = '';
|
|
37
37
|
const dDate = new Date();
|
|
38
38
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
39
39
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=16.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.2.
|
|
6
|
+
"version": "2.2.4",
|
|
7
7
|
"description": "Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer. Easy to use and highly configurable. With integrated Philips HUE devices control.",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"binary-parser": "2.2.1",
|