node-red-contrib-knx-ultimate 2.4.23 → 2.4.26

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,10 +6,24 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ **Version 2.4.26** - Mai 2024<br/>
10
+ - Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
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/>
22
+
9
23
  **Version 2.4.23** - Mai 2024<br/>
10
24
  - Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
11
25
  - HUE Scene node: fixed max scene count to 64.<br/>
12
-
26
+
13
27
  **Version 2.4.22** - April 2024<br/>
14
28
  - Warning: this version uses the Node-Red plugin system; the Node-Red version must be **equals or major than 3.1.1**<br/>
15
29
  - 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,14 +50,17 @@ 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
+
53
56
  |Technology|Supported|
54
57
  |--|--|
55
58
  | KNX Tunnelling | ![](https://placehold.co/200x20/green/white?text=YES) |
56
59
  | KNX Routing | ![](https://placehold.co/200x20/green/white?text=YES) |
57
60
  | KNX Secure Tunnelling | ![](https://placehold.co/200x20/orange/white?text=UNDER+DEVELOPMENT) |
58
61
  | KNX Secure Routing | ![](https://placehold.co/200x20/red/white?text=NO) |
59
- | KNX 3rd PARTY IOT API | ![](https://placehold.co/200x20/orange/white?text=UNDER+DEVELOPMENT) |
60
-
62
+ | KNX 3rd PARTY IOT API client | ![](https://placehold.co/200x20/orange/white?text=UNDER+DEVELOPMENT) |
63
+ | Matter | ![](https://placehold.co/200x20/blue/white?text=UNDER+BRAINSTORMING) |
61
64
 
62
65
  <br/>
63
66
 
@@ -8,6 +8,7 @@ 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");
11
12
 
12
13
  module.exports = (RED) => {
13
14
  function hueConfig(config) {
@@ -50,6 +51,9 @@ module.exports = (RED) => {
50
51
  node.nodeClients.forEach((_oClient) => {
51
52
  const oClient = _oClient;
52
53
  try {
54
+ // if (_event.type === "light" || _event.type === "grouped_light") {
55
+ // console.log(_event);
56
+ // }
53
57
  if (oClient.handleSendHUE !== undefined) oClient.handleSendHUE(_event);
54
58
  } catch (error) {
55
59
  if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`Errore node.hueManager.on(event): ${error.message}`);
@@ -65,7 +69,11 @@ module.exports = (RED) => {
65
69
  node.timerDoInitialRead = setTimeout(() => {
66
70
  (async () => {
67
71
  try {
68
- await node.loadResourcesFromHUEBridge();
72
+ if (node.hueAllResources === undefined) {
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
+ }
69
77
  } catch (error) {
70
78
  node.linkStatus = "disconnected";
71
79
  node.nodeClients.forEach((_oClient) => {
@@ -114,6 +122,7 @@ module.exports = (RED) => {
114
122
  };
115
123
  node.startWatchdogTimer();
116
124
 
125
+ // Functions called from the nodes ----------------------------------------------------------------
117
126
  // Query the HUE Bridge to return the resources
118
127
  node.loadResourcesFromHUEBridge = async () => {
119
128
  if (node.linkStatus === "disconnected") return;
@@ -136,7 +145,7 @@ module.exports = (RED) => {
136
145
  });
137
146
  _node.currentHUEDevice = cloneDeep(oHUEDevice); // Copy by Value and not by ref
138
147
  if (_node.initializingAtStart === true) {
139
- _node.handleSendHUE(oHUEDevice); // Pass by value
148
+ _node.handleSendHUE(_node.currentHUEDevice); // Pass by value
140
149
  }
141
150
  }
142
151
  }
@@ -173,11 +182,13 @@ module.exports = (RED) => {
173
182
  };
174
183
 
175
184
  // Return an array of light belonging to the groupID
176
- node.getAllLightsBelongingToTheGroup = async function getAllLightsBelongingToTheGroup(_groupID) {
185
+ node.getAllLightsBelongingToTheGroup = async function getAllLightsBelongingToTheGroup(_groupID, refreshResourcesFromBridge = true) {
177
186
  if (node.hueAllResources === undefined || node.hueAllResources === null) return;
178
187
  const retArr = [];
179
188
  try {
180
- await node.loadResourcesFromHUEBridge();
189
+ if (refreshResourcesFromBridge === true) {
190
+ await node.loadResourcesFromHUEBridge();
191
+ }
181
192
  node.hueAllResources.forEach((res) => {
182
193
  if (res.services !== undefined && res.services.length > 0) {
183
194
  res.services.forEach((serv) => {
@@ -187,7 +198,8 @@ module.exports = (RED) => {
187
198
  for (let index = 0; index < children.length; index++) {
188
199
  const element = children[index];
189
200
  const oLight = node.hueAllResources.filter((a) => a.id === element.rid);
190
- if (oLight !== null && oLight !== undefined) retArr.push({ groupID: _groupID, light: oLight });
201
+ //if (oLight !== null && oLight !== undefined) retArr.push({ groupID: _groupID, light: oLight[0] });
202
+ if (oLight !== null && oLight !== undefined) retArr.push(oLight[0]);
191
203
  }
192
204
  }
193
205
  }
@@ -363,6 +375,46 @@ module.exports = (RED) => {
363
375
  }
364
376
  };
365
377
 
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
+
366
418
  node.addClient = (_Node) => {
367
419
  // Update the node hue device, as soon as a node register itself to hue-config nodeClients
368
420
  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].light[0];
159
+ const element = node.HUELightsBelongingToGroupWhileDaytime[index];
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].light[0];
166
+ const element = node.HUELightsBelongingToGroupWhileDaytime[index];
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, false);
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,16 +509,56 @@ 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)
512
513
  ret = node.currentHUEDevice.color_temperature.mirek;
513
514
  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
+ // }
514
534
  break;
515
535
  case config.GALightBrightnessState:
516
536
  ret = node.currentHUEDevice.dimming.brightness;
517
537
  if (ret !== undefined) node.updateKNXBrightnessState(ret, "response");
518
538
  break;
519
539
  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)
520
541
  ret = node.currentHUEDevice.color_temperature.mirek;
521
542
  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
+ // }
522
562
  break;
523
563
  default:
524
564
  break;
@@ -870,22 +910,87 @@ module.exports = function (RED) {
870
910
  };
871
911
  // ***********************************************************
872
912
 
873
- node.handleSendHUE = (_event) => {
913
+ node.handleSendHUE = async (_event) => {
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 ------------------------------------------------------------
874
922
  try {
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
- }
923
+ if (node.currentHUEDevice === undefined || node.serverHue === null || node.serverHue === undefined) {
924
+ node.setNodeStatusHue({
925
+ fill: "red",
926
+ shape: "ring",
927
+ text: "Rejected HUE light settings. I'm still not ready...",
928
+ payload: "",
929
+ });
930
+ return;
931
+ }
932
+
933
+ const receivedHUEObject = cloneDeep(_event);
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
+ }
886
988
 
989
+ // --------------------------------------------------------------------------------------------------
990
+
991
+ if (canContinue === true) {
887
992
  // Output the msg to the flow
888
- node.send(deviceByRef);
993
+ node.send(receivedHUEObject);
889
994
 
890
995
  // // DEBUG testing enable/disable HTML UI Tabs
891
996
  //delete _event.dimming;
@@ -893,53 +998,39 @@ module.exports = function (RED) {
893
998
  //delete _event.color_temperature;
894
999
  //delete _event.color_temperature_delta;
895
1000
 
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);
1001
+ if (receivedHUEObject.on !== undefined) {
1002
+ node.updateKNXLightState(receivedHUEObject.on.on);
914
1003
  // In case of switch off, set the dim to zero
915
- if (deviceByRef.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === "onhueoff")) {
1004
+ if (receivedHUEObject.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === "onhueoff")) {
916
1005
  node.updateKNXBrightnessState(0);
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) {
919
- // Turn on always update the dimming KNX Status value as well.
1006
+ 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.
1007
+ } else if (receivedHUEObject.on.on === true && node.currentHUEDevice.on.on === false) {
920
1008
  let brightVal = 50;
921
- if (node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness !== undefined) brightVal = node.currentHUEDevice.dimming.brightness;
1009
+ // Turn on always update the dimming KNX Status value as well.
1010
+ if (node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness !== undefined) {
1011
+ brightVal = node.currentHUEDevice.dimming.brightness;
1012
+ }
922
1013
  node.updateKNXBrightnessState(brightVal);
923
1014
  }
924
- node.currentHUEDevice.on.on = deviceByRef.on.on;
1015
+ node.currentHUEDevice.on.on = receivedHUEObject.on.on;
925
1016
  }
926
1017
 
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;
1018
+ if (receivedHUEObject.color !== undefined && receivedHUEObject.color.xy !== undefined) { // fixed https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/287
1019
+ node.updateKNXLightColorState(receivedHUEObject.color);
1020
+ node.currentHUEDevice.color = receivedHUEObject.color;
930
1021
  }
931
1022
 
932
- if (deviceByRef.dimming !== undefined && deviceByRef.dimming.brightness !== undefined) {
1023
+ if (receivedHUEObject.dimming !== undefined && receivedHUEObject.dimming.brightness !== undefined) {
933
1024
  // Once upon n a time, the light transmit the brightness value of 0.39.
934
1025
  // To avoid wrongly turn light state on, exit
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) {
1026
+ if (receivedHUEObject.dimming.brightness < 1) receivedHUEObject.dimming.brightness = 0;
1027
+ if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && receivedHUEObject.dimming.brightness === 0) {
937
1028
  // Do nothing, because the light is off and the dimming also is 0
938
1029
  } else {
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);
1030
+ 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);
1031
+ node.updateKNXBrightnessState(receivedHUEObject.dimming.brightness);
941
1032
  // If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
942
- if (deviceByRef.dimming.brightness === 0 && node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true) {
1033
+ if (receivedHUEObject.dimming.brightness === 0 && node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true) {
943
1034
  node.serverHue.hueManager.writeHueQueueAdd(
944
1035
  node.hueDevice,
945
1036
  { on: { on: false } },
@@ -947,14 +1038,15 @@ module.exports = function (RED) {
947
1038
  );
948
1039
  node.currentHUEDevice.on.on = false;
949
1040
  }
950
- node.currentHUEDevice.dimming.brightness = deviceByRef.dimming.brightness;
1041
+ node.currentHUEDevice.dimming.brightness = receivedHUEObject.dimming.brightness;
951
1042
  }
952
1043
  }
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
- }
1044
+
1045
+ if (receivedHUEObject.color_temperature !== undefined && receivedHUEObject.color_temperature.mirek !== undefined) {
1046
+ node.updateKNXLightKelvinPercentageState(receivedHUEObject.color_temperature.mirek);
1047
+ node.updateKNXLightKelvinState(receivedHUEObject.color_temperature.mirek);
1048
+ node.currentHUEDevice.color_temperature.mirek = receivedHUEObject.color_temperature.mirek;
1049
+ };
958
1050
  }
959
1051
  } catch (error) {
960
1052
  node.status({
@@ -964,8 +1056,163 @@ module.exports = function (RED) {
964
1056
  });
965
1057
  RED.log.error(`knxUltimateHueLight: node.handleSendHUE = (_event): ${error.stack}`);
966
1058
  }
1059
+ //})();
967
1060
  };
968
1061
 
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
+
969
1216
  // Leave the name after "function", to avoid <anonymous function> in the stack trace, in caso of errors.
970
1217
  node.updateKNXBrightnessState = function updateKNXBrightnessState(_value, _outputtype = "write") {
971
1218
  if (config.GALightBrightnessState !== undefined && config.GALightBrightnessState !== "") {
@@ -1128,11 +1375,11 @@ module.exports = function (RED) {
1128
1375
  // };
1129
1376
 
1130
1377
  /**
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
- */
1378
+ * Update the KNC colors and HSV states group addresses
1379
+ * @param {object} _value {xy:{x,y}} in 0-1 scale
1380
+ * @param {string} _outputtype "write" is the default KNX command
1381
+ * @returns {}
1382
+ */
1136
1383
  node.updateKNXLightColorState = function updateKNXLightColorState(_value, _outputtype = "write") {
1137
1384
  if (config.GALightColorState !== undefined && config.GALightColorState !== "") {
1138
1385
  if (_value.xy === undefined || _value.xy.x === undefined) return;
@@ -1229,8 +1476,8 @@ module.exports = function (RED) {
1229
1476
  knxMsgPayload.topic = config.GALightKelvinState;
1230
1477
  knxMsgPayload.dpt = config.dptLightKelvinState;
1231
1478
  if (config.dptLightKelvinState === "7.600") {
1232
- kelvinValue = hueColorConverter.ColorConverter.mirekToKelvin(_value);
1233
- knxMsgPayload.payload = hueColorConverter.ColorConverter.scale(kelvinValue, [2000, 6535], [0, 65535]);
1479
+ knxMsgPayload.payload = hueColorConverter.ColorConverter.mirekToKelvin(_value);
1480
+ //knxMsgPayload.payload = hueColorConverter.ColorConverter.scale(kelvinValue, [2000, 6535], [0, 65535]);
1234
1481
  } else if (config.dptLightKelvinState === "9.002") {
1235
1482
  knxMsgPayload.payload = hueColorConverter.ColorConverter.mirekToKelvin(_value);
1236
1483
  }
@@ -1250,7 +1497,7 @@ module.exports = function (RED) {
1250
1497
  fill: "blue",
1251
1498
  shape: "ring",
1252
1499
  text: "HUE->KNX Kelvin",
1253
- payload: kelvinValue,
1500
+ payload: knxMsgPayload.payload,
1254
1501
  });
1255
1502
  }
1256
1503
  }
@@ -53,5 +53,6 @@ module.exports.fetchFromObject = function fetchFromObject(
53
53
  if (typeof _msg[_payloadPropName] === "object") return undefined;
54
54
  return _msg[_payloadPropName];
55
55
  };
56
+
56
57
  const DEFAULTTRANSLATIONINPUT =
57
58
  "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.23",
6
+ "version": "2.4.26",
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",