node-red-contrib-knx-ultimate 2.2.26 → 2.2.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 CHANGED
@@ -6,6 +6,18 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ **Version 2.2.28** - November 2023<br/>
10
+ This is an interim version, to quick fix some issues. Please report any issue with HUE Nodes, on gitHub.<br/>
11
+ - HUE Light: fixed an issue where dimming down with the light switched off, causes the brightness status to jump to 100%, thus the light remains off.<br/>
12
+ - HUE Light: Fixed some errors, if all devices belonging to a group, have only the dimming capability.<br/>
13
+ - WARNING: the new HUE Light options are to be considered **BETA (= in testing with user feedback)**.<br/>
14
+
15
+ **Version 2.2.27** - November 2023<br/>
16
+ This is an interim version, to quick fix some issues. Please report any issue with HUE Nodes, on gitHub.<br/>
17
+ - HUE Light: the UI now changes, to adapt to lamp type.<br/>
18
+ - HUE Light: "Get current" color button, now works for grouped light as well, by reading the first light belongin to the group.<br/>
19
+ - WARNING: the new HUE Light options are to be considered **BETA (= in testing with user feedback)**.<br/>
20
+
9
21
  **Version 2.2.26** - November 2023<br/>
10
22
  This is an interim version, to quick fix some issues. Please report any issue with HUE Nodes, on gitHub.<br/>
11
23
  - HUE Light: fixed some spurious node status errors.<br/>
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-underscore-dangle */
1
2
  /* eslint-disable no-lonely-if */
2
3
  /* eslint-disable no-param-reassign */
3
4
  /* eslint-disable no-inner-declarations */
