node-red-contrib-knx-ultimate 2.4.26 → 2.4.28
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 -14
- package/README.md +2 -5
- package/nodes/hue-config.js +5 -57
- package/nodes/knxUltimateHueLight.js +63 -310
- package/nodes/utils/utils.js +0 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,24 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
-
**Version 2.4.
|
|
10
|
-
-
|
|
11
|
-
- HUE light node: fixed status refresh of kelvin and brightness of a light belonging to a grouped_light.<br/>
|
|
12
|
-
- KNOW ISSUE: HUE light node: grouped_lights: the status group address is updated multiple times, equals to the lights contained in the grouped_light. To avoid repeating the same telegram multiple times, simply enable the RBE filter on the KNX node. <br/>
|
|
13
|
-
|
|
14
|
-
**Version 2.4.25** - Mai 2024<br/>
|
|
15
|
-
- Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
|
|
16
|
-
- HUE light node: fixed status sent to the KNX bus after issuing a read request for grouped_lights.<br/>
|
|
17
|
-
- KNOW ISSUE: HUE light node: grouped_lights: the status group address is updated multiple times, equals to the lights contained in the grouped_light. To avoid repeating the same telegram multiple times, simply enable the RBE filter on the KNX node. <br/>
|
|
18
|
-
|
|
19
|
-
**Version 2.4.24** - Mai 2024<br/>
|
|
20
|
-
- Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
|
|
21
|
-
- HUE light node: fixed kelvin temp status with datapoint 7.600, that sent wrong values to the bus.<br/>
|
|
9
|
+
**Version 2.4.28**
|
|
10
|
+
- temporary reveft to 2.4.23
|
|
22
11
|
|
|
23
12
|
**Version 2.4.23** - Mai 2024<br/>
|
|
24
13
|
- Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
|
|
25
14
|
- HUE Scene node: fixed max scene count to 64.<br/>
|
|
26
|
-
|
|
15
|
+
|
|
27
16
|
**Version 2.4.22** - April 2024<br/>
|
|
28
17
|
- Warning: this version uses the Node-Red plugin system; the Node-Red version must be **equals or major than 3.1.1**<br/>
|
|
29
18
|
- HUE button node: NEW: now you can select the value and the dim direction to be transmitted, when Toggle Status is set to unchecked. Thanks @cybersmart-eu for the suggestion.<br/>
|
package/README.md
CHANGED
|
@@ -50,17 +50,14 @@ msg.payload = {red:255, green:200, blue:30} // Put some colors in our life
|
|
|
50
50
|
|
|
51
51
|
* See <a href="https://github.com/Supergiovane/node-red-contrib-knx-ultimate/blob/master/CHANGELOG.md">here the changelog</a>
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
## SUPPORTED TECHNOLOGIES
|
|
55
|
-
|
|
56
53
|
|Technology|Supported|
|
|
57
54
|
|--|--|
|
|
58
55
|
| KNX Tunnelling |  |
|
|
59
56
|
| KNX Routing |  |
|
|
60
57
|
| KNX Secure Tunnelling |  |
|
|
61
58
|
| KNX Secure Routing |  |
|
|
62
|
-
| KNX 3rd PARTY IOT API
|
|
63
|
-
|
|
59
|
+
| KNX 3rd PARTY IOT API |  |
|
|
60
|
+
|
|
64
61
|
|
|
65
62
|
<br/>
|
|
66
63
|
|
package/nodes/hue-config.js
CHANGED
|
@@ -8,7 +8,6 @@ const cloneDeep = require("lodash/cloneDeep");
|
|
|
8
8
|
const HueClass = require("./utils/hueEngine").classHUE;
|
|
9
9
|
const loggerEngine = require("./utils/sysLogger");
|
|
10
10
|
const hueColorConverter = require("./utils/colorManipulators/hueColorConverter");
|
|
11
|
-
const { AsyncObservable } = require("@project-chip/matter-node.js/util");
|
|
12
11
|
|
|
13
12
|
module.exports = (RED) => {
|
|
14
13
|
function hueConfig(config) {
|
|
@@ -51,9 +50,6 @@ module.exports = (RED) => {
|
|
|
51
50
|
node.nodeClients.forEach((_oClient) => {
|
|
52
51
|
const oClient = _oClient;
|
|
53
52
|
try {
|
|
54
|
-
// if (_event.type === "light" || _event.type === "grouped_light") {
|
|
55
|
-
// console.log(_event);
|
|
56
|
-
// }
|
|
57
53
|
if (oClient.handleSendHUE !== undefined) oClient.handleSendHUE(_event);
|
|
58
54
|
} catch (error) {
|
|
59
55
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`Errore node.hueManager.on(event): ${error.message}`);
|
|
@@ -69,11 +65,7 @@ module.exports = (RED) => {
|
|
|
69
65
|
node.timerDoInitialRead = setTimeout(() => {
|
|
70
66
|
(async () => {
|
|
71
67
|
try {
|
|
72
|
-
|
|
73
|
-
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`HTTP getting resource from HUE bridge : ${node.name}`);
|
|
74
|
-
await node.loadResourcesFromHUEBridge();
|
|
75
|
-
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info(`Total HUE resources count : ${node.hueAllResources.length}`);
|
|
76
|
-
}
|
|
68
|
+
await node.loadResourcesFromHUEBridge();
|
|
77
69
|
} catch (error) {
|
|
78
70
|
node.linkStatus = "disconnected";
|
|
79
71
|
node.nodeClients.forEach((_oClient) => {
|
|
@@ -122,7 +114,6 @@ module.exports = (RED) => {
|
|
|
122
114
|
};
|
|
123
115
|
node.startWatchdogTimer();
|
|
124
116
|
|
|
125
|
-
// Functions called from the nodes ----------------------------------------------------------------
|
|
126
117
|
// Query the HUE Bridge to return the resources
|
|
127
118
|
node.loadResourcesFromHUEBridge = async () => {
|
|
128
119
|
if (node.linkStatus === "disconnected") return;
|
|
@@ -145,7 +136,7 @@ module.exports = (RED) => {
|
|
|
145
136
|
});
|
|
146
137
|
_node.currentHUEDevice = cloneDeep(oHUEDevice); // Copy by Value and not by ref
|
|
147
138
|
if (_node.initializingAtStart === true) {
|
|
148
|
-
_node.handleSendHUE(
|
|
139
|
+
_node.handleSendHUE(oHUEDevice); // Pass by value
|
|
149
140
|
}
|
|
150
141
|
}
|
|
151
142
|
}
|
|
@@ -182,13 +173,11 @@ module.exports = (RED) => {
|
|
|
182
173
|
};
|
|
183
174
|
|
|
184
175
|
// Return an array of light belonging to the groupID
|
|
185
|
-
node.getAllLightsBelongingToTheGroup = async function getAllLightsBelongingToTheGroup(_groupID
|
|
176
|
+
node.getAllLightsBelongingToTheGroup = async function getAllLightsBelongingToTheGroup(_groupID) {
|
|
186
177
|
if (node.hueAllResources === undefined || node.hueAllResources === null) return;
|
|
187
178
|
const retArr = [];
|
|
188
179
|
try {
|
|
189
|
-
|
|
190
|
-
await node.loadResourcesFromHUEBridge();
|
|
191
|
-
}
|
|
180
|
+
await node.loadResourcesFromHUEBridge();
|
|
192
181
|
node.hueAllResources.forEach((res) => {
|
|
193
182
|
if (res.services !== undefined && res.services.length > 0) {
|
|
194
183
|
res.services.forEach((serv) => {
|
|
@@ -198,8 +187,7 @@ module.exports = (RED) => {
|
|
|
198
187
|
for (let index = 0; index < children.length; index++) {
|
|
199
188
|
const element = children[index];
|
|
200
189
|
const oLight = node.hueAllResources.filter((a) => a.id === element.rid);
|
|
201
|
-
|
|
202
|
-
if (oLight !== null && oLight !== undefined) retArr.push(oLight[0]);
|
|
190
|
+
if (oLight !== null && oLight !== undefined) retArr.push({ groupID: _groupID, light: oLight });
|
|
203
191
|
}
|
|
204
192
|
}
|
|
205
193
|
}
|
|
@@ -375,46 +363,6 @@ module.exports = (RED) => {
|
|
|
375
363
|
}
|
|
376
364
|
};
|
|
377
365
|
|
|
378
|
-
/**
|
|
379
|
-
* Get average color XY from a light array
|
|
380
|
-
* @param {array} _arrayLights - Light array
|
|
381
|
-
* @returns { x,y,mirek,brightness } - Object containing all infos
|
|
382
|
-
*/
|
|
383
|
-
node.getAverageColorsXYBrightnessAndTemperature = async function getAverageColorsXYBrightnessAndTemperature(_arrayLights) {
|
|
384
|
-
let x; let y; let mirek; let brightness;
|
|
385
|
-
let countColor = 0, countColor_Temperature = 0, countDimming = 0;
|
|
386
|
-
_arrayLights.forEach((element) => {
|
|
387
|
-
if (element.color !== undefined && element.color.xy !== undefined) {
|
|
388
|
-
if (x === undefined) { x = 0; y = 0; }
|
|
389
|
-
x += element.color.xy.x;
|
|
390
|
-
y += element.color.xy.y;
|
|
391
|
-
countColor += 1;
|
|
392
|
-
}
|
|
393
|
-
if (element.color_temperature !== undefined && element.color_temperature.mirek !== undefined) {
|
|
394
|
-
if (mirek === undefined) mirek = 0;
|
|
395
|
-
mirek += element.color_temperature.mirek;
|
|
396
|
-
countColor_Temperature += 1;
|
|
397
|
-
}
|
|
398
|
-
if (element.dimming !== undefined && element.dimming.brightness !== undefined) {
|
|
399
|
-
if (brightness === undefined) brightness = 0;
|
|
400
|
-
brightness += element.dimming.brightness;
|
|
401
|
-
countDimming += 1;
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
// Calculate and return the averages
|
|
405
|
-
const retX = countColor === 0 ? undefined : x / countColor;
|
|
406
|
-
const retY = countColor === 0 ? undefined : y / countColor;
|
|
407
|
-
const retMirek = countColor_Temperature === 0 ? undefined : mirek / countColor_Temperature;
|
|
408
|
-
const retBrightness = countDimming === 0 ? undefined : brightness / countDimming;
|
|
409
|
-
|
|
410
|
-
return {
|
|
411
|
-
x: retX, y: retY, mirek: retMirek, brightness: retBrightness
|
|
412
|
-
};
|
|
413
|
-
};
|
|
414
|
-
// END functions called from the nodes ----------------------------------------------------------------
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
366
|
node.addClient = (_Node) => {
|
|
419
367
|
// Update the node hue device, as soon as a node register itself to hue-config nodeClients
|
|
420
368
|
if (node.nodeClients.filter((x) => x.id === _Node.id).length === 0) {
|
|
@@ -156,14 +156,14 @@ module.exports = function (RED) {
|
|
|
156
156
|
// The DayNight has switched into day, so restore the previous light state, belonging to the group
|
|
157
157
|
let bAtLeastOneIsOn = false;
|
|
158
158
|
for (let index = 0; index < node.HUELightsBelongingToGroupWhileDaytime.length; index++) { // Ensure, at least 1 lamp was on, otherwise turn all lamps on
|
|
159
|
-
const element = node.HUELightsBelongingToGroupWhileDaytime[index];
|
|
159
|
+
const element = node.HUELightsBelongingToGroupWhileDaytime[index].light[0];
|
|
160
160
|
if (element.on.on === true) {
|
|
161
161
|
bAtLeastOneIsOn = true;
|
|
162
162
|
break;
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
for (let index = 0; index < node.HUELightsBelongingToGroupWhileDaytime.length; index++) {
|
|
166
|
-
const element = node.HUELightsBelongingToGroupWhileDaytime[index];
|
|
166
|
+
const element = node.HUELightsBelongingToGroupWhileDaytime[index].light[0];
|
|
167
167
|
if (bAtLeastOneIsOn === true) {
|
|
168
168
|
state = { on: element.on, dimming: element.dimming, color: element.color, color_temperature: element.color_temperature };
|
|
169
169
|
} else {
|
|
@@ -317,7 +317,7 @@ module.exports = function (RED) {
|
|
|
317
317
|
if (node.isGrouped_light === true) {
|
|
318
318
|
(async () => {
|
|
319
319
|
try {
|
|
320
|
-
const retLights = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice
|
|
320
|
+
const retLights = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice);
|
|
321
321
|
node.HUELightsBelongingToGroupWhileDaytime = cloneDeep(retLights); // DayTime has switched to false: save the lights belonging to the group into the HUELightsBelongingToGroupWhileDaytime array
|
|
322
322
|
} catch (error) { /* empty */ }
|
|
323
323
|
})();
|
|
@@ -509,56 +509,16 @@ module.exports = function (RED) {
|
|
|
509
509
|
if (ret !== undefined) node.updateKNXLightColorState(node.currentHUEDevice.color, "response");
|
|
510
510
|
break;
|
|
511
511
|
case config.GALightKelvinPercentageState:
|
|
512
|
-
// The kelvin level belongs to the group defice, so i don't need to get the first light in the collection (if the device is a grouped_light)
|
|
513
512
|
ret = node.currentHUEDevice.color_temperature.mirek;
|
|
514
513
|
if (ret !== undefined) node.updateKNXLightKelvinPercentageState(ret, "response");
|
|
515
|
-
// if (node.isGrouped_light === false) {
|
|
516
|
-
// ret = node.currentHUEDevice.color_temperature.mirek;
|
|
517
|
-
// if (ret !== undefined) node.updateKNXLightKelvinPercentageState(ret, "response");
|
|
518
|
-
// } else {
|
|
519
|
-
// (async () => {
|
|
520
|
-
// try {
|
|
521
|
-
// // Find the first light in the collection, having the color_temperature capabilities
|
|
522
|
-
// const devices = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false);
|
|
523
|
-
// for (let index = 0; index < devices.length; index++) {
|
|
524
|
-
// const element = devices[index];
|
|
525
|
-
// if (element.light[0].color_temperature !== undefined) {
|
|
526
|
-
// ret = element.light[0].color_temperature.mirek;
|
|
527
|
-
// break;
|
|
528
|
-
// }
|
|
529
|
-
// }
|
|
530
|
-
// if (ret !== undefined) node.updateKNXLightKelvinPercentageState(ret, "response");
|
|
531
|
-
// } catch (error) { /* empty */ }
|
|
532
|
-
// })();
|
|
533
|
-
// }
|
|
534
514
|
break;
|
|
535
515
|
case config.GALightBrightnessState:
|
|
536
516
|
ret = node.currentHUEDevice.dimming.brightness;
|
|
537
517
|
if (ret !== undefined) node.updateKNXBrightnessState(ret, "response");
|
|
538
518
|
break;
|
|
539
519
|
case config.GALightKelvinState:
|
|
540
|
-
// The kelvin level belongs to the group defice, so i don't need to get the first light in the collection (if the device is a grouped_light)
|
|
541
520
|
ret = node.currentHUEDevice.color_temperature.mirek;
|
|
542
521
|
if (ret !== undefined) node.updateKNXLightKelvinState(ret, "response");
|
|
543
|
-
// if (node.isGrouped_light === false) {
|
|
544
|
-
// ret = node.currentHUEDevice.color_temperature.mirek;
|
|
545
|
-
// if (ret !== undefined) node.updateKNXLightKelvinState(ret, "response");
|
|
546
|
-
// } else {
|
|
547
|
-
// (async () => {
|
|
548
|
-
// try {
|
|
549
|
-
// // Find the first light in the collection, having the color_temperature capabilities
|
|
550
|
-
// const devices = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false);
|
|
551
|
-
// for (let index = 0; index < devices.length; index++) {
|
|
552
|
-
// const element = devices[index];
|
|
553
|
-
// if (element.light[0].color_temperature !== undefined) {
|
|
554
|
-
// ret = element.light[0].color_temperature.mirek;
|
|
555
|
-
// break;
|
|
556
|
-
// }
|
|
557
|
-
// }
|
|
558
|
-
// if (ret !== undefined) node.updateKNXLightKelvinState(ret, "response");
|
|
559
|
-
// } catch (error) { /* empty */ }
|
|
560
|
-
// })();
|
|
561
|
-
// }
|
|
562
522
|
break;
|
|
563
523
|
default:
|
|
564
524
|
break;
|
|
@@ -910,87 +870,22 @@ module.exports = function (RED) {
|
|
|
910
870
|
};
|
|
911
871
|
// ***********************************************************
|
|
912
872
|
|
|
913
|
-
node.handleSendHUE =
|
|
914
|
-
if (_event === undefined) return;
|
|
915
|
-
if (_event.type !== 'grouped_light' && _event.type !== 'light') return;
|
|
916
|
-
|
|
917
|
-
// !!!! >>> if the node is a grouped_light, the only values required, thus present, by HUE apis are "on" and "dimming".
|
|
918
|
-
// !!!! >>> For all others properties like for example color and tunable white, i must get the data from one of the child lights.
|
|
919
|
-
|
|
920
|
-
//(async () => {
|
|
921
|
-
// Check and set canContinue true or false ------------------------------------------------------------
|
|
873
|
+
node.handleSendHUE = (_event) => {
|
|
922
874
|
try {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
let canContinue = false;
|
|
935
|
-
// If the current node is a grouped lights, i must check wether the receivedHUEObject (containing a light) belongs to the node lights collection.
|
|
936
|
-
if (node.isGrouped_light === true && receivedHUEObject.type === 'grouped_light' && receivedHUEObject.id === node.hueDevice) {
|
|
937
|
-
canContinue = true;
|
|
938
|
-
} else if (node.isGrouped_light === true && receivedHUEObject.type === 'light') {
|
|
939
|
-
// Handling of not by HUE handled Color Temperature and ColorXY
|
|
940
|
-
// let groupChilds = undefined;
|
|
941
|
-
// let AverageColorsXYBrightnessAndTemperature = undefined; // Average color xy and color temp if the node is a grouped light.
|
|
942
|
-
// // If the current node is a grouped lights, i must check wether the receivedHUEObject (containing a light) belongs to the node lights collection.
|
|
943
|
-
// try {
|
|
944
|
-
// // Find all the lights in the collection, having the color_temperature capabilities, belonging to the group.
|
|
945
|
-
// const devices = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, true);
|
|
946
|
-
// groupChilds = [];
|
|
947
|
-
// for (let index = 0; index < devices.length; index++) {
|
|
948
|
-
// const element = devices[index];
|
|
949
|
-
// if (receivedHUEObject.id === element.id) {
|
|
950
|
-
// //if (groupChilds === undefined) groupChilds = [];
|
|
951
|
-
// // groupChilds.push(element);
|
|
952
|
-
// let modifiedLight = cloneDeep(element);
|
|
953
|
-
// // The dimming is not necessary, beacause the HUE API already sends a group_light event with the average brightness //if (receivedHUEObject.dimming !== undefined) modifiedLight.dimming = { brightness: receivedHUEObject.dimming.brightness };
|
|
954
|
-
// if (receivedHUEObject.color !== undefined && receivedHUEObject.color.xy !== undefined) modifiedLight.color = receivedHUEObject.color;
|
|
955
|
-
// if (receivedHUEObject.color_temperature !== undefined) modifiedLight.color_temperature = receivedHUEObject.color_temperature;
|
|
956
|
-
// groupChilds.push(modifiedLight);
|
|
957
|
-
// } else {
|
|
958
|
-
// // Simply ppend the light
|
|
959
|
-
// groupChilds.push(element);
|
|
960
|
-
// }
|
|
961
|
-
// }
|
|
962
|
-
|
|
963
|
-
// // Use the arithmetic average of color xy, brightness and color temperature "averageColorXYandKelvinOfGroupedLights"
|
|
964
|
-
// if (groupChilds !== undefined) AverageColorsXYBrightnessAndTemperature = await node.serverHue.getAverageColorsXYBrightnessAndTemperature(groupChilds);
|
|
965
|
-
|
|
966
|
-
// // Set the new values based on average calculated above
|
|
967
|
-
// try {
|
|
968
|
-
// // CHECK FIRST THE COLOR_TEMPERATURE, because it can be undefined, because the current selected color
|
|
969
|
-
// // is out of the mirek range, so it cannot be represented with the colore temperature.
|
|
970
|
-
// if (receivedHUEObject.color_temperature !== undefined && AverageColorsXYBrightnessAndTemperature.mirek !== undefined) {
|
|
971
|
-
// receivedHUEObject.color_temperature = { mirek: AverageColorsXYBrightnessAndTemperature.mirek };
|
|
972
|
-
// } else if (receivedHUEObject.color !== undefined && AverageColorsXYBrightnessAndTemperature.x !== undefined) {
|
|
973
|
-
// receivedHUEObject.color = {
|
|
974
|
-
// xy: { x: AverageColorsXYBrightnessAndTemperature.x, y: AverageColorsXYBrightnessAndTemperature.y }
|
|
975
|
-
// };
|
|
976
|
-
// }
|
|
977
|
-
// // The dimming is not necessary, beacause the HUE API already sends a group_light event with the average brightness
|
|
978
|
-
// // if (receivedHUEObject.dimming !== undefined && AverageColorsXYBrightnessAndTemperature.brightness !== undefined) {
|
|
979
|
-
// // receivedHUEObject.dimming = { brightness: AverageColorsXYBrightnessAndTemperature.brightness };
|
|
980
|
-
// // }
|
|
981
|
-
// } catch (error) { /* empty */ }
|
|
982
|
-
|
|
983
|
-
canContinue = true;
|
|
984
|
-
//} catch (error) { /* empty */ }
|
|
985
|
-
} else if (node.isGrouped_light === false && receivedHUEObject.type === 'light' && receivedHUEObject.id === node.hueDevice) {
|
|
986
|
-
canContinue = true;
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
// --------------------------------------------------------------------------------------------------
|
|
875
|
+
const deviceByRef = cloneDeep(_event);
|
|
876
|
+
if (deviceByRef.id === node.hueDevice) {
|
|
877
|
+
if (node.currentHUEDevice === undefined || node.serverHue === null || node.serverHue === undefined) {
|
|
878
|
+
node.setNodeStatusHue({
|
|
879
|
+
fill: "red",
|
|
880
|
+
shape: "ring",
|
|
881
|
+
text: "Rejected HUE message. I'm connecting to the Bridge...",
|
|
882
|
+
payload: "",
|
|
883
|
+
});
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
990
886
|
|
|
991
|
-
if (canContinue === true) {
|
|
992
887
|
// Output the msg to the flow
|
|
993
|
-
node.send(
|
|
888
|
+
node.send(deviceByRef);
|
|
994
889
|
|
|
995
890
|
// // DEBUG testing enable/disable HTML UI Tabs
|
|
996
891
|
//delete _event.dimming;
|
|
@@ -998,39 +893,53 @@ module.exports = function (RED) {
|
|
|
998
893
|
//delete _event.color_temperature;
|
|
999
894
|
//delete _event.color_temperature_delta;
|
|
1000
895
|
|
|
1001
|
-
|
|
1002
|
-
|
|
896
|
+
// As grouped_light doesn't contain all requested properties, i find the first light in the group, and use this below in the code
|
|
897
|
+
// If the event type is grouped light, and there are missing properties, i infer these missing properties from the first light in the group!
|
|
898
|
+
if ((deviceByRef.color !== undefined || deviceByRef.dimming !== undefined || deviceByRef.color_temperature !== undefined) && deviceByRef.type === 'grouped_light') {
|
|
899
|
+
try {
|
|
900
|
+
const firstLightInGroup = node.serverHue.getFirstLightInGroup(deviceByRef.id);
|
|
901
|
+
if (firstLightInGroup !== null && firstLightInGroup !== undefined) {
|
|
902
|
+
if (deviceByRef.color === undefined) {
|
|
903
|
+
deviceByRef.color = firstLightInGroup.color;
|
|
904
|
+
}
|
|
905
|
+
if (deviceByRef.color_temperature === undefined) {
|
|
906
|
+
deviceByRef.color_temperature = firstLightInGroup.color_temperature;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
} catch (error) { }
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
if (deviceByRef.on !== undefined) {
|
|
913
|
+
node.updateKNXLightState(deviceByRef.on.on);
|
|
1003
914
|
// In case of switch off, set the dim to zero
|
|
1004
|
-
if (
|
|
915
|
+
if (deviceByRef.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === "onhueoff")) {
|
|
1005
916
|
node.updateKNXBrightnessState(0);
|
|
1006
|
-
if (
|
|
1007
|
-
} else if (
|
|
1008
|
-
let brightVal = 50;
|
|
917
|
+
if (deviceByRef.dimming !== undefined) delete deviceByRef.dimming; // Remove event.dimming, because has beem handled by this function and i don't want the function below to take care of it.
|
|
918
|
+
} else if (deviceByRef.on.on === true && node.currentHUEDevice.on.on === false) {
|
|
1009
919
|
// Turn on always update the dimming KNX Status value as well.
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
}
|
|
920
|
+
let brightVal = 50;
|
|
921
|
+
if (node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness !== undefined) brightVal = node.currentHUEDevice.dimming.brightness;
|
|
1013
922
|
node.updateKNXBrightnessState(brightVal);
|
|
1014
923
|
}
|
|
1015
|
-
node.currentHUEDevice.on.on =
|
|
924
|
+
node.currentHUEDevice.on.on = deviceByRef.on.on;
|
|
1016
925
|
}
|
|
1017
926
|
|
|
1018
|
-
if (
|
|
1019
|
-
node.updateKNXLightColorState(
|
|
1020
|
-
node.currentHUEDevice.color =
|
|
927
|
+
if (deviceByRef.color !== undefined) { // fixed https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/287
|
|
928
|
+
node.updateKNXLightColorState(deviceByRef.color);
|
|
929
|
+
node.currentHUEDevice.color = deviceByRef.color;
|
|
1021
930
|
}
|
|
1022
931
|
|
|
1023
|
-
if (
|
|
932
|
+
if (deviceByRef.dimming !== undefined && deviceByRef.dimming.brightness !== undefined) {
|
|
1024
933
|
// Once upon n a time, the light transmit the brightness value of 0.39.
|
|
1025
934
|
// To avoid wrongly turn light state on, exit
|
|
1026
|
-
if (
|
|
1027
|
-
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false &&
|
|
935
|
+
if (deviceByRef.dimming.brightness < 1) deviceByRef.dimming.brightness = 0;
|
|
936
|
+
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && deviceByRef.dimming.brightness === 0) {
|
|
1028
937
|
// Do nothing, because the light is off and the dimming also is 0
|
|
1029
938
|
} else {
|
|
1030
|
-
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && (
|
|
1031
|
-
node.updateKNXBrightnessState(
|
|
939
|
+
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && (deviceByRef.on === undefined || (deviceByRef.on !== undefined && deviceByRef.on.on === true))) node.updateKNXLightState(deviceByRef.dimming.brightness > 0);
|
|
940
|
+
node.updateKNXBrightnessState(deviceByRef.dimming.brightness);
|
|
1032
941
|
// If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
|
|
1033
|
-
if (
|
|
942
|
+
if (deviceByRef.dimming.brightness === 0 && node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true) {
|
|
1034
943
|
node.serverHue.hueManager.writeHueQueueAdd(
|
|
1035
944
|
node.hueDevice,
|
|
1036
945
|
{ on: { on: false } },
|
|
@@ -1038,15 +947,14 @@ module.exports = function (RED) {
|
|
|
1038
947
|
);
|
|
1039
948
|
node.currentHUEDevice.on.on = false;
|
|
1040
949
|
}
|
|
1041
|
-
node.currentHUEDevice.dimming.brightness =
|
|
950
|
+
node.currentHUEDevice.dimming.brightness = deviceByRef.dimming.brightness;
|
|
1042
951
|
}
|
|
1043
952
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
node.
|
|
1047
|
-
node.
|
|
1048
|
-
|
|
1049
|
-
};
|
|
953
|
+
if (deviceByRef.color_temperature !== undefined && deviceByRef.color_temperature.mirek !== undefined) {
|
|
954
|
+
node.updateKNXLightKelvinPercentageState(deviceByRef.color_temperature.mirek);
|
|
955
|
+
node.updateKNXLightKelvinState(deviceByRef.color_temperature.mirek);
|
|
956
|
+
node.currentHUEDevice.color_temperature.mirek = deviceByRef.color_temperature.mirek;
|
|
957
|
+
}
|
|
1050
958
|
}
|
|
1051
959
|
} catch (error) {
|
|
1052
960
|
node.status({
|
|
@@ -1056,163 +964,8 @@ module.exports = function (RED) {
|
|
|
1056
964
|
});
|
|
1057
965
|
RED.log.error(`knxUltimateHueLight: node.handleSendHUE = (_event): ${error.stack}`);
|
|
1058
966
|
}
|
|
1059
|
-
//})();
|
|
1060
967
|
};
|
|
1061
968
|
|
|
1062
|
-
|
|
1063
|
-
// node.handleSendHUE = async (_event) => {
|
|
1064
|
-
// if (_event === undefined) return;
|
|
1065
|
-
// if (_event.type !== 'grouped_light' && _event.type !== 'light') return;
|
|
1066
|
-
|
|
1067
|
-
// // if the node is a grouped_light, the only values required, thus present, by HUE apis are "on" and "dimming".
|
|
1068
|
-
// // For all others properties like for example color and tunable white, i must get the data from one of the child lights.
|
|
1069
|
-
// //(async () => {
|
|
1070
|
-
// // Check and set canContinue true or false ------------------------------------------------------------
|
|
1071
|
-
// try {
|
|
1072
|
-
// if (node.currentHUEDevice === undefined || node.serverHue === null || node.serverHue === undefined) {
|
|
1073
|
-
// node.setNodeStatusHue({
|
|
1074
|
-
// fill: "red",
|
|
1075
|
-
// shape: "ring",
|
|
1076
|
-
// text: "Rejected HUE light settings. I'm still not ready...",
|
|
1077
|
-
// payload: "",
|
|
1078
|
-
// });
|
|
1079
|
-
// return;
|
|
1080
|
-
// }
|
|
1081
|
-
|
|
1082
|
-
// const receivedHUEObject = cloneDeep(_event);
|
|
1083
|
-
// let groupChilds = undefined;
|
|
1084
|
-
// let AverageColorsXYBrightnessAndTemperature = undefined; // Average color and temp if the node is a grouped light.
|
|
1085
|
-
// let canContinue = false;
|
|
1086
|
-
// // If the current node is a grouped lights, i must check wether the receivedHUEObject (containing a light) belongs to the node lights collection.
|
|
1087
|
-
// if (node.isGrouped_light === true) {
|
|
1088
|
-
// try {
|
|
1089
|
-
// // Find all the lights in the collection, having the color_temperature capabilities, belonging to the group.
|
|
1090
|
-
// if (receivedHUEObject.type === "grouped_light") {
|
|
1091
|
-
// groupChilds = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false);
|
|
1092
|
-
// } else {
|
|
1093
|
-
// const devices = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false);
|
|
1094
|
-
// groupChilds = [];
|
|
1095
|
-
// for (let index = 0; index < devices.length; index++) {
|
|
1096
|
-
// const element = devices[index];
|
|
1097
|
-
// if (receivedHUEObject.id === element.id) {
|
|
1098
|
-
// //if (groupChilds === undefined) groupChilds = [];
|
|
1099
|
-
// // groupChilds.push(element);
|
|
1100
|
-
// let modifiedLight = cloneDeep(element);
|
|
1101
|
-
// if (receivedHUEObject.dimming !== undefined) modifiedLight.dimming = { brightness: receivedHUEObject.dimming.brightness };
|
|
1102
|
-
// if (receivedHUEObject.color !== undefined) modifiedLight.color = receivedHUEObject.color;
|
|
1103
|
-
// if (receivedHUEObject.color_temperature !== undefined) modifiedLight.color_temperature = receivedHUEObject.color_temperature;
|
|
1104
|
-
// groupChilds.push(modifiedLight);
|
|
1105
|
-
// } else {
|
|
1106
|
-
// // Simply ppend the light
|
|
1107
|
-
// groupChilds.push(element);
|
|
1108
|
-
// }
|
|
1109
|
-
// }
|
|
1110
|
-
// }
|
|
1111
|
-
// if (groupChilds !== undefined) AverageColorsXYBrightnessAndTemperature = await node.serverHue.getAverageColorsXYBrightnessAndTemperature(groupChilds);
|
|
1112
|
-
|
|
1113
|
-
// // Set the new values based on average calculated above
|
|
1114
|
-
// try {
|
|
1115
|
-
// // Use the arithmetic average of color xy, brightness and color temperature "averageColorXYandKelvinOfGroupedLights"
|
|
1116
|
-
// if (receivedHUEObject.color !== undefined && AverageColorsXYBrightnessAndTemperature.x !== undefined) {
|
|
1117
|
-
// receivedHUEObject.color = {
|
|
1118
|
-
// xy: { x: AverageColorsXYBrightnessAndTemperature.x, y: AverageColorsXYBrightnessAndTemperature.y }
|
|
1119
|
-
// };
|
|
1120
|
-
// }
|
|
1121
|
-
// if (receivedHUEObject.color_temperature !== undefined && AverageColorsXYBrightnessAndTemperature.mirek !== undefined) {
|
|
1122
|
-
// receivedHUEObject.color_temperature = { mirek: AverageColorsXYBrightnessAndTemperature.mirek };
|
|
1123
|
-
// }
|
|
1124
|
-
// if (receivedHUEObject.dimming !== undefined && AverageColorsXYBrightnessAndTemperature.brightness !== undefined) {
|
|
1125
|
-
// receivedHUEObject.dimming = { brightness: AverageColorsXYBrightnessAndTemperature.brightness };
|
|
1126
|
-
// }
|
|
1127
|
-
// } catch (error) { /* empty */ }
|
|
1128
|
-
|
|
1129
|
-
// canContinue = true;
|
|
1130
|
-
// } catch (error) { /* empty */ }
|
|
1131
|
-
// } else {
|
|
1132
|
-
// if (receivedHUEObject.type !== "light") return;
|
|
1133
|
-
// if (receivedHUEObject.id === node.hueDevice) {
|
|
1134
|
-
// canContinue = true;
|
|
1135
|
-
// }
|
|
1136
|
-
// }
|
|
1137
|
-
// // --------------------------------------------------------------------------------------------------
|
|
1138
|
-
|
|
1139
|
-
// if (canContinue === true) {
|
|
1140
|
-
|
|
1141
|
-
// // Output the msg to the flow
|
|
1142
|
-
// node.send(receivedHUEObject);
|
|
1143
|
-
|
|
1144
|
-
// // // DEBUG testing enable/disable HTML UI Tabs
|
|
1145
|
-
// //delete _event.dimming;
|
|
1146
|
-
// //delete _event.color;
|
|
1147
|
-
// //delete _event.color_temperature;
|
|
1148
|
-
// //delete _event.color_temperature_delta;
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
// if (receivedHUEObject.on !== undefined) {
|
|
1152
|
-
// node.updateKNXLightState(receivedHUEObject.on.on);
|
|
1153
|
-
// // In case of switch off, set the dim to zero
|
|
1154
|
-
// if (receivedHUEObject.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === "onhueoff")) {
|
|
1155
|
-
// node.updateKNXBrightnessState(0);
|
|
1156
|
-
// if (receivedHUEObject.dimming !== undefined) delete receivedHUEObject.dimming; // Remove event.dimming, because has beem handled by this function and i don't want the function below to take care of it.
|
|
1157
|
-
// } else if (receivedHUEObject.on.on === true && node.currentHUEDevice.on.on === false) {
|
|
1158
|
-
// let brightVal = 50;
|
|
1159
|
-
// if (node.currentHUEDevice.type === "light") {
|
|
1160
|
-
// // Turn on always update the dimming KNX Status value as well.
|
|
1161
|
-
// if (node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness !== undefined) {
|
|
1162
|
-
// brightVal = node.currentHUEDevice.dimming.brightness;
|
|
1163
|
-
// }
|
|
1164
|
-
// } else if (node.currentHUEDevice.type === "grouped_light") {
|
|
1165
|
-
// brightVal = AverageColorsXYBrightnessAndTemperature;
|
|
1166
|
-
// }
|
|
1167
|
-
// node.updateKNXBrightnessState(brightVal);
|
|
1168
|
-
// }
|
|
1169
|
-
// node.currentHUEDevice.on.on = receivedHUEObject.on.on;
|
|
1170
|
-
// }
|
|
1171
|
-
|
|
1172
|
-
// if (receivedHUEObject.color !== undefined) { // fixed https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/287
|
|
1173
|
-
// node.updateKNXLightColorState(receivedHUEObject.color);
|
|
1174
|
-
// node.currentHUEDevice.color = receivedHUEObject.color;
|
|
1175
|
-
// }
|
|
1176
|
-
|
|
1177
|
-
// if (receivedHUEObject.dimming !== undefined && receivedHUEObject.dimming.brightness !== undefined) {
|
|
1178
|
-
// // Once upon n a time, the light transmit the brightness value of 0.39.
|
|
1179
|
-
// // To avoid wrongly turn light state on, exit
|
|
1180
|
-
// if (receivedHUEObject.dimming.brightness < 1) receivedHUEObject.dimming.brightness = 0;
|
|
1181
|
-
// if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && receivedHUEObject.dimming.brightness === 0) {
|
|
1182
|
-
// // Do nothing, because the light is off and the dimming also is 0
|
|
1183
|
-
// } else {
|
|
1184
|
-
// if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && (receivedHUEObject.on === undefined || (receivedHUEObject.on !== undefined && receivedHUEObject.on.on === true))) node.updateKNXLightState(receivedHUEObject.dimming.brightness > 0);
|
|
1185
|
-
// node.updateKNXBrightnessState(receivedHUEObject.dimming.brightness);
|
|
1186
|
-
// // If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
|
|
1187
|
-
// if (receivedHUEObject.dimming.brightness === 0 && node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true) {
|
|
1188
|
-
// node.serverHue.hueManager.writeHueQueueAdd(
|
|
1189
|
-
// node.hueDevice,
|
|
1190
|
-
// { on: { on: false } },
|
|
1191
|
-
// node.isGrouped_light === false ? "setLight" : "setGroupedLight",
|
|
1192
|
-
// );
|
|
1193
|
-
// node.currentHUEDevice.on.on = false;
|
|
1194
|
-
// }
|
|
1195
|
-
// node.currentHUEDevice.dimming.brightness = receivedHUEObject.dimming.brightness;
|
|
1196
|
-
// }
|
|
1197
|
-
// }
|
|
1198
|
-
|
|
1199
|
-
// if (receivedHUEObject.color_temperature !== undefined) {
|
|
1200
|
-
// node.updateKNXLightKelvinPercentageState(receivedHUEObject.color_temperature.mirek);
|
|
1201
|
-
// node.updateKNXLightKelvinState(receivedHUEObject.color_temperature.mirek);
|
|
1202
|
-
// node.currentHUEDevice.color_temperature.mirek = receivedHUEObject.color_temperature.mirek;
|
|
1203
|
-
// };
|
|
1204
|
-
// }
|
|
1205
|
-
// } catch (error) {
|
|
1206
|
-
// node.status({
|
|
1207
|
-
// fill: "red",
|
|
1208
|
-
// shape: "dot",
|
|
1209
|
-
// text: `HUE->KNX error ${node.id} ${error.message}. Seee Log`,
|
|
1210
|
-
// });
|
|
1211
|
-
// RED.log.error(`knxUltimateHueLight: node.handleSendHUE = (_event): ${error.stack}`);
|
|
1212
|
-
// }
|
|
1213
|
-
// //})();
|
|
1214
|
-
// };
|
|
1215
|
-
|
|
1216
969
|
// Leave the name after "function", to avoid <anonymous function> in the stack trace, in caso of errors.
|
|
1217
970
|
node.updateKNXBrightnessState = function updateKNXBrightnessState(_value, _outputtype = "write") {
|
|
1218
971
|
if (config.GALightBrightnessState !== undefined && config.GALightBrightnessState !== "") {
|
|
@@ -1375,11 +1128,11 @@ module.exports = function (RED) {
|
|
|
1375
1128
|
// };
|
|
1376
1129
|
|
|
1377
1130
|
/**
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1131
|
+
* Update the KNC colors and HSV states group addresses
|
|
1132
|
+
* @param {object} _value {xy:{x,y}} in 0-1 scale
|
|
1133
|
+
* @param {string} _outputtype "write" is the default KNX command
|
|
1134
|
+
* @returns {}
|
|
1135
|
+
*/
|
|
1383
1136
|
node.updateKNXLightColorState = function updateKNXLightColorState(_value, _outputtype = "write") {
|
|
1384
1137
|
if (config.GALightColorState !== undefined && config.GALightColorState !== "") {
|
|
1385
1138
|
if (_value.xy === undefined || _value.xy.x === undefined) return;
|
|
@@ -1476,8 +1229,8 @@ module.exports = function (RED) {
|
|
|
1476
1229
|
knxMsgPayload.topic = config.GALightKelvinState;
|
|
1477
1230
|
knxMsgPayload.dpt = config.dptLightKelvinState;
|
|
1478
1231
|
if (config.dptLightKelvinState === "7.600") {
|
|
1479
|
-
|
|
1480
|
-
|
|
1232
|
+
kelvinValue = hueColorConverter.ColorConverter.mirekToKelvin(_value);
|
|
1233
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.scale(kelvinValue, [2000, 6535], [0, 65535]);
|
|
1481
1234
|
} else if (config.dptLightKelvinState === "9.002") {
|
|
1482
1235
|
knxMsgPayload.payload = hueColorConverter.ColorConverter.mirekToKelvin(_value);
|
|
1483
1236
|
}
|
|
@@ -1497,7 +1250,7 @@ module.exports = function (RED) {
|
|
|
1497
1250
|
fill: "blue",
|
|
1498
1251
|
shape: "ring",
|
|
1499
1252
|
text: "HUE->KNX Kelvin",
|
|
1500
|
-
payload:
|
|
1253
|
+
payload: kelvinValue,
|
|
1501
1254
|
});
|
|
1502
1255
|
}
|
|
1503
1256
|
}
|
package/nodes/utils/utils.js
CHANGED
|
@@ -53,6 +53,5 @@ module.exports.fetchFromObject = function fetchFromObject(
|
|
|
53
53
|
if (typeof _msg[_payloadPropName] === "object") return undefined;
|
|
54
54
|
return _msg[_payloadPropName];
|
|
55
55
|
};
|
|
56
|
-
|
|
57
56
|
const DEFAULTTRANSLATIONINPUT =
|
|
58
57
|
"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";
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=16.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.4.
|
|
6
|
+
"version": "2.4.28",
|
|
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",
|