node-red-contrib-knx-ultimate 2.2.33 → 2.2.35

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,6 +6,14 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ **Version 2.2.35** - December 2023<br/>
10
+ - NEW: HUE Light Node: now it resumes the old status of all lights belonging to the selected group.<br/>
11
+
12
+ **Version 2.2.34** - December 2023<br/>
13
+ - NEW: HUE Light Node: there is a new tab that auto-generates the light entity for Home Assistant.<br/>
14
+ - HUE Light: resuming the last daytime status after nighttime, if the switch on behaviour at daytime is set to None.<br/>
15
+ - The new HUE Scene node has exited the BETA status and is now considered safe to be used.<br/>
16
+
9
17
  **Version 2.2.33** - December 2023<br/>
10
18
  - Quickfix: HUE Light: fixed an issue in the conversion of tunable white from Datapint 7.600 to mired and vice versa.<br/>
11
19
  - WARNING: the new HUE Scene node is to be considered **BETA (= in testing with user feedback)**.<br/>
@@ -242,6 +242,32 @@ module.exports = (RED) => {
242
242
  } catch (error) { }
243
243
  };
244
244
 
245
+ // Return an array of light belonging to the groupID
246
+ node.getAllLightsBelongingToTheGroup = async function getAllLightsBelongingToTheGroup(_groupID) {
247
+ if (node.hueAllResources === undefined || node.hueAllResources === null) return;
248
+ const retArr = [];
249
+ try {
250
+ await node.loadResourcesFromHUEBridge();
251
+ node.hueAllResources.forEach((res) => {
252
+ if (res.services !== undefined && res.services.length > 0) {
253
+ res.services.forEach((serv) => {
254
+ if (serv.rid === _groupID) {
255
+ if (res.children !== undefined) {
256
+ const children = res.children.filter((a) => a.rtype === "light");
257
+ for (let index = 0; index < children.length; index++) {
258
+ const element = children[index];
259
+ const oLight = node.hueAllResources.filter((a) => a.id === element.rid);
260
+ if (oLight !== null && oLight !== undefined) retArr.push({ groupID: _groupID, light: oLight });
261
+ }
262
+ }
263
+ }
264
+ });
265
+ }
266
+ });
267
+ return retArr;
268
+ } catch (error) { /* empty */ }
269
+ };
270
+
245
271
  // Returns the cached devices (node.hueAllResources) by type.
246
272
  node.getResources = function getResources(_rtype) {
247
273
  try {
@@ -15,6 +15,7 @@ const dptlib = require("../KNXEngine/src/dptlib");
15
15
  const payloadRounder = require("./utils/payloadManipulation");
16
16
  const loggerEngine = require("./utils/sysLogger.js");
17
17
 
18
+
18
19
  // Helpers
19
20
  const sortBy = (field) => (a, b) => {
20
21
  if (a[field] > b[field]) {
@@ -189,7 +189,7 @@
189
189
  $("#node-input-specifySwitchOnBrightness").empty().append(
190
190
  $("<option>")
191
191
  .val("no")
192
- .text("Last status")
192
+ .text("None")
193
193
  ).append(
194
194
  $("<option>")
195
195
  .val("yes")
@@ -222,7 +222,7 @@
222
222
  $("#node-input-specifySwitchOnBrightness").empty().append(
223
223
  $("<option>")
224
224
  .val("no")
225
- .text("Last status")
225
+ .text("None")
226
226
  );
227
227
  $("#node-input-enableDayNightLighting").empty().append(
228
228
  $("<option>")
@@ -655,11 +655,28 @@
655
655
  },
656
656
  paletteLabel: "Hue Light",
657
657
  oneditprepare: function () {
658
+ // $.post("banana", { func: "getNameAndTime" }, function (data) {
659
+ // //alert(data.body); // John
660
+ // }, "json");
661
+ try {
662
+ RED.sidebar.show("help");
663
+ } catch (error) { }
658
664
  onEditPrepare(this);
665
+ let node = this;
666
+ node.yamlEditor = RED.editor.createEditor({
667
+ id: 'aceEditor',
668
+ mode: 'ace/mode/text'
669
+ });
670
+ node.yamlEditor.session.setValue(yamelize());
671
+ $('[id*="node-input-"]').on('keyup change autocompletechange', function () {
672
+ try {
673
+ node.yamlEditor.session.setValue(yamelize());
674
+ } catch (error) {
675
+ }
676
+ });
659
677
  },
660
678
  oneditsave: function () {
661
679
  //RED.sidebar.removeTab("tabNRColor");
662
- //RED.sidebar.show("help");
663
680
  if ($("#node-input-enableNodePINS").val() === "yes") {
664
681
  this.outputs = 1;
665
682
  this.inputs = 1;
@@ -674,9 +691,6 @@
674
691
  }
675
692
  });
676
693
 
677
-
678
-
679
-
680
694
  function rgbHex(red, green, blue, alpha) {
681
695
  const toHex = (red, green, blue, alpha) => ((blue | green << 8 | red << 16) | 1 << 24).toString(16).slice(1) + alpha;
682
696
  const parseCssRgbString = (input) => {
@@ -747,6 +761,60 @@
747
761
 
748
762
  return toHex(red, green, blue, alpha);
749
763
  }
764
+ function yamelize() {
765
+ try {
766
+ // Get the HUE Node properties and transform it into yaml
767
+ let sYaml = '- name: "' + $("#node-input-name").val() + '"' + "\n";
768
+ sYaml += $("#node-input-GALightSwitch").val() != '' ? ' address: "' + $("#node-input-GALightSwitch").val() + '"' + "\n" : '';
769
+ sYaml += $("#node-input-GALightState").val() != '' ? ' state_address: "' + $("#node-input-GALightState").val() + '"' + "\n" : '';
770
+ sYaml += $("#node-input-GALightBrightness").val() != '' ? ' brightness_address: "' + $("#node-input-GALightBrightness").val() + '"' + "\n" : '';
771
+ sYaml += $("#node-input-GALightBrightnessState").val() != '' ? ' brightness_state_address: "' + $("#node-input-GALightBrightnessState").val() + '"' + "\n" : '';
772
+
773
+ //#region color_temperature_mode
774
+ // ----------------------------
775
+ if ($("#node-input-GALightHSVPercentage").val !== '') {
776
+
777
+ // color_temperature_mode: relative
778
+ sYaml += ' color_temperature_mode: relative' + '\n';
779
+ sYaml += ' color_temperature_address: "' + $("#node-input-GALightHSVPercentage").val() + '"\n';
780
+ sYaml += $("#node-input-GALightHSVState").val() != '' ? ' color_temperature_state_address: "' + $("#node-input-GALightHSVState").val() + '"' + "\n" : '';
781
+ sYaml += ' min_kelvin: 2200' + '\n';
782
+ sYaml += ' max_kelvin: 6500' + '\n';
783
+
784
+ } else if ($("#node-input-GALightKelvin").val() !== '') {
785
+
786
+ if ($("#node-input-dptLightKelvin").val() === '7.600') {
787
+ sYaml += ' color_temperature_mode: absolute' + '\n';
788
+ sYaml += ' color_temperature_address: "' + $("#node-input-GALightKelvin").val() + '"\n';
789
+ if ($("#node-input-dptLightKelvinState").val() === '7.600') {
790
+ // Add the status only if also 7.600
791
+ sYaml += $("#node-input-GALightKelvinState").val() != '' ? ' color_temperature_state_address: "' + $("#node-input-GALightKelvinState").val() + '"' + "\n" : '';
792
+ }
793
+ sYaml += ' min_kelvin: 2200' + '\n';
794
+ sYaml += ' max_kelvin: 6500' + '\n';
795
+
796
+ } else if ($("#node-input-dptLightKelvin").val() === '9.002') {
797
+
798
+ sYaml += ' color_temperature_mode: absolute_float' + '\n';
799
+ sYaml += ' color_temperature_address: "' + $("#node-input-GALightKelvin").val() + '"\n';
800
+ if ($("#node-input-dptLightKelvinState").val() === '9.002') {
801
+ // Add the status only if also 7.600
802
+ sYaml += $("#node-input-GALightKelvinState").val() != '' ? ' color_temperature_state_address: "' + $("#node-input-GALightKelvinState").val() + '"' + "\n" : '';
803
+ }
804
+ sYaml += ' min_kelvin: 2200' + '\n';
805
+ sYaml += ' max_kelvin: 6500' + '\n';
806
+
807
+ }
808
+ }
809
+ // ----------------------------
810
+ //#endregion
811
+
812
+ sYaml += $("#node-input-GALightColor").val() != '' ? ' color_address: "' + $("#node-input-GALightColor").val() + '"' + "\n" : '';
813
+ sYaml += $("#node-input-GALightColorState").val() != '' ? ' color_state_address: "' + $("#node-input-GALightColorState").val() + '"' + "\n" : '';
814
+
815
+ return (sYaml);
816
+ } catch (error) { }
817
+ }
750
818
 
751
819
  }())
752
820
 
@@ -795,30 +863,29 @@
795
863
  <br />
796
864
 
797
865
 
798
- <div id="tabs" style="width:680px" hidden>
866
+ <div id="tabs" hidden>
799
867
  <ul>
800
- <li><a href="#tabs-1">Switching</a></li>
801
- <li><a href="#tabs-2">Dim/Brightness</a></li>
802
- <li><a href="#tabs-3">Tunable white</a></li>
803
- <li><a href="#tabs-4">Colors</a></li>
804
- <li><a href="#tabs-5">Effects</a></li>
805
- <li><a href="#tabs-6">Behaviour</a></li>
868
+ <li><a href="#tabs-1"><i class="fa-solid fa-toggle-on fa-beat"></i> Switching</a></li>
869
+ <li><a href="#tabs-2"><i class="fa-solid fa-arrow-up-wide-short fa-beat"></i> Dim/Brightness</a></li>
870
+ <li><a href="#tabs-3"><i class="fa-solid fa-temperature-quarter fa-beat"></i> Tunable white</a></li>
871
+ <li><a href="#tabs-4"><i class="fa-solid fa-palette fa-beat"></i> Colors</a></li>
872
+ <li><a href="#tabs-5"><i class="fa-solid fa-heart-circle-check fa-beat"></i> Effects</a></li>
873
+ <li><a href="#tabs-6"><i class="fa-solid fa-code-merge fa-beat"></i> Behaviour</a></li>
874
+ <li><a href="#tabs-7"><i class="fa-solid fa-house fa-beat"></i> Home Assistant Export (beta)</a></li>
806
875
  </ul>
807
876
  <div id="tabs-1">
808
877
  <p>
809
878
  <div class="form-row">
810
879
  <label for="node-input-nameLightSwitch" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control</label>
811
880
 
812
- <label for="node-input-GALightSwitch" style="width:20px;"><span
813
- data-i18n="knxUltimateHueLight.node-input-GALightSwitch"></span></label>
881
+ <label for="node-input-GALightSwitch" style="width:20px;">GA</label>
814
882
  <input type="text" id="node-input-GALightSwitch" placeholder="Ex: 1/1/1"
815
883
  style="width:70px;margin-left: 5px; text-align: left;">
816
884
 
817
885
  <label for="node-input-dptLightSwitch" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
818
886
  <select id="node-input-dptLightSwitch" style="width:140px;"></select>
819
887
 
820
- <label for="node-input-nameLightSwitch" style="width:50px; margin-left: 0px; text-align: right;"><span
821
- data-i18n="knxUltimateHueLight.node-input-name"></span></label>
888
+ <label for="node-input-nameLightSwitch" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
822
889
  <input type="text" id="node-input-nameLightSwitch" style="width:190px;margin-left: 5px; text-align: left;">
823
890
  </div>
824
891
  <div class="form-row">
@@ -842,8 +909,7 @@
842
909
  <div class="form-row">
843
910
  <label for="node-input-nameLightDIM" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control</label>
844
911
 
845
- <label for="node-input-GALightDIM" style="width:20px;"><span
846
- data-i18n="knxUltimateHueLight.node-input-GALightState"></span></label>
912
+ <label for="node-input-GALightDIM" style="width:20px;">GA</label>
847
913
  <input type="text" id="node-input-GALightDIM" placeholder="Ex: 1/1/1"
848
914
  style="width:70px;margin-left: 5px; text-align: left;">
849
915
 
@@ -858,8 +924,7 @@
858
924
  <label for="node-input-nameLightBrightness" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control
859
925
  %</label>
860
926
 
861
- <label for="node-input-GALightBrightness" style="width:20px;"><span
862
- data-i18n="knxUltimateHueLight.node-input-GALightState"></span></label>
927
+ <label for="node-input-GALightBrightness" style="width:20px;">GA</label>
863
928
  <input type="text" id="node-input-GALightBrightness" placeholder="Ex: 1/1/1"
864
929
  style="width:70px;margin-left: 5px; text-align: left;">
865
930
 
@@ -939,8 +1004,7 @@
939
1004
  <label for="node-input-nameLightHSVState" style="width:110px;"><i class="fa fa-play-circle-o"></i> Status
940
1005
  %</label>
941
1006
 
942
- <label for="node-input-GALightHSVState" style="width:20px;"><span
943
- data-i18n="knxUltimateHueLight.node-input-GALightState"></span></label>
1007
+ <label for="node-input-GALightHSVState" style="width:20px;">GA</label>
944
1008
  <input type="text" id="node-input-GALightHSVState" placeholder="Ex: 1/1/1"
945
1009
  style="width:70px;margin-left: 5px; text-align: left;">
946
1010
 
@@ -1062,7 +1126,7 @@
1062
1126
  <i class="fa fa-tag"></i> Switch on behaviour
1063
1127
  </label>
1064
1128
  <select id="node-input-specifySwitchOnBrightness">
1065
- <option value="no">Last status</option>
1129
+ <option value="no">None</option>
1066
1130
  <!-- <option value="temperature">Select temperature and brightness</option>
1067
1131
  <option value="yes">Select color</option> -->
1068
1132
  </select>
@@ -1165,14 +1229,19 @@
1165
1229
  </div>
1166
1230
  </p>
1167
1231
  </div>
1232
+ <div id="tabs-7">
1233
+ <p>
1234
+ <br/> <b>YAML</b> <br/>
1235
+ <div style="height: 220px; min-height:150px;" class="node-text-editor" id="aceEditor"></div>
1236
+ <!-- <button type="button" class="red-ui-button">Button</button> -->
1237
+ </p>
1238
+ </div>
1168
1239
 
1169
1240
  <br />
1170
1241
  </script>
1171
1242
 
1172
1243
 
1173
1244
  <script type="text/markdown" data-help-name="knxUltimateHueLight">
1174
-
1175
-
1176
1245
  <p>This node lets you control your Philips HUE light and grouped lights and also gets the states of this lights, to be sent to the KNX bus.</p>
1177
1246
 
1178
1247
  **General**
@@ -1238,7 +1307,7 @@ Start typing in the GA field, the name or group address of your KNX device, the
1238
1307
  | Property | Description |
1239
1308
  | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1240
1309
  | KNX Brightness Status | Updates the KNX brightness group address status, whenever the HUE lamp is switched ON/OFF. The options are **When HUE light is Off send 0%. When HUE On, restore previous value (Default KNX behaviour)** and **Leave as is (default HUE behaviour)**. If you have KNX dimmer with brightness status, like MDT, the suggested option is ***When HUE light is Off send 0%. When HUE On, restore previous value (Default KNX behaviour)*** |
1241
- | Switch on behaviour | It sets the behaviour of your lights when switched on. You can choose from differents behaviours.<br/>**Select color:** the light will be switched on with the color of your choice. To change color, just CLICK on the color selector (under the *Select color* control).<br/>**Select temperature and brightness:** the light will be switched on with the temperature (Kelvin) and brightness (0-100) of your choice.<br>**Last status:** the light will be switched on in the last status. |
1310
+ | Switch on behaviour | It sets the behaviour of your lights when switched on. You can choose from differents behaviours.<br/>**Select color:** the light will be switched on with the color of your choice. To change color, just CLICK on the color selector (under the *Select color* control).<br/>**Select temperature and brightness:** the light will be switched on with the temperature (Kelvin) and brightness (0-100) of your choice.<br/>**None:** the light will retain its last status. In case you've enable the night lighting, after the night time ends, the lamp will resume the color/temperature/brightness state set at day time. |
1242
1311
  | Night Lighting | It allows to set a particular light color/brightness at nighttime. The options are the same as the daytime. You could select either a temperature/brightness or color. A cozy temperature of 2700 Kelvin, with a brightness of 10% or 20%, is a good choice for bathroom's night light.|
1243
1312
  | Day/Night | Select the group address used to set the day/night behaviour. The group address value is _true_ if daytime, _false_ if nighttime. |
1244
1313
  | Invert day/night values | Invert the values of _Day/Night_ group address. Default value is **unchecked**. |
@@ -1253,6 +1322,14 @@ The Dimming function works in **KNX mode `start` and `stop`**. To start dimming,
1253
1322
 
1254
1323
  <br/>
1255
1324
 
1325
+ **Home Assistant Export**
1326
+
1327
+ | Property | Description |
1328
+ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1329
+ | YAML | Get or sets the node properties based on Home Assistant YAML format. By editing the node properties, the YAML will automatically be created. You can copy and paste it into the "knx_lights.yaml" Home Assistant config file. Not yet implemented: likewise, if you copy the single light descriptor from the "knx_lights.yaml" Home Assistant config file and paste it here, the relative node properties will be automatically set. |
1330
+
1331
+ <br/>
1332
+
1256
1333
  [Find it useful?](https://www.paypal.me/techtoday)
1257
1334
 
1258
1335
  <br/>
@@ -2,6 +2,8 @@
2
2
  /* eslint-disable camelcase */
3
3
  /* eslint-disable max-len */
4
4
  /* eslint-disable no-lonely-if */
5
+ const cloneDeep = require("lodash/cloneDeep");
6
+
5
7
  module.exports = function (RED) {
6
8
  const dptlib = require("../KNXEngine/src/dptlib");
7
9
  const hueColorConverter = require("./utils/hueColorConverter");
@@ -31,6 +33,8 @@ module.exports = function (RED) {
31
33
  node.formatnegativevalue = "leave";
32
34
  node.formatdecimalsvalue = 2;
33
35
  node.currentHUEDevice = undefined; // At start, this value is filled by a call to HUE api. It stores a value representing the current light status.
36
+ node.HUEDeviceWhileDaytime = null;// This retains the HUE device status while daytime, to be restored after nighttime elapsed.
37
+ node.HUELightsBelongingToGroupWhileDaytime = null; // Array contains all light belonging to the grouped_light (if grouped_light is selected)
34
38
  node.DayTime = true;
35
39
  node.isGrouped_light = config.hueDevice.split("#")[1] === "grouped_light";
36
40
  node.hueDevice = config.hueDevice.split("#")[0];
@@ -100,57 +104,93 @@ module.exports = function (RED) {
100
104
  case config.GALightSwitch:
101
105
  msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightSwitch));
102
106
  if (msg.payload === true) {
103
- let colorChoosen;
104
- let temperatureChoosen;
105
- let brightnessChoosen;
106
- // The light must support the temperature (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
107
- if (node.currentHUEDevice.color_temperature !== undefined) {
108
- if (node.DayTime === true && config.specifySwitchOnBrightness === "temperature") {
109
- temperatureChoosen = config.colorAtSwitchOnDayTime.kelvin;
110
- } else if (node.DayTime === false && config.enableDayNightLighting === "temperature") {
111
- temperatureChoosen = config.colorAtSwitchOnNightTime.kelvin;
107
+ // From HUE Api core concepts:
108
+ // If you try and control multiple conflicting parameters at once e.g. {"color": {"xy": {"x":0.5,"y":0.5}}, "color_temperature": {"mirek": 250}}
109
+ // the lights can only physically do one, for this we apply the rule that xy beats ct. Simple.
110
+ // color_temperature.mirek: color temperature in mirek is null when the light color is not in the ct spectrum
111
+ if (node.DayTime === true && config.specifySwitchOnBrightness === "no") {
112
+ if (node.isGrouped_light === false && node.HUEDeviceWhileDaytime !== null) {
113
+ // The DayNight has switched into day, so restore the previous light status
114
+ state = { on: { on: true }, dimming: node.HUEDeviceWhileDaytime.dimming, color: node.HUEDeviceWhileDaytime.color, color_temperature: node.HUEDeviceWhileDaytime.color_temperature };
115
+ if (node.HUEDeviceWhileDaytime.color_temperature.mirek === null) delete state.color_temperature; // Otherwise the lamp will not turn on due to an error. color_temperature.mirek: color temperature in mirek is null when the light color is not in the ct spectrum
116
+ node.HUEDeviceWhileDaytime = null; // Nullize the object.
117
+ node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
118
+ node.setNodeStatusHue({
119
+ fill: "green",
120
+ shape: "dot",
121
+ text: "KNX->HUE",
122
+ payload: "Restore light status",
123
+ });
124
+ } else if (node.isGrouped_light === true && node.HUELightsBelongingToGroupWhileDaytime !== null) {
125
+ // The DayNight has switched into day, so restore the previous light state, belonging to the group
126
+ for (let index = 0; index < node.HUELightsBelongingToGroupWhileDaytime.length; index++) {
127
+ const element = node.HUELightsBelongingToGroupWhileDaytime[index].light[0];
128
+ state = { on: { on: true }, dimming: element.dimming, color: element.color, color_temperature: element.color_temperature };
129
+ if (element.color_temperature.mirek === null) delete state.color_temperature; // Otherwise the lamp will not turn on due to an error. color_temperature.mirek: color temperature in mirek is null when the light color is not in the ct spectrum
130
+ node.serverHue.hueManager.writeHueQueueAdd(element.id, state, "setLight");
131
+ }
132
+ node.HUELightsBelongingToGroupWhileDaytime = null; // Nullize the object.
133
+ node.setNodeStatusHue({
134
+ fill: "green",
135
+ shape: "dot",
136
+ text: "KNX->HUE",
137
+ payload: "Resuming all group's light",
138
+ });
139
+ return;
112
140
  }
113
- }
114
- if (node.currentHUEDevice.dimming !== undefined) {
115
- // Check wether the user selected specific brightness at switch on (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
116
- if (node.DayTime === true && config.specifySwitchOnBrightness === "temperature") {
117
- brightnessChoosen = config.colorAtSwitchOnDayTime.brightness;
118
- } else if (node.DayTime === false && config.enableDayNightLighting === "temperature") {
119
- brightnessChoosen = config.colorAtSwitchOnNightTime.brightness;
141
+ } else {
142
+ let colorChoosen;
143
+ let temperatureChoosen;
144
+ let brightnessChoosen;
145
+ // The light must support the temperature (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
146
+ if (node.currentHUEDevice.color_temperature !== undefined) {
147
+ if (node.DayTime === true && config.specifySwitchOnBrightness === "temperature") {
148
+ temperatureChoosen = config.colorAtSwitchOnDayTime.kelvin;
149
+ } else if (node.DayTime === false && config.enableDayNightLighting === "temperature") {
150
+ temperatureChoosen = config.colorAtSwitchOnNightTime.kelvin;
151
+ }
120
152
  }
121
- }
122
- if (node.currentHUEDevice.color !== undefined) {
123
- // Check wether the user selected specific color at switch on (in this case, colorAtSwitchOnDayTime is a text with HTML web color)
124
- if (node.DayTime === true && config.specifySwitchOnBrightness === "yes") {
125
- colorChoosen = config.colorAtSwitchOnDayTime;
126
- } else if (node.DayTime === false && config.enableDayNightLighting === "yes") {
127
- colorChoosen = config.colorAtSwitchOnNightTime;
153
+ if (node.currentHUEDevice.dimming !== undefined) {
154
+ // Check wether the user selected specific brightness at switch on (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
155
+ if (node.DayTime === true && config.specifySwitchOnBrightness === "temperature") {
156
+ brightnessChoosen = config.colorAtSwitchOnDayTime.brightness;
157
+ } else if (node.DayTime === false && config.enableDayNightLighting === "temperature") {
158
+ brightnessChoosen = config.colorAtSwitchOnNightTime.brightness;
159
+ }
128
160
  }
129
- }
130
-
131
- if (colorChoosen !== undefined) {
132
- // Now we have a jColorChoosen. Proceed illuminating the light
133
- let gamut = null;
134
- if (node.currentHUEDevice.color.gamut_type !== undefined) {
135
- gamut = node.currentHUEDevice.color.gamut_type;
161
+ if (node.currentHUEDevice.color !== undefined) {
162
+ // Check wether the user selected specific color at switch on (in this case, colorAtSwitchOnDayTime is a text with HTML web color)
163
+ if (node.DayTime === true && config.specifySwitchOnBrightness === "yes") {
164
+ colorChoosen = config.colorAtSwitchOnDayTime;
165
+ } else if (node.DayTime === false && config.enableDayNightLighting === "yes") {
166
+ colorChoosen = config.colorAtSwitchOnNightTime;
167
+ }
168
+ }
169
+ // Create the HUE command
170
+ if (colorChoosen !== undefined) {
171
+ // Now we have a jColorChoosen. Proceed illuminating the light
172
+ let gamut = null;
173
+ if (node.currentHUEDevice.color.gamut_type !== undefined) {
174
+ gamut = node.currentHUEDevice.color.gamut_type;
175
+ }
176
+ const dretXY = hueColorConverter.ColorConverter.rgbToXy(colorChoosen.red, colorChoosen.green, colorChoosen.blue, gamut);
177
+ const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(colorChoosen.red, colorChoosen.green, colorChoosen.blue);
178
+ node.currentHUEDevice.dimming.brightness = Math.round(dbright, 0);
179
+ node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
180
+ state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } };
181
+ } else if (temperatureChoosen !== undefined) {
182
+ // Kelvin
183
+ const mirek = hueColorConverter.ColorConverter.kelvinToMirek(temperatureChoosen);
184
+ node.currentHUEDevice.color_temperature.mirek = mirek;
185
+ node.currentHUEDevice.dimming.brightness = brightnessChoosen;
186
+ node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
187
+ // Kelvin temp
188
+ state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen }, color_temperature: { mirek: mirek } } : { on: { on: false } };
189
+ } else if (brightnessChoosen !== undefined) {
190
+ state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen } } : { on: { on: false } };
191
+ } else {
192
+ state = { on: { on: true } };
136
193
  }
137
- const dretXY = hueColorConverter.ColorConverter.rgbToXy(colorChoosen.red, colorChoosen.green, colorChoosen.blue, gamut);
138
- const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(colorChoosen.red, colorChoosen.green, colorChoosen.blue);
139
- node.currentHUEDevice.dimming.brightness = Math.round(dbright, 0);
140
- node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
141
- state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } };
142
- } else if (temperatureChoosen !== undefined) {
143
- // Kelvin
144
- const mirek = hueColorConverter.ColorConverter.kelvinToMirek(temperatureChoosen);
145
- node.currentHUEDevice.color_temperature.mirek = mirek;
146
- node.currentHUEDevice.dimming.brightness = brightnessChoosen;
147
- node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
148
- // Kelvin temp
149
- state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen }, color_temperature: { mirek: mirek } } : { on: { on: false } };
150
- } else if (brightnessChoosen !== undefined) {
151
- state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen } } : { on: { on: false } };
152
- } else {
153
- state = { on: { on: true } };
154
194
  }
155
195
  } else {
156
196
  state = { on: { on: false } };
@@ -202,6 +242,23 @@ module.exports = function (RED) {
202
242
  case config.GADaylightSensor:
203
243
  node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)));
204
244
  if (config.invertDayNight !== undefined && config.invertDayNight === true) node.DayTime = !node.DayTime;
245
+ if (config.specifySwitchOnBrightness === "no") {
246
+ // This retains the HUE device status while daytime, to be restored after nighttime elapsed. https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/298
247
+ if (node.DayTime === false) {
248
+ if (node.isGrouped_light === false) node.HUEDeviceWhileDaytime = cloneDeep(node.currentHUEDevice); // DayTime has switched to false: save the currentHUEDevice into the HUEDeviceWhileDaytime
249
+ if (node.isGrouped_light === true) {
250
+ (async () => {
251
+ try {
252
+ const retLights = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice);
253
+ node.HUELightsBelongingToGroupWhileDaytime = cloneDeep(retLights); // DayTime has switched to false: save the lights belonging to the group into the HUELightsBelongingToGroupWhileDaytime array
254
+ } catch (error) { }
255
+ })();
256
+ }
257
+ }
258
+ } else {
259
+ node.HUEDeviceWhileDaytime = null;
260
+ node.HUELightsBelongingToGroupWhileDaytime = null;
261
+ }
205
262
  node.setNodeStatusHue({
206
263
  fill: "green",
207
264
  shape: "dot",
@@ -0,0 +1,38 @@
1
+ <script type="text/javascript">
2
+
3
+ // Aggiungere questo JSON al package.json
4
+ // "plugins": {
5
+ // "sidebar-plugin": "/nodes/plugins/HomeAssistantImporter-sidebar-plugin.html"
6
+ // }
7
+ (function () {
8
+ RED.plugins.registerPlugin("HomeAssistantImporter-sidebar-plugin", {
9
+ onadd: function () {
10
+
11
+ //#region Create Home Assistant Import TAB on the left tabs.
12
+ // The sidebar content
13
+ const content = $("<div>").css({ "position": "relative", "height": "100%" });
14
+
15
+ // (optional) A toolbar header for the sidebar
16
+ const header = $("<div>", { class: "red-ui-sidebar-header" }).appendTo(content);
17
+ // const textarea = "<textarea rows="20" id="node - config - input - csv" style="width: 100 % "
18
+ // data - i18n="[placeholder]knxUltimate-config.ets.ga_list_help" ></textarea > "
19
+
20
+ RED.actions.add("HAImporterTab:show-custom-tab", function () {
21
+ RED.sidebar.show("HAImporterTab");
22
+ });
23
+
24
+ if (RED.sidebar.containsTab('HAImporterTab')) RED.sidebar.removeTab("HAImporterTab");
25
+ RED.sidebar.addTab({
26
+ id: "HAImporterTab",
27
+ label: "custom",
28
+ name: "Home Assistant importer",
29
+ iconClass: "fa fa-database",
30
+ content: content,
31
+ action: "HAImporterTab:show-custom-tab"
32
+ });
33
+ //#endregion
34
+
35
+ }
36
+ })
37
+ })();
38
+ </script>
@@ -0,0 +1,21 @@
1
+ // Utility function
2
+ // until node-red 3.1.0, there is a bug creating a plugin, so for backward compatibility, i must use a JS as a node.
3
+ const yaml = require('js-yaml');
4
+ module.exports = function (RED) {
5
+
6
+ //RED.log.error("###############################################################")
7
+ RED.httpAdmin.post("/banana", RED.auth.needsPermission("write"), (req, res) => {
8
+ var node = RED.nodes.getNode(req.params.id);
9
+ if (node != null) {
10
+ try {
11
+ if (req.body) {
12
+ console.log(body);
13
+ }
14
+ } catch (err) { }
15
+ }
16
+ res.json(req.body)
17
+ })
18
+
19
+
20
+ }
21
+
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=16.0.0"
5
5
  },
6
- "version": "2.2.33",
6
+ "version": "2.2.35",
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",
@@ -17,12 +17,13 @@
17
17
  "path": "0.12.7",
18
18
  "ping": "0.4.4",
19
19
  "simple-get": "4.0.1",
20
- "xml2js": "0.6.0"
20
+ "xml2js": "0.6.0",
21
+ "js-yaml": "4.1.0"
21
22
  },
22
-
23
23
  "node-red": {
24
24
  "version": ">=2.0.0",
25
25
  "nodes": {
26
+ "commonFunctions": "/nodes/utils/commonFunctions.js",
26
27
  "knxUltimate": "/nodes/knxUltimate.js",
27
28
  "knxUltimateSceneController": "/nodes/knxUltimateSceneController.js",
28
29
  "knxUltimateWatchDog": "/nodes/knxUltimateWatchDog.js",
@@ -91,4 +92,4 @@
91
92
  "editor.defaultFormatter": "vscode.html-language-features"
92
93
  }
93
94
  }
94
- }
95
+ }
Binary file