@@ -170,7 +171,7 @@ module.exports = (RED) => {
170
171
  // Query the HUE Bridge to return the resources
171
172
  node.loadResourcesFromHUEBridge = async () => {
172
173
  if (node.linkStatus === "disconnected") return;
173
- //(async () => {
174
+ // (async () => {
174
175
  // °°°°°° Load ALL resources
175
176
  try {
176
177
  node.hueAllResources = await node.hueManager.hueApiV2.get("/resource");
@@ -226,24 +227,19 @@ module.exports = (RED) => {
226
227
  node.getFirstLightInGroup = function getFirstLightInGroup(_groupID) {
227
228
  if (node.hueAllResources === undefined || node.hueAllResources === null) return;
228
229
  try {
229
- // Find the group
230
230
  const group = node.hueAllResources.filter((a) => a.id === _groupID)[0];
231
- if (group === null || group === undefined) return;
232
231
  const owner = node.hueAllResources.filter((a) => a.id === group.owner.rid)[0];
233
- if (owner.children !== undefined && owner.children.length > 0) {
234
- const firstLightId = owner.children.find((a) => a.rtype === "light").rid;
235
- if (firstLightId !== undefined && firstLightId !== null) {
236
- const firstLight = node.hueAllResources.find((a) => a.id === firstLightId);
237
- if (firstLight !== null && firstLight !== undefined) {
238
- return firstLight;
239
- } else {
240
- return;
241
- }
232
+ if (owner.children !== undefined) {
233
+ const dev = node.hueAllResources.filter((a) => a.id === owner.children[0].rid)[0];
234
+ if (dev.type === "device" && dev.services !== undefined) {
235
+ const lightID = dev.services.filter((a) => a.rtype === 'light')[0].rid;
236
+ const oLight = node.hueAllResources.filter((a) => a.id === lightID)[0];
237
+ return oLight;
238
+ } else if (dev.type === "light") {
239
+ return dev;
242
240
  }
243
241
  }
244
- } catch (error) {
245
-
246
- }
242
+ } catch (error) { }
247
243
  };
248
244
 
249
245
  // Returns the cached devices (node.hueAllResources) by type.
@@ -445,18 +441,64 @@ module.exports = (RED) => {
445
441
 
446
442
  RED.httpAdmin.get("/knxUltimateGetHueColor", RED.auth.needsPermission("hue-config.read"), (req, res) => {
447
443
  try {
448
- const hexColor = node.getColorFromHueLight(req.query.id);
449
- res.json(hexColor);
444
+ // find wether the light is a light or is grouped_light
445
+ let hexColor;
446
+ const _oDevice = node.hueAllResources.filter((a) => a.id === req.query.id)[0];
447
+ if (_oDevice.type === "light") {
448
+ hexColor = node.getColorFromHueLight(req.query.id);
449
+ } else {
450
+ // grouped_light, get the first light in the group
451
+ const oLight = node.getFirstLightInGroup(_oDevice.id);
452
+ hexColor = node.getColorFromHueLight(oLight.id);
453
+ }
454
+ res.json(hexColor !== undefined ? hexColor : "Select the device first!");
450
455
  } catch (error) {
451
456
  res.json("Select the device first!");
452
457
  }
453
458
  });
454
459
  RED.httpAdmin.get("/knxUltimateGetKelvinColor", RED.auth.needsPermission("hue-config.read"), (req, res) => {
455
460
  try {
456
- const jKelvin = node.getKelvinFromHueLight(req.query.id);
457
- res.json(jKelvin);
461
+ // find wether the light is a light or is grouped_light
462
+ let kelvinValue;
463
+ const _oDevice = node.hueAllResources.filter((a) => a.id === req.query.id)[0];
464
+ if (_oDevice.type === "light") {
465
+ kelvinValue = node.getKelvinFromHueLight(req.query.id);
466
+ } else {
467
+ // grouped_light, get the first light in the group
468
+ const oLight = node.getFirstLightInGroup(_oDevice.id);
469
+ kelvinValue = node.getKelvinFromHueLight(oLight.id);
470
+ }
471
+ res.json(kelvinValue !== undefined ? kelvinValue : "Select the device first!");
458
472
  } catch (error) {
459
473
  res.json("Select the device first!");
474
+ };
475
+ });
476
+
477
+ RED.httpAdmin.get("/knxUltimateGetLightObject", RED.auth.needsPermission("hue-config.read"), (req, res) => {
478
+ try {
479
+ const _lightId = req.query.id;
480
+ const oLight = node.hueAllResources.filter((a) => a.id === _lightId)[0];
481
+ // Infer some useful info, so the HTML part cann avoid to query the server
482
+ // Kelvin
483
+ try {
484
+ if (oLight.color_temperature !== undefined && oLight.color_temperature.mirek !== undefined) {
485
+ oLight.calculatedKelvin = hueColorConverter.ColorConverter.mirekToKelvin(oLight.color_temperature.mirek);
486
+ }
487
+ } catch (error) {
488
+ oLight.calculatedKelvin = undefined;
489
+ }
490
+ // HEX value from XYBri
491
+ try {
492
+ const retRGB = hueColorConverter.ColorConverter.xyBriToRgb(oLight.color.xy.x, oLight.color.xy.y, oLight.dimming.brightness);
493
+ const ret = "#" + hueColorConverter.ColorConverter.rgbHex(retRGB.r, retRGB.g, retRGB.b).toString();
494
+ oLight.calculatedHEXColor = ret;
495
+ } catch (error) {
496
+ oLight.calculatedHEXColor = undefined;
497
+ }
498
+ res.json(oLight);
499
+ } catch (error) {
500
+ if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: knxUltimateGetLightObject: error ${error.message}. Resources still loading. Try later.`);
501
+ res.json({});
460
502
  }
461
503
  });
462
504
 
@@ -486,6 +528,15 @@ module.exports = (RED) => {
486
528
  }
487
529
  });
488
530
 
531
+ RED.httpAdmin.get("/knxUltimateGetFirstLightInGroup", RED.auth.needsPermission("hue-config.read"), (req, res) => {
532
+ try {
533
+ res.json(node.getFirstLightInGroup(req.query.id));
534
+ } catch (error) {
535
+ if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: knxUltimateGetFirstLightInGroup: error ${error.message}`);
536
+ res.json({});
537
+ }
538
+ });
539
+
489
540
  RED.httpAdmin.get("/knxUltimateDpts", RED.auth.needsPermission("hue-config.read"), (req, res) => {
490
541
  try {
491
542
  const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy("base")).reduce(toConcattedSubtypes, []);
@@ -1,108 +1,14 @@
1
1
  <!-- <script type="application/javascript;charset=utf-8" src="https://kit.fontawesome.com/11f26b4500.js" crossorigin="anonymous"></script>
2
2
  <script type="application/javascript;charset=utf-8" src="https://cdn.jsdelivr.net/npm/@jaames/iro@5"></script> -->
3
+
4
+ 'use strict'
3
5
  <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
4
6
 
5
7
  <script type="text/javascript">
8
+ (function () {
6
9
 
7
- RED.nodes.registerType("knxUltimateHueLight", {
8
- category: "KNX Ultimate",
9
- color: "#C0C7E9",
10
- defaults: {
11
- //buttonState: {value: true},
12
- server: { type: "knxUltimate-config", required: false },
13
- serverHue: { type: "hue-config", required: true },
14
- name: { value: "" },
15
-
16
- nameLightSwitch: { value: "" },
17
- GALightSwitch: { value: "" },
18
- dptLightSwitch: { value: "" },
19
-
20
- nameLightState: { value: "" },
21
- GALightState: { value: "" },
22
- dptLightState: { value: "" },
23
-
24
- nameLightDIM: { value: "" },
25
- GALightDIM: { value: "" },
26
- dptLightDIM: { value: "" },
27
-
28
- nameLightColor: { value: "" },
29
- GALightColor: { value: "" },
30
- dptLightColor: { value: "" },
31
-
32
- nameLightColorState: { value: "" },
33
- GALightColorState: { value: "" },
34
- dptLightColorState: { value: "" },
35
-
36
- nameLightHSV: { value: "" },
37
- GALightHSV: { value: "" },
38
- dptLightHSV: { value: "" },
39
-
40
- nameLightHSVPercentage: { value: "" },
41
- GALightHSVPercentage: { value: "" },
42
- dptLightHSVPercentage: { value: "" },
43
-
44
- nameLightHSVState: { value: "" },
45
- GALightHSVState: { value: "" },
46
- dptLightHSVState: { value: "" },
47
-
48
- nameLightBrightness: { value: "" },
49
- GALightBrightness: { value: "" },
50
- dptLightBrightness: { value: "" },
51
-
52
- nameLightBrightnessState: { value: "" },
53
- GALightBrightnessState: { value: "" },
54
- dptLightBrightnessState: { value: "" },
55
-
56
- nameLightBlink: { value: "" },
57
- GALightBlink: { value: "" },
58
- dptLightBlink: { value: "" },
59
-
60
- nameLightColorCycle: { value: "" },
61
- GALightColorCycle: { value: "" },
62
- dptLightColorCycle: { value: "" },
63
-
64
- nameDaylightSensor: { value: "" },
65
- GADaylightSensor: { value: "" },
66
- dptDaylightSensor: { value: "" },
67
-
68
- nameLightKelvin: { value: "" },
69
- GALightKelvin: { value: "" },
70
- dptLightKelvin: { value: "" },
71
-
72
- nameLightKelvinState: { value: "" },
73
- GALightKelvinState: { value: "" },
74
- dptLightKelvinState: { value: "" },
75
-
76
- specifySwitchOnBrightness: { value: "temperature" },
77
- colorAtSwitchOnDayTime: { value: '{"kelvin":3000, "brightness":100 }' },
78
-
79
- enableDayNightLighting: { value: "no" },
80
- colorAtSwitchOnNightTime: { value: '{ "kelvin":2700, "brightness":20 }' },
81
-
82
- invertDayNight: { value: false },
83
-
84
- updateKNXBrightnessStatusOnHUEOnOff: { value: "no" },
85
- dimSpeed: { value: 5000, required: false },
86
- minDimLevelLight: { value: 10, required: false },
87
- maxDimLevelLight: { value: 100, required: false },
88
- readStatusAtStartup: { value: "yes" },
89
- enableNodePINS: { value: "no" },
90
-
91
- outputs: { value: 0 },
92
- inputs: { value: 0 },
93
-
94
- hueDevice: { value: "" },
95
- hueDeviceObject: { value: {} },
96
- },
97
- inputs: 0,
98
- outputs: 0,
99
- icon: "node-hue-icon.svg",
100
- label: function () {
101
- return this.name;
102
- },
103
- paletteLabel: "Hue Light (beta)",
104
- oneditprepare: function () {
105
- var node = this;
10
+ function onEditPrepare(node) {
11
+ // var node = node;
106
12
  var oNodeServer = RED.nodes.node($("#node-input-server").val()); // Store the config-node
107
13
  var oNodeServerHue = RED.nodes.node($("#node-input-serverHue").val()); // Store the config-node
108
14
 
@@ -134,19 +40,19 @@
134
40
  // 19/02/2020 Used to get the server sooner als deploy.
135
41
  $("#node-input-server").change(function () {
136
42
  try {
137
- oNodeServer = RED.nodes.node($(this).val());
43
+ oNodeServer = RED.nodes.node($(node).val());
138
44
  } catch (error) { }
139
45
  });
140
46
  // 19/02/2020 Used to get the server sooner als deploy.
141
47
  $("#node-input-serverHue").change(function () {
142
48
  try {
143
- oNodeServerHue = RED.nodes.node($(this).val());
49
+ oNodeServerHue = RED.nodes.node($(node).val());
144
50
  } catch (error) { }
145
51
  });
146
52
 
147
53
  // 31/03/2020 Search Helper
148
54
  function fullSearch(sourceText, searchString) {
149
- // This searches for all words in a string
55
+ // node searches for all words in a string
150
56
  var aSearchWords = searchString.toLowerCase().split(" ");
151
57
  var i = 0;
152
58
  for (let index = 0; index < aSearchWords.length; index++) {
@@ -158,6 +64,7 @@
158
64
  function getDPT(_dpt, _destinationWidget) {
159
65
  // DPT Switch command
160
66
  // ########################
67
+ $(_destinationWidget).empty();
161
68
  $.getJSON("knxUltimateDpts", (data) => {
162
69
  data.forEach((dpt) => {
163
70
  if (dpt.value.startsWith(_dpt)) {
@@ -172,7 +79,7 @@
172
79
  }
173
80
  });
174
81
  // Eval
175
- const format = "this." + _destinationWidget.replace("#node-input-", "");
82
+ const format = "node." + _destinationWidget.replace("#node-input-", "");
176
83
  try {
177
84
  if (format !== undefined) $(_destinationWidget).val(eval(format).toString());
178
85
  } catch (error) { }
@@ -267,57 +174,138 @@
267
174
  getGroupAddress("#node-input-GALightKelvinState", "#node-input-nameLightKelvinState", "#node-input-dptLightKelvinState", " 9.002");
268
175
 
269
176
 
177
+ // Get the HUE capabilities to enable/disable UI parts
178
+ $.getJSON("knxUltimateGetLightObject?id=" + $("#node-input-hueDevice").val().split("#")[0], (data) => {
179
+ let oLight = data;
180
+ // Check if grouped, to hide/show the "Get current" buttons
181
+ if (oLight.type === "grouped_light") {
182
+ $("#tabs").tabs("enable", "#tabs-4");
183
+ $("#tabs").tabs("enable", "#tabs-3");
184
+ $("#tabs").tabs("enable", "#tabs-2");
185
+ $("#getColorAtSwitchOnDayTimeButton").show();
186
+ $("#getColorAtSwitchOnNightTimeButton").show();
187
+ $("#node-input-specifySwitchOnBrightness").empty().append(
188
+ $("<option>")
189
+ .val("no")
190
+ .text("Last status")
191
+ ).append(
192
+ $("<option>")
193
+ .val("yes")
194
+ .text("Select color")
195
+ ).append(
196
+ $("<option>")
197
+ .val("temperature")
198
+ .text("Select temperature and brightness")
199
+ );
200
+ $("#node-input-enableDayNightLighting").empty().append(
201
+ $("<option>")
202
+ .val("no")
203
+ .text("No")
204
+ ).append(
205
+ $("<option>")
206
+ .val("yes")
207
+ .text("Select color")
208
+ ).append(
209
+ $("<option>")
210
+ .val("temperature")
211
+ .text("Select temperature and brightness")
212
+ );
213
+ $("#node-input-specifySwitchOnBrightness").val(node.specifySwitchOnBrightness).trigger('change');
214
+ $("#node-input-enableDayNightLighting").val(node.enableDayNightLighting).trigger('change');
215
+ return;
216
+ } else {
270
217
 
271
- // Autocomplete suggestion with HUE Lights
272
- $("#node-input-name").autocomplete({
273
- minLength: 1,
274
- source: function (request, response) {
275
- $.getJSON("KNXUltimateGetResourcesHUE?rtype=light&nodeID=" + oNodeServerHue.id, (data) => {
276
- response(
277
- $.map(data.devices, function (value, key) {
278
- //alert(JSON.stringify(value) + " "+ key)
279
- var sSearch = value.name;
280
- if (!value.name.includes("I'm still connecting")) {
281
- if (fullSearch(sSearch, request.term)) {
282
- return {
283
- hueDevice: value.id,
284
- value: value.name,
285
- };
286
- } else {
287
- return null;
288
- }
289
- } else {
290
- return {
291
- hueDevice: value.id,
292
- value: value.name,
293
- };
294
- }
295
- })
296
- );
297
- });
298
- },
299
- select: function (event, ui) {
300
- // Distinguish between group of lights an single light.
301
- if (ui.item.value.toLowerCase().startsWith("grouped_light")) {
302
- $("#node-input-hueDevice").val(ui.item.hueDevice + "#grouped_light");
303
- $("#getColorAtSwitchOnDayTimeButton").hide();
304
- $("#getColorAtSwitchOnNightTimeButton").hide();
305
- } else {
306
- $("#node-input-hueDevice").val(ui.item.hueDevice + "#light");
307
- $("#getColorAtSwitchOnDayTimeButton").show();
308
- $("#getColorAtSwitchOnNightTimeButton").show();
309
- }
310
- $("#tabs").show();
311
- },
218
+ $("#getColorAtSwitchOnDayTimeButton").show();
219
+ $("#getColorAtSwitchOnNightTimeButton").show();
220
+ $("#node-input-specifySwitchOnBrightness").empty().append(
221
+ $("<option>")
222
+ .val("no")
223
+ .text("Last status")
224
+ );
225
+ $("#node-input-enableDayNightLighting").empty().append(
226
+ $("<option>")
227
+ .val("no")
228
+ .text("No")
229
+ );
230
+ }
231
+ $("#tabs").tabs("disable", "#tabs-4");
232
+ $("#tabs").tabs("disable", "#tabs-3");
233
+ $("#tabs").tabs("disable", "#tabs-2");
234
+ $("#divColorsAtSwitchOn").hide();
235
+ $("#divColorsAtSwitchOnNightTime").hide();
236
+ $("#divTemperatureAtSwitchOn").hide();
237
+ $("#divTemperatureAtSwitchOnNightTime").hide();
238
+ $("#divColorCycle").hide();
239
+ $("#divUpdateKNXBrightnessStatusOnHUEOnOff").hide();
240
+ $("#divMinMaxBrightness").hide();
241
+ $("#comboTemperatureAtSwitchOn").hide();
242
+ $("#comboTemperatureAtSwitchOnNightTime").hide();
243
+
244
+ // Enable options/tabs one by one
245
+ if (oLight.color !== undefined) {
246
+ $("#tabs").tabs("enable", "#tabs-4");
247
+ $("#divColorsAtSwitchOn").show();
248
+ $("#divColorsAtSwitchOnNightTime").show();
249
+ $("#divColorCycle").show();
250
+ $("#node-input-specifySwitchOnBrightness").append(
251
+ $("<option>")
252
+ .val("yes")
253
+ .text("Select color")
254
+ );
255
+ $("#node-input-enableDayNightLighting").append(
256
+ $("<option>")
257
+ .val("yes")
258
+ .text("Select color")
259
+ );
260
+ }
261
+ // Check temperature (if the light supports temperature, it support dimming as well)
262
+ if (oLight.color_temperature !== undefined) {
263
+ $("#tabs").tabs("enable", "#tabs-3");
264
+ $("#tabs").tabs("enable", "#tabs-2");
265
+ $("#node-input-specifySwitchOnBrightness").append(
266
+ $("<option>")
267
+ .val("temperature")
268
+ .text("Select temperature and brightness")
269
+ );
270
+ $("#node-input-enableDayNightLighting").append(
271
+ $("<option>")
272
+ .val("temperature")
273
+ .text("Select temperature and brightness")
274
+ );
275
+ $("#divTemperatureAtSwitchOn").show();
276
+ $("#divTemperatureAtSwitchOnNightTime").show();
277
+ $("#divUpdateKNXBrightnessStatusOnHUEOnOff").show();
278
+ $("#divMinMaxBrightness").show();
279
+ $("#comboTemperatureAtSwitchOn").show();
280
+ $("#comboTemperatureAtSwitchOnNightTime").show();
281
+ } else {
282
+ $("#tabs").tabs("enable", "#tabs-2");
283
+ $("#node-input-specifySwitchOnBrightness").append(
284
+ $("<option>")
285
+ .val("temperature")
286
+ .text("Select brightness")
287
+ );
288
+ $("#node-input-enableDayNightLighting").append(
289
+ $("<option>")
290
+ .val("temperature")
291
+ .text("Select brightness")
292
+ );
293
+ $("#comboTemperatureAtSwitchOn").val(0);
294
+ $("#comboTemperatureAtSwitchOnNightTime").val(0);
295
+ $("#divTemperatureAtSwitchOn").show();
296
+ $("#divTemperatureAtSwitchOnNightTime").show();
297
+ $("#divUpdateKNXBrightnessStatusOnHUEOnOff").show();
298
+ $("#divMinMaxBrightness").show();
299
+ }
300
+ $("#node-input-specifySwitchOnBrightness").val(node.specifySwitchOnBrightness).trigger('change');
301
+ $("#node-input-enableDayNightLighting").val(node.enableDayNightLighting).trigger('change');
312
302
  });
313
303
 
314
-
315
-
316
304
  // Show/Hide the div of the color at swich on
317
- if (this.specifySwitchOnBrightness === "yes") {
305
+ if (node.specifySwitchOnBrightness === "yes") {
318
306
  $("#divColorsAtSwitchOn").show();
319
307
  $("#divTemperatureAtSwitchOn").hide();
320
- } else if (this.specifySwitchOnBrightness === "temperature") {
308
+ } else if (node.specifySwitchOnBrightness === "temperature") {
321
309
  $("#divColorsAtSwitchOn").hide();
322
310
  $("#divTemperatureAtSwitchOn").show();
323
311
  } else {
@@ -340,12 +328,12 @@
340
328
  });
341
329
 
342
330
  // Show/Hide and enable/disable day/night Lighting behaviour
343
- if (this.enableDayNightLighting === "yes") {
331
+ if (node.enableDayNightLighting === "yes") {
344
332
  $("#divEnableDayNightLighting").show();
345
333
  $("#divCCSBoxAtNightLighting").css({ border: "1px solid dimgrey", "border-radius": "12px", padding: "5px" }); // Add little box to better understand the property page
346
334
  $("#divColorsAtSwitchOnNightTime").show();
347
335
  $("#divTemperatureAtSwitchOnNightTime").hide();
348
- } else if (this.enableDayNightLighting === "temperature") {
336
+ } else if (node.enableDayNightLighting === "temperature") {
349
337
  $("#divEnableDayNightLighting").show();
350
338
  $("#divCCSBoxAtNightLighting").css({ border: "1px solid dimgrey", "border-radius": "12px", padding: "5px" }); // Add little box to better understand the property page
351
339
  $("#divColorsAtSwitchOnNightTime").hide();
@@ -374,79 +362,6 @@
374
362
  }
375
363
  });
376
364
 
377
-
378
- // Get the HUE capabilities to enable/disable UI parts
379
- $.getJSON("KNXUltimateGetResourcesHUE?rtype=light&nodeID=" + oNodeServerHue.id, (data) => {
380
- data.devices.forEach((element) => {
381
- if (element.id === this.hueDevice.split("#")[0] && element.deviceObject !== undefined) {
382
-
383
- // Check color
384
- if (element.deviceObject.color_temperature === undefined) $("#tabs").tabs("disable", "#tabs-3");
385
- if (element.deviceObject.color === undefined || JSON.stringify(deviceObject.color) === "{}") {
386
- $("#tabs").tabs("disable", "#tabs-4");
387
- $("#divColorsAtSwitchOn").hide();
388
- $("#divColorCycle").hide();
389
- $("#node-input-specifySwitchOnBrightness").empty().append(
390
- $("<option>")
391
- .val("no")
392
- .text("Last status")
393
- ).append(
394
- $("<option>")
395
- .val("temperature")
396
- .text("Select temperature and brightness")
397
- );
398
- $("#node-input-specifySwitchOnBrightness").val(this.specifySwitchOnBrightness).trigger('change');
399
-
400
- $("#node-input-enableDayNightLighting").empty().append(
401
- $("<option>")
402
- .val("no")
403
- .text("Last status")
404
- ).append(
405
- $("<option>")
406
- .val("temperature")
407
- .text("Select temperature and brightness")
408
- );
409
- $("#node-input-enableDayNightLighting").val(this.enableDayNightLighting).trigger('change');
410
- }
411
-
412
- // Check dimming
413
- if (element.deviceObject.dimming === undefined) {
414
- $("#tabs").tabs("disable", "#tabs-2");
415
- $("#divColorsAtSwitchOn").hide();
416
- $("#divColorCycle").hide();
417
- $("#divUpdateKNXBrightnessStatusOnHUEOnOff").hide();
418
- $("#divCCSBoxAtNightLighting").hide();
419
- $("#node-input-specifySwitchOnBrightness").val("no");
420
- $("#node-input-enableDayNightLighting").val("no");
421
- $("#divMinMaxBrightness").hide();
422
- $("#node-input-specifySwitchOnBrightness").empty().append(
423
- $("<option>")
424
- .val("no")
425
- .text("Last status")
426
- )
427
- $("#node-input-specifySwitchOnBrightness").val(this.specifySwitchOnBrightness).trigger('change');
428
-
429
- $("#node-input-enableDayNightLighting").empty().append(
430
- $("<option>")
431
- .val("no")
432
- .text("Last status")
433
- )
434
- }
435
- $("#node-input-enableDayNightLighting").val(this.enableDayNightLighting).trigger('change');
436
-
437
- // Check if grouped, to hide/show the "Get current" buttons
438
- if (element.deviceObject.type === "grouped_light") {
439
- $("#getColorAtSwitchOnDayTimeButton").hide();
440
- $("#getColorAtSwitchOnNightTimeButton").hide();
441
- } else {
442
- $("#getColorAtSwitchOnDayTimeButton").show();
443
- $("#getColorAtSwitchOnNightTimeButton").show();
444
- }
445
- return;
446
- }
447
- });
448
- });
449
-
450
365
  $("#getColorAtSwitchOnDayTimeButton").on("click", function () {
451
366
  $("#getColorAtSwitchOnDayTimeButton").text("Wait...");
452
367
  let jRet;
@@ -476,7 +391,7 @@
476
391
  });
477
392
 
478
393
  // Fill options for minDimLevel and maxDimLevel and comboBrightnessAtSwitchOn (for color brightness at switch on, with temperature toghedher)
479
- for (let index = 0; index <= 100; index += 5) {
394
+ for (let index = 100; index >= 0; index -= 5) {
480
395
  if (index === 0) {
481
396
  $("#node-input-minDimLevelLight").append($("<option>").val(index).text(index.toString() + "% (Switch Off)"));
482
397
  $("#comboBrightnessAtSwitchOn").append($("<option>").val(index).text(index.toString() + "% (Switch Off)"));
@@ -519,18 +434,18 @@
519
434
 
520
435
  // Calculate kelvin/color
521
436
  let json;
522
- this.colorAtSwitchOnDayTime = this.colorAtSwitchOnDayTime.replace("geen", "green"); // Old bug in "geen" property
523
- this.colorAtSwitchOnNightTime = this.colorAtSwitchOnNightTime.replace("geen", "green"); // Old bug in "geen" property
437
+ node.colorAtSwitchOnDayTime = node.colorAtSwitchOnDayTime.replace("geen", "green"); // Old bug in "geen" property
438
+ node.colorAtSwitchOnNightTime = node.colorAtSwitchOnNightTime.replace("geen", "green"); // Old bug in "geen" property
524
439
  try {
525
- json = JSON.parse(this.colorAtSwitchOnDayTime);
440
+ json = JSON.parse(node.colorAtSwitchOnDayTime);
526
441
  } catch (error) {
527
- console.log("json = JSON.parse(this.colorAtSwitchOnDayTime) in HTML: " + error.message)
442
+ console.log("json = JSON.parse(node.colorAtSwitchOnDayTime) in HTML: " + error.message)
528
443
  }
529
444
  if (json !== undefined && json.kelvin !== undefined) {
530
445
  // Kelvin
531
446
  $("#comboTemperatureAtSwitchOn").val(json.kelvin);
532
447
  $("#comboBrightnessAtSwitchOn").val(json.brightness);
533
- if (this.specifySwitchOnBrightness !== 'no') $("#node-input-specifySwitchOnBrightness").val('temperature'); // Adjust in case of mismatch (from old geen bug)
448
+ if (node.specifySwitchOnBrightness !== 'no') $("#node-input-specifySwitchOnBrightness").val('temperature'); // Adjust in case of mismatch (from old geen bug)
534
449
  } else if (json !== undefined && json.red !== undefined) {
535
450
  // Must transform RGB into HTML HEX color
536
451
  try {
@@ -538,22 +453,22 @@
538
453
  } catch (error) {
539
454
  }
540
455
  $("#colorPickerDay").val($("#node-input-colorAtSwitchOnDayTime").val());
541
- if (this.specifySwitchOnBrightness !== 'no') $("#node-input-specifySwitchOnBrightness").val('yes'); // Adjust in case of mismatch (from old geen bug)
456
+ if (node.specifySwitchOnBrightness !== 'no') $("#node-input-specifySwitchOnBrightness").val('yes'); // Adjust in case of mismatch (from old geen bug)
542
457
  } else {
543
458
  // It's already an HEX color
544
- $("#colorPickerDay").val(this.colorAtSwitchOnDayTime);
545
- if (this.specifySwitchOnBrightness !== 'no') $("#node-input-specifySwitchOnBrightness").val('yes'); // Adjust in case of mismatch (from old geen bug)
459
+ $("#colorPickerDay").val(node.colorAtSwitchOnDayTime);
460
+ if (node.specifySwitchOnBrightness !== 'no') $("#node-input-specifySwitchOnBrightness").val('yes'); // Adjust in case of mismatch (from old geen bug)
546
461
  }
547
462
  //Night
548
463
  json = undefined;
549
464
  try {
550
- json = JSON.parse(this.colorAtSwitchOnNightTime);
465
+ json = JSON.parse(node.colorAtSwitchOnNightTime);
551
466
  } catch (error) { }
552
467
  if (json !== undefined && json.kelvin !== undefined) {
553
468
  // Kelvin
554
469
  $("#comboTemperatureAtSwitchOnNightTime").val(json.kelvin);
555
470
  $("#comboBrightnessAtSwitchOnNightTime").val(json.brightness);
556
- if (this.enableDayNightLighting !== 'no') $("#node-input-enableDayNightLighting").val('temperature'); // Adjust in case of mismatch (from old geen bug)
471
+ if (node.enableDayNightLighting !== 'no') $("#node-input-enableDayNightLighting").val('temperature'); // Adjust in case of mismatch (from old geen bug)
557
472
  } else if (json !== undefined && json.red !== undefined) {
558
473
  // Must transform RGB into HTML HEX color
559
474
  try {
@@ -561,11 +476,11 @@
561
476
  } catch (error) {
562
477
  }
563
478
  $("#colorPickerNight").val($("#node-input-colorAtSwitchOnNightTime").val());
564
- if (this.enableDayNightLighting !== 'no') $("#node-input-enableDayNightLighting").val('yes'); // Adjust in case of mismatch (from old geen bug)
479
+ if (node.enableDayNightLighting !== 'no') $("#node-input-enableDayNightLighting").val('yes'); // Adjust in case of mismatch (from old geen bug)
565
480
  } else {
566
481
  // It's already an HEX color
567
- $("#colorPickerNight").val(this.colorAtSwitchOnNightTime);
568
- if (this.enableDayNightLighting !== 'no') $("#node-input-enableDayNightLighting").val('yes'); // Adjust in case of mismatch (from old geen bug)
482
+ $("#colorPickerNight").val(node.colorAtSwitchOnNightTime);
483
+ if (node.enableDayNightLighting !== 'no') $("#node-input-enableDayNightLighting").val('yes'); // Adjust in case of mismatch (from old geen bug)
569
484
  }
570
485
 
571
486
 
@@ -585,7 +500,7 @@
585
500
  });
586
501
 
587
502
 
588
- $("#node-input-minDimLevelLight").val(this.minDimLevelLight);
503
+ $("#node-input-minDimLevelLight").val(node.minDimLevelLight);
589
504
  for (let index = 100; index >= 10; index--) {
590
505
  $("#node-input-maxDimLevelLight").append(
591
506
  $("<option>")
@@ -593,106 +508,248 @@
593
508
  .text(index.toString() + "%")
594
509
  );
595
510
  }
596
- $("#node-input-maxDimLevelLight").val(this.maxDimLevelLight);
597
-
598
- if (this.hueDevice !== "") $("#tabs").show(); // Light options
511
+ $("#node-input-maxDimLevelLight").val(node.maxDimLevelLight);
599
512
 
600
- },
601
- oneditsave: function () {
602
- //RED.sidebar.removeTab("tabNRColor");
603
- //RED.sidebar.show("help");
604
- if ($("#node-input-enableNodePINS").val() === "yes") {
605
- this.outputs = 1;
606
- this.inputs = 1;
607
- } else {
608
- this.outputs = 0;
609
- this.inputs = 0;
610
- }
611
- },
612
- oneditcancel: function () {
613
- //RED.sidebar.removeTab("tabNRColor");
614
- //RED.sidebar.show("help");
615
- }
616
- });
513
+ if (node.hueDevice !== "") $("#tabs").show(); // Light options
617
514
 
618
515
 
619
516
 
517
+ // Autocomplete suggestion with HUE Lights
518
+ $("#node-input-name").autocomplete({
519
+ minLength: 1,
520
+ source: function (request, response) {
521
+ $.getJSON("KNXUltimateGetResourcesHUE?rtype=light&nodeID=" + oNodeServerHue.id, (data) => {
522
+ response(
523
+ $.map(data.devices, function (value, key) {
524
+ //alert(JSON.stringify(value) + " "+ key)
525
+ var sSearch = value.name;
526
+ if (!value.name.includes("I'm still connecting")) {
527
+ if (fullSearch(sSearch, request.term)) {
528
+ return {
529
+ hueDevice: value.id,
530
+ value: value.name,
531
+ };
532
+ } else {
533
+ return null;
534
+ }
535
+ } else {
536
+ return {
537
+ hueDevice: value.id,
538
+ value: value.name,
539
+ };
540
+ }
541
+ })
542
+ );
543
+ });
544
+ },
545
+ select: function (event, ui) {
546
+ // Distinguish between group of lights an single light.
547
+ if (ui.item.value.toLowerCase().startsWith("grouped_light")) {
548
+ $("#node-input-hueDevice").val(ui.item.hueDevice + "#grouped_light");
549
+ } else {
550
+ $("#node-input-hueDevice").val(ui.item.hueDevice + "#light");
551
+ }
552
+ onEditPrepare(node);
553
+ $("#tabs").show();
554
+ },
555
+ });
556
+ }
620
557
 
621
- function rgbHex(red, green, blue, alpha) {
622
- const toHex = (red, green, blue, alpha) => ((blue | green << 8 | red << 16) | 1 << 24).toString(16).slice(1) + alpha;
623
- const parseCssRgbString = (input) => {
624
- const parts = input.replace(/rgba?\(([^)]+)\)/, '$1').split(/[,\s/]+/).filter(Boolean);
625
- if (parts.length < 3) {
626
- return;
558
+ RED.nodes.registerType("knxUltimateHueLight", {
559
+ category: "KNX Ultimate",
560
+ color: "#C0C7E9",
561
+ defaults: {
562
+ //buttonState: {value: true},
563
+ server: { type: "knxUltimate-config", required: false },
564
+ serverHue: { type: "hue-config", required: true },
565
+ name: { value: "" },
566
+
567
+ nameLightSwitch: { value: "" },
568
+ GALightSwitch: { value: "" },
569
+ dptLightSwitch: { value: "" },
570
+
571
+ nameLightState: { value: "" },
572
+ GALightState: { value: "" },
573
+ dptLightState: { value: "" },
574
+
575
+ nameLightDIM: { value: "" },
576
+ GALightDIM: { value: "" },
577
+ dptLightDIM: { value: "" },
578
+
579
+ nameLightColor: { value: "" },
580
+ GALightColor: { value: "" },
581
+ dptLightColor: { value: "" },
582
+
583
+ nameLightColorState: { value: "" },
584
+ GALightColorState: { value: "" },
585
+ dptLightColorState: { value: "" },
586
+
587
+ nameLightHSV: { value: "" },
588
+ GALightHSV: { value: "" },
589
+ dptLightHSV: { value: "" },
590
+
591
+ nameLightHSVPercentage: { value: "" },
592
+ GALightHSVPercentage: { value: "" },
593
+ dptLightHSVPercentage: { value: "" },
594
+
595
+ nameLightHSVState: { value: "" },
596
+ GALightHSVState: { value: "" },
597
+ dptLightHSVState: { value: "" },
598
+
599
+ nameLightBrightness: { value: "" },
600
+ GALightBrightness: { value: "" },
601
+ dptLightBrightness: { value: "" },
602
+
603
+ nameLightBrightnessState: { value: "" },
604
+ GALightBrightnessState: { value: "" },
605
+ dptLightBrightnessState: { value: "" },
606
+
607
+ nameLightBlink: { value: "" },
608
+ GALightBlink: { value: "" },
609
+ dptLightBlink: { value: "" },
610
+
611
+ nameLightColorCycle: { value: "" },
612
+ GALightColorCycle: { value: "" },
613
+ dptLightColorCycle: { value: "" },
614
+
615
+ nameDaylightSensor: { value: "" },
616
+ GADaylightSensor: { value: "" },
617
+ dptDaylightSensor: { value: "" },
618
+
619
+ nameLightKelvin: { value: "" },
620
+ GALightKelvin: { value: "" },
621
+ dptLightKelvin: { value: "" },
622
+
623
+ nameLightKelvinState: { value: "" },
624
+ GALightKelvinState: { value: "" },
625
+ dptLightKelvinState: { value: "" },
626
+
627
+ specifySwitchOnBrightness: { value: "temperature" },
628
+ colorAtSwitchOnDayTime: { value: '{"kelvin":3000, "brightness":100 }' },
629
+
630
+ enableDayNightLighting: { value: "no" },
631
+ colorAtSwitchOnNightTime: { value: '{ "kelvin":2700, "brightness":20 }' },
632
+
633
+ invertDayNight: { value: false },
634
+
635
+ updateKNXBrightnessStatusOnHUEOnOff: { value: "no" },
636
+ dimSpeed: { value: 5000, required: false },
637
+ minDimLevelLight: { value: 10, required: false },
638
+ maxDimLevelLight: { value: 100, required: false },
639
+ readStatusAtStartup: { value: "yes" },
640
+ enableNodePINS: { value: "no" },
641
+
642
+ outputs: { value: 0 },
643
+ inputs: { value: 0 },
644
+
645
+ hueDevice: { value: "" },
646
+ hueDeviceObject: { value: {} },
647
+ },
648
+ inputs: 0,
649
+ outputs: 0,
650
+ icon: "node-hue-icon.svg",
651
+ label: function () {
652
+ return this.name;
653
+ },
654
+ paletteLabel: "Hue Light (beta)",
655
+ oneditprepare: function () {
656
+ onEditPrepare(this);
657
+ },
658
+ oneditsave: function () {
659
+ //RED.sidebar.removeTab("tabNRColor");
660
+ //RED.sidebar.show("help");
661
+ if ($("#node-input-enableNodePINS").val() === "yes") {
662
+ this.outputs = 1;
663
+ this.inputs = 1;
664
+ } else {
665
+ this.outputs = 0;
666
+ this.inputs = 0;
667
+ }
668
+ },
669
+ oneditcancel: function () {
670
+ //RED.sidebar.removeTab("tabNRColor");
671
+ //RED.sidebar.show("help");
627
672
  }
673
+ });
674
+
628
675
 
629
- const parseValue = (value, max) => {
630
- value = value.trim();
631
676
 
632
- if (value.endsWith('%')) {
633
- return Math.min(Number.parseFloat(value) * max / 100, max);
677
+
678
+ function rgbHex(red, green, blue, alpha) {
679
+ const toHex = (red, green, blue, alpha) => ((blue | green << 8 | red << 16) | 1 << 24).toString(16).slice(1) + alpha;
680
+ const parseCssRgbString = (input) => {
681
+ const parts = input.replace(/rgba?\(([^)]+)\)/, '$1').split(/[,\s/]+/).filter(Boolean);
682
+ if (parts.length < 3) {
683
+ return;
634
684
  }
635
685
 
636
- return Math.min(Number.parseFloat(value), max);
637
- };
686
+ const parseValue = (value, max) => {
687
+ value = value.trim();
638
688
 
639
- const red = parseValue(parts[0], 255);
640
- const green = parseValue(parts[1], 255);
641
- const blue = parseValue(parts[2], 255);
642
- let alpha;
689
+ if (value.endsWith('%')) {
690
+ return Math.min(Number.parseFloat(value) * max / 100, max);
691
+ }
643
692
 
644
- if (parts.length === 4) {
645
- alpha = parseValue(parts[3], 1);
646
- }
693
+ return Math.min(Number.parseFloat(value), max);
694
+ };
647
695
 
648
- return [red, green, blue, alpha];
649
- };
696
+ const red = parseValue(parts[0], 255);
697
+ const green = parseValue(parts[1], 255);
698
+ const blue = parseValue(parts[2], 255);
699
+ let alpha;
650
700
 
651
- let isPercent = (red + (alpha || '')).toString().includes('%');
701
+ if (parts.length === 4) {
702
+ alpha = parseValue(parts[3], 1);
703
+ }
704
+
705
+ return [red, green, blue, alpha];
706
+ };
707
+
708
+ let isPercent = (red + (alpha || '')).toString().includes('%');
652
709
 
653
- if (typeof red === 'string' && !green) { // Single string parameter.
654
- const parsed = parseCssRgbString(red);
655
- if (!parsed) {
656
- throw new TypeError('Invalid or unsupported color format.');
710
+ if (typeof red === 'string' && !green) { // Single string parameter.
711
+ const parsed = parseCssRgbString(red);
712
+ if (!parsed) {
713
+ throw new TypeError('Invalid or unsupported color format.');
714
+ }
715
+
716
+ isPercent = false;
717
+ [red, green, blue, alpha] = parsed;
718
+ } else if (alpha !== undefined) {
719
+ alpha = Number.parseFloat(alpha);
657
720
  }
658
721
 
659
- isPercent = false;
660
- [red, green, blue, alpha] = parsed;
661
- } else if (alpha !== undefined) {
662
- alpha = Number.parseFloat(alpha);
663
- }
722
+ if (typeof red !== 'number'
723
+ || typeof green !== 'number'
724
+ || typeof blue !== 'number'
725
+ || red > 255
726
+ || green > 255
727
+ || blue > 255
728
+ ) {
729
+ throw new TypeError('Expected three numbers below 256');
730
+ }
664
731
 
665
- if (typeof red !== 'number'
666
- || typeof green !== 'number'
667
- || typeof blue !== 'number'
668
- || red > 255
669
- || green > 255
670
- || blue > 255
671
- ) {
672
- throw new TypeError('Expected three numbers below 256');
673
- }
732
+ if (typeof alpha === 'number') {
733
+ if (!isPercent && alpha >= 0 && alpha <= 1) {
734
+ alpha = Math.round(255 * alpha);
735
+ } else if (isPercent && alpha >= 0 && alpha <= 100) {
736
+ alpha = Math.round(255 * alpha / 100);
737
+ } else {
738
+ throw new TypeError(`Expected alpha value (${alpha}) as a fraction or percentage`);
739
+ }
674
740
 
675
- if (typeof alpha === 'number') {
676
- if (!isPercent && alpha >= 0 && alpha <= 1) {
677
- alpha = Math.round(255 * alpha);
678
- } else if (isPercent && alpha >= 0 && alpha <= 100) {
679
- alpha = Math.round(255 * alpha / 100);
741
+ alpha = (alpha | 1 << 8).toString(16).slice(1); // eslint-disable-line no-mixed-operators
680
742
  } else {
681
- throw new TypeError(`Expected alpha value (${alpha}) as a fraction or percentage`);
743
+ alpha = '';
682
744
  }
683
745
 
684
- alpha = (alpha | 1 << 8).toString(16).slice(1); // eslint-disable-line no-mixed-operators
685
- } else {
686
- alpha = '';
746
+ return toHex(red, green, blue, alpha);
687
747
  }
688
748
 
689
- return toHex(red, green, blue, alpha);
690
- }
691
-
749
+ }())
692
750
 
693
751
  </script>
694
752
 
695
-
696
753
  <script type="text/html" data-template-name="knxUltimateHueLight">
697
754
 
698
755
  <div class="form-row">
@@ -1003,9 +1060,9 @@
1003
1060
  <i class="fa fa-tag"></i> Switch on behaviour
1004
1061
  </label>
1005
1062
  <select id="node-input-specifySwitchOnBrightness">
1006
- <option value="temperature">Select temperature and brightness</option>
1007
- <option value="yes">Select color</option>
1008
1063
  <option value="no">Last status</option>
1064
+ <!-- <option value="temperature">Select temperature and brightness</option>
1065
+ <option value="yes">Select color</option> -->
1009
1066
  </select>
1010
1067
  </div>
1011
1068
 
@@ -1019,8 +1076,8 @@
1019
1076
  <div class="form-row" id="divTemperatureAtSwitchOn" hidden>
1020
1077
  <label for="node-input-colorAtSwitchOnDayTime" style="width:260px">
1021
1078
  </label>
1022
- <select style="width:180px;" id="comboTemperatureAtSwitchOn"></select>
1023
- <select style="width:180px;" id="comboBrightnessAtSwitchOn"></select>
1079
+ <select style="width:12%;" id="comboTemperatureAtSwitchOn"></select>
1080
+ <select style="width:25%;" id="comboBrightnessAtSwitchOn"></select>
1024
1081
  </div>
1025
1082
 
1026
1083
  <div id="divCCSBoxAtNightLighting">
@@ -1029,9 +1086,9 @@
1029
1086
  <i class="fa fa-clone"></i> Night Lighting
1030
1087
  </label>
1031
1088
  <select id="node-input-enableDayNightLighting">
1032
- <option value="temperature">Select temperature and brightness</option>
1033
- <option value="yes">Select color</option>
1034
1089
  <option value="no">No night lighting</option>
1090
+ <!-- <option value="temperature">Select temperature and brightness</option>
1091
+ <option value="yes">Select color</option> -->
1035
1092
  </select>
1036
1093
  </div>
1037
1094
 
@@ -1110,7 +1167,10 @@
1110
1167
  <br />
1111
1168
  </script>
1112
1169
 
1170
+
1113
1171
  <script type="text/markdown" data-help-name="knxUltimateHueLight">
1172
+
1173
+
1114
1174
  <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>
1115
1175
 
1116
1176
  **General**
@@ -1194,4 +1254,4 @@ The Dimming function works in **KNX mode `start` and `stop`**. To start dimming,
1194
1254
  [Find it useful?](https://www.paypal.me/techtoday)
1195
1255
 
1196
1256
  <br/>
1197
- </script>-
1257
+ </script>
@@ -99,36 +99,56 @@ module.exports = function (RED) {
99
99
  case config.GALightSwitch:
100
100
  msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightSwitch));
101
101
  if (msg.payload === true) {
102
- // Check wether the user selected specific color/brightness at switch on.
103
- let jColorChoosen = null;
104
- if (node.DayTime === true && (config.specifySwitchOnBrightness === "yes" || config.specifySwitchOnBrightness === "temperature")) {
105
- jColorChoosen = config.colorAtSwitchOnDayTime;
106
- } else if (node.DayTime === false && (config.enableDayNightLighting === "yes" || config.enableDayNightLighting === "temperature")) {
107
- jColorChoosen = config.colorAtSwitchOnNightTime;
102
+ let colorChoosen;
103
+ let temperatureChoosen;
104
+ let brightnessChoosen;
105
+ // The light must support the temperature (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
106
+ if (node.currentHUEDevice.color_temperature !== undefined) {
107
+ if (node.DayTime === true && config.specifySwitchOnBrightness === "temperature") {
108
+ temperatureChoosen = config.colorAtSwitchOnDayTime.kelvin;
109
+ } else if (node.DayTime === false && config.enableDayNightLighting === "temperature") {
110
+ temperatureChoosen = config.colorAtSwitchOnNightTime.kelvin;
111
+ }
112
+ }
113
+ if (node.currentHUEDevice.dimming !== undefined) {
114
+ // Check wether the user selected specific brightness at switch on (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
115
+ if (node.DayTime === true && config.specifySwitchOnBrightness === "temperature") {
116
+ brightnessChoosen = config.colorAtSwitchOnDayTime.brightness;
117
+ } else if (node.DayTime === false && config.enableDayNightLighting === "temperature") {
118
+ brightnessChoosen = config.colorAtSwitchOnNightTime.brightness;
119
+ }
120
+ }
121
+ if (node.currentHUEDevice.color !== undefined) {
122
+ // Check wether the user selected specific color at switch on (in this case, colorAtSwitchOnDayTime is a text with HTML web color)
123
+ if (node.DayTime === true && config.specifySwitchOnBrightness === "yes") {
124
+ colorChoosen = config.colorAtSwitchOnDayTime;
125
+ } else if (node.DayTime === false && config.enableDayNightLighting === "yes") {
126
+ colorChoosen = config.colorAtSwitchOnNightTime;
127
+ }
108
128
  }
109
129
 
110
- // Now we have a jColorChoosen. Proceed illuminating the light
111
- if (jColorChoosen !== null && jColorChoosen.kelvin === undefined) {
112
- // RGB
130
+ if (colorChoosen !== undefined) {
131
+ // Now we have a jColorChoosen. Proceed illuminating the light
113
132
  let gamut = null;
114
- if (node.currentHUEDevice !== undefined && node.currentHUEDevice.hasOwnProperty("color") && node.currentHUEDevice.color.hasOwnProperty("gamut_type")) {
133
+ if (node.currentHUEDevice.color.gamut_type !== undefined) {
115
134
  gamut = node.currentHUEDevice.color.gamut_type;
116
135
  }
117
- const dretXY = hueColorConverter.ColorConverter.rgbToXy(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue, gamut);
118
- const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue);
136
+ const dretXY = hueColorConverter.ColorConverter.rgbToXy(colorChoosen.red, colorChoosen.green, colorChoosen.blue, gamut);
137
+ const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(colorChoosen.red, colorChoosen.green, colorChoosen.blue);
119
138
  node.currentHUEDevice.dimming.brightness = Math.round(dbright, 0);
120
139
  node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
121
140
  state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } };
122
- } if (jColorChoosen !== null && jColorChoosen.kelvin !== undefined) {
141
+ } else if (temperatureChoosen !== undefined) {
123
142
  // Kelvin
124
- const dbright = jColorChoosen.brightness;
125
- const mirek = hueColorConverter.ColorConverter.kelvinToMirek(jColorChoosen.kelvin);
143
+ const mirek = hueColorConverter.ColorConverter.kelvinToMirek(temperatureChoosen);
126
144
  node.currentHUEDevice.color_temperature.mirek = mirek;
127
- node.currentHUEDevice.dimming.brightness = dbright;
145
+ node.currentHUEDevice.dimming.brightness = brightnessChoosen;
128
146
  node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
129
147
  // Kelvin temp
130
- state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color_temperature: { mirek: mirek } } : { on: { on: false } };
131
- } else if (jColorChoosen === null || jColorChoosen === undefined) {
148
+ state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen }, color_temperature: { mirek: mirek } } : { on: { on: false } };
149
+ } else if (brightnessChoosen !== undefined) {
150
+ state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen } } : { on: { on: false } };
151
+ } else {
132
152
  state = { on: { on: true } };
133
153
  }
134
154
  } else {
@@ -238,8 +258,8 @@ module.exports = function (RED) {
238
258
  let gamut = null;
239
259
  if (
240
260
  node.currentHUEDevice !== undefined
241
- && node.currentHUEDevice.hasOwnProperty("color")
242
- && node.currentHUEDevice.color.hasOwnProperty("gamut_type")
261
+ && node.currentHUEDevice.color !== undefined
262
+ && node.currentHUEDevice.color.gamut_type !== undefined
243
263
  ) {
244
264
  gamut = node.currentHUEDevice.color.gamut_type;
245
265
  }
@@ -305,8 +325,8 @@ module.exports = function (RED) {
305
325
  let gamut = null;
306
326
  if (
307
327
  node.currentHUEDevice !== undefined
308
- && node.currentHUEDevice.hasOwnProperty("color")
309
- && node.currentHUEDevice.color.hasOwnProperty("gamut_type")
328
+ && node.currentHUEDevice.color !== undefined
329
+ && node.currentHUEDevice.color.gamut_type !== undefined
310
330
  ) {
311
331
  gamut = node.currentHUEDevice.color.gamut_type;
312
332
  }
@@ -411,7 +431,7 @@ module.exports = function (RED) {
411
431
  if (node.brightnessStep > maxDimLevelLight) node.brightnessStep = maxDimLevelLight;
412
432
  hueTelegram = { dimming: { brightness: node.brightnessStep }, dynamics: { duration: _dimSpeedInMillisecs } };
413
433
  // Switch on the light if off
414
- if (node.currentHUEDevice.hasOwnProperty("on") !== undefined && node.currentHUEDevice.on.on === false) {
434
+ if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false) {
415
435
  hueTelegram.on = { on: true };
416
436
  }
417
437
  node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, hueTelegram, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
@@ -419,6 +439,7 @@ module.exports = function (RED) {
419
439
  }, _dimSpeedInMillisecs);
420
440
  }
421
441
  if (_KNXbrightness_delta > 0 && _KNXaction === 0) {
442
+ if (node.currentHUEDevice.on.on === false) return; // Don't dim down, if the light is already off.
422
443
  // DIM DOWN
423
444
  if (node.timerStepDim !== undefined) clearInterval(node.timerStepDim);
424
445
  node.timerStepDim = setInterval(() => {
@@ -427,7 +448,7 @@ module.exports = function (RED) {
427
448
  if (node.brightnessStep < minDimLevelLight) node.brightnessStep = minDimLevelLight;
428
449
  hueTelegram = { dimming: { brightness: node.brightnessStep }, dynamics: { duration: _dimSpeedInMillisecs } };
429
450
  // Switch off the light if on
430
- if (node.currentHUEDevice.hasOwnProperty("on") !== undefined && node.currentHUEDevice.on.on === true && node.brightnessStep === 0) {
451
+ if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true && node.brightnessStep === 0) {
431
452
  hueTelegram.on = { on: false };
432
453
  }
433
454
  node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, hueTelegram, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
@@ -445,7 +466,7 @@ module.exports = function (RED) {
445
466
  let hueTelegram = {};
446
467
  _dimSpeedInMillisecs = _dimSpeedInMillisecs === undefined || _dimSpeedInMillisecs === "" ? 5000 : _dimSpeedInMillisecs;
447
468
  let delta = 0;
448
- if (!node.currentHUEDevice.color_temperature.hasOwnProperty("mirek")) delta = 347 - Math.round(173, 0); // Unable to read the mirek, set medium as default
469
+ if (node.currentHUEDevice.color_temperature.mirek === undefined) delta = 347 - Math.round(173, 0); // Unable to read the mirek, set medium as default
449
470
  // We have also minDimLevelLight and maxDimLevelLight to take care of.
450
471
  // Mirek limits are not taken in consideration.
451
472
  // Maximum mirek is 347
@@ -456,12 +477,12 @@ module.exports = function (RED) {
456
477
  return;
457
478
  }
458
479
  if (_KNXbrightness_delta > 0 && _KNXaction === 1) {
459
- if (node.currentHUEDevice.color_temperature.hasOwnProperty("mirek")) delta = 347 - Math.round(node.currentHUEDevice.color_temperature.mirek, 0);
480
+ if (node.currentHUEDevice.color_temperature.mirek !== undefined) delta = 347 - Math.round(node.currentHUEDevice.color_temperature.mirek, 0);
460
481
  dimDirection = "up";
461
482
  }
462
483
  if (_KNXbrightness_delta > 0 && _KNXaction === 0) {
463
484
  // Set the minumum delta, taking care of the minimum brightness specified either in the HUE lamp itself, or specified by the user (parameter node.minDimLevelLight)
464
- if (node.currentHUEDevice.color_temperature.hasOwnProperty("mirek")) delta = Math.round(node.currentHUEDevice.color_temperature.mirek, 0);
485
+ if (node.currentHUEDevice.color_temperature.mirek !== undefined) delta = Math.round(node.currentHUEDevice.color_temperature.mirek, 0);
465
486
  dimDirection = "down";
466
487
  }
467
488
  // Calculate the dimming time based on delta
@@ -471,7 +492,7 @@ module.exports = function (RED) {
471
492
 
472
493
  hueTelegram = { color_temperature_delta: { action: dimDirection, mirek_delta: delta }, dynamics: { duration: _dimSpeedInMillisecs } };
473
494
  // Switch on the light if off
474
- if (node.currentHUEDevice.hasOwnProperty("on") !== undefined && node.currentHUEDevice.on.on === false && dimDirection === "up") {
495
+ if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && dimDirection === "up") {
475
496
  hueTelegram.on = { on: true };
476
497
  }
477
498
  node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, hueTelegram, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
@@ -506,17 +527,17 @@ module.exports = function (RED) {
506
527
  try {
507
528
  const firstLightInGroup = node.serverHue.getFirstLightInGroup(_event.id);
508
529
  if (firstLightInGroup !== null && firstLightInGroup !== undefined) {
509
- if (_event.color === undefined || Object.keys(_event.color).length === 0) {
530
+ if (_event.color === undefined) {
510
531
  _event.color = firstLightInGroup.color;
511
532
  }
512
- if (_event.color_temperature === undefined || Object.keys(_event.color_temperature).length === 0) {
533
+ if (_event.color_temperature === undefined) {
513
534
  _event.color_temperature = firstLightInGroup.color_temperature;
514
535
  }
515
536
  }
516
537
  } catch (error) { }
517
538
  }
518
539
 
519
- if (_event.hasOwnProperty("on")) {
540
+ if (_event.on !== undefined) {
520
541
  node.updateKNXLightState(_event.on.on);
521
542
  // In case of switch off, set the dim to zero
522
543
  if (_event.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === "onhueoff")) {
@@ -524,7 +545,7 @@ module.exports = function (RED) {
524
545
  //node.currentHUEDevice.dimming.brightness = 0;
525
546
  } else if (_event.on.on === true && node.currentHUEDevice.on.on === false) {
526
547
  // Turn on always update the dimming KNX Status value as well.
527
- let brightVal = 100;
548
+ let brightVal = 50;
528
549
  if (node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness !== undefined) brightVal = node.currentHUEDevice.dimming.brightness;
529
550
  node.updateKNXBrightnessState(brightVal);
530
551
  }
@@ -536,17 +557,17 @@ module.exports = function (RED) {
536
557
  node.currentHUEDevice.color = _event.color;
537
558
  }
538
559
 
539
- if (_event.hasOwnProperty("dimming") && _event.dimming.brightness !== undefined) {
540
- // Every once on a time, the light transmit the brightness value of 0.39.
560
+ if (_event.dimming !== undefined && _event.dimming.brightness !== undefined) {
561
+ // Once upon n a time, the light transmit the brightness value of 0.39.
541
562
  // To avoid wrongly turn light state on, exit
542
563
  if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
543
- if (node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0) {
564
+ if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0) {
544
565
  // Do nothing, because the light is off and the dimming also is 0
545
566
  } else {
546
- if (node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === false && (!_event.hasOwnProperty("on") || (_event.hasOwnProperty("on") && _event.on.on === true))) node.updateKNXLightState(_event.dimming.brightness > 0);
567
+ if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && (!_event.on !== undefined || (_event.on !== undefined && _event.on.on === true))) node.updateKNXLightState(_event.dimming.brightness > 0);
547
568
  node.updateKNXBrightnessState(_event.dimming.brightness);
548
569
  // If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
549
- if (_event.dimming.brightness === 0 && node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === true) {
570
+ if (_event.dimming.brightness === 0 && node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true) {
550
571
  node.serverHue.hueManager.writeHueQueueAdd(
551
572
  node.hueDevice,
552
573
  { on: { on: false } },
@@ -557,7 +578,7 @@ module.exports = function (RED) {
557
578
  node.currentHUEDevice.dimming.brightness = _event.dimming.brightness;
558
579
  }
559
580
  }
560
- if (_event.hasOwnProperty("color_temperature") && _event.color_temperature.mirek !== undefined) {
581
+ if (_event.color_temperature !== undefined && _event.color_temperature.mirek !== undefined) {
561
582
  node.updateKNXLightHSVState(_event.color_temperature.mirek);
562
583
  node.updateKNXLightKelvinState(_event.color_temperature.mirek);
563
584
  node.currentHUEDevice.color_temperature.mirek = _event.color_temperature.mirek;
@@ -666,7 +687,7 @@ module.exports = function (RED) {
666
687
 
667
688
  node.updateKNXLightColorState = function updateKNXLightColorState(_value, _outputtype = "write") {
668
689
  if (config.GALightColorState !== undefined && config.GALightColorState !== "") {
669
- if (!_value.hasOwnProperty('xy') || _value.xy.x === undefined) return;
690
+ if (_value.xy === undefined || _value.xy.x === undefined) return;
670
691
  const knxMsgPayload = {};
671
692
  knxMsgPayload.topic = config.GALightColorState;
672
693
  knxMsgPayload.dpt = config.dptLightColorState;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=16.0.0"
5
5
  },
6
- "version": "2.2.26",
6
+ "version": "2.2.28",
7
7
  "description": "Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer. Easy to use and highly configurable. With integrated Philips HUE devices control.",
8
8
  "dependencies": {
9
9
  "binary-parser": "2.2.1",