node-red-contrib-knx-ultimate 2.2.28 → 2.2.29

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,11 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ **Version 2.2.29** - 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 causing the node status to signal an error. Filtered the groupvalue_read from imbound KNX messages.<br/>
12
+ - WARNING: the new HUE Light options are to be considered **BETA (= in testing with user feedback)**.<br/>
13
+
9
14
  **Version 2.2.28** - November 2023<br/>
10
15
  This is an interim version, to quick fix some issues. Please report any issue with HUE Nodes, on gitHub.<br/>
11
16
  - 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/>
@@ -258,6 +258,7 @@ module.exports = (RED) => {
258
258
  } else {
259
259
  allResources = node.hueAllResources.filter((a) => a.type === _rtype);
260
260
  }
261
+ if (allResources === null) return;
261
262
  for (let index = 0; index < allResources.length; index++) {
262
263
  const resource = allResources[index];
263
264
  // Get the owner
@@ -267,15 +268,17 @@ module.exports = (RED) => {
267
268
  if (_rtype === "light" || _rtype === "grouped_light") {
268
269
  // It's a service, having a owner
269
270
  const owners = node.hueAllResources.filter((a) => a.id === resource.owner.rid);
270
- for (let index = 0; index < owners.length; index++) {
271
- const owner = owners[index];
272
- if (owner.type === "bridge_home") {
273
- resourceName += "ALL GROUPS and ";
274
- } else {
275
- resourceName += `${owner.metadata.name} and `;
276
- // const room = node.hueAllRooms.find((child) => child.children.find((a) => a.rid === owner.id));
277
- // sRoom += room !== undefined ? `${room.metadata.name} + ` : " + ";
278
- sType += `${capStr(owner.type)} + `;
271
+ if (owners !== null) {
272
+ for (let index = 0; index < owners.length; index++) {
273
+ const owner = owners[index];
274
+ if (owner.type === "bridge_home") {
275
+ resourceName += "ALL GROUPS and ";
276
+ } else {
277
+ resourceName += `${owner.metadata.name} and `;
278
+ // const room = node.hueAllRooms.find((child) => child.children.find((a) => a.rid === owner.id));
279
+ // sRoom += room !== undefined ? `${room.metadata.name} + ` : " + ";
280
+ sType += `${capStr(owner.type)} + `;
281
+ }
279
282
  }
280
283
  }
281
284
  sType = sType.slice(0, -" + ".length);
@@ -93,251 +93,212 @@ module.exports = function (RED) {
93
93
  });
94
94
  return;
95
95
  }
96
- let state = {};
97
- try {
98
- switch (msg.knx.destination) {
99
- case config.GALightSwitch:
100
- msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightSwitch));
101
- if (msg.payload === true) {
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;
96
+ if (msg.knx.event !== "GroupValue_Read" && node.currentHUEDevice !== undefined) {
97
+ let state = {};
98
+ try {
99
+ switch (msg.knx.destination) {
100
+ case config.GALightSwitch:
101
+ msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightSwitch));
102
+ 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;
112
+ }
111
113
  }
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;
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;
120
+ }
119
121
  }
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;
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;
128
+ }
127
129
  }
128
- }
129
130
 
130
- if (colorChoosen !== undefined) {
131
- // Now we have a jColorChoosen. Proceed illuminating the light
132
- let gamut = null;
133
- if (node.currentHUEDevice.color.gamut_type !== undefined) {
134
- gamut = node.currentHUEDevice.color.gamut_type;
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;
136
+ }
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 } };
135
154
  }
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);
138
- node.currentHUEDevice.dimming.brightness = Math.round(dbright, 0);
139
- node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
140
- state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } };
141
- } else if (temperatureChoosen !== undefined) {
142
- // Kelvin
143
- const mirek = hueColorConverter.ColorConverter.kelvinToMirek(temperatureChoosen);
144
- node.currentHUEDevice.color_temperature.mirek = mirek;
145
- node.currentHUEDevice.dimming.brightness = brightnessChoosen;
146
- node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
147
- // Kelvin temp
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
155
  } else {
152
- state = { on: { on: true } };
156
+ state = { on: { on: false } };
153
157
  }
154
- } else {
155
- state = { on: { on: false } };
156
- }
157
158
 
158
- node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
159
- node.setNodeStatusHue({
160
- fill: "green",
161
- shape: "dot",
162
- text: "KNX->HUE",
163
- payload: state,
164
- });
165
- break;
166
- case config.GALightDIM:
167
- // { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
168
- // { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
169
- msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM));
170
- node.hueDimming(msg.payload.decr_incr, msg.payload.data, config.dimSpeed);
171
- node.setNodeStatusHue({
172
- fill: "green", shape: "dot", text: "KNX->HUE", payload: JSON.stringify(msg.payload),
173
- });
174
- break;
175
- case config.GALightKelvin:
176
- let retMirek;
177
- msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvin));
178
- if (config.dptLightKelvin === "7.600") {
179
- if (msg.payload > 65535) msg.payload = 65535;
180
- if (msg.payload < 0) msg.payload = 0;
181
- retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 65535], [500, 153]);
182
- } else if (config.dptLightKelvin === "9.002") {
183
- // Relative temperature in Kelvin. Use HUE scale.
184
- if (msg.payload > 6535) msg.payload = 6535;
185
- if (msg.payload < 2000) msg.payload = 2000;
186
- retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [2000, 6535], [500, 153]);
187
- }
188
- state = { color_temperature: { mirek: retMirek } };
189
- node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
190
- node.setNodeStatusHue({
191
- fill: "green",
192
- shape: "dot",
193
- text: "KNX->HUE",
194
- payload: msg.payload,
195
- });
196
- break;
197
- case config.GADaylightSensor:
198
- node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)));
199
- if (config.invertDayNight !== undefined && config.invertDayNight === true) node.DayTime = !node.DayTime;
200
- node.setNodeStatusHue({
201
- fill: "green",
202
- shape: "dot",
203
- text: "KNX->HUE Daytime",
204
- payload: node.DayTime,
205
- });
206
-
207
- break;
208
- case config.GALightHSV:
209
- if (config.dptLightHSV === "3.007") {
210
- // MDT smartbutton will dim the color temperature
159
+ node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
160
+ node.setNodeStatusHue({
161
+ fill: "green",
162
+ shape: "dot",
163
+ text: "KNX->HUE",
164
+ payload: state,
165
+ });
166
+ break;
167
+ case config.GALightDIM:
211
168
  // { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
212
169
  // { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
213
- msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSV));
214
- node.hueDimmingTunableWhite(msg.payload.decr_incr, msg.payload.data, config.dimSpeed);
170
+ msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM));
171
+ node.hueDimming(msg.payload.decr_incr, msg.payload.data, config.dimSpeed);
215
172
  node.setNodeStatusHue({
216
173
  fill: "green", shape: "dot", text: "KNX->HUE", payload: JSON.stringify(msg.payload),
217
174
  });
218
- }
219
- break;
220
- case config.GALightHSVPercentage:
221
- if (config.dptLightHSVPercentage === "5.001") {
222
- // 0-100% tunable white
223
- msg.payload = 100 - dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSVPercentage));
224
- // msg.payload = msg.payload <= 0 ? 1 : msg.payload
225
- const retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 100], [153, 500]);
226
- msg.payload = retMirek;
227
- state = { color_temperature: { mirek: msg.payload } };
175
+ break;
176
+ case config.GALightKelvin:
177
+ let retMirek;
178
+ msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvin));
179
+ if (config.dptLightKelvin === "7.600") {
180
+ if (msg.payload > 65535) msg.payload = 65535;
181
+ if (msg.payload < 0) msg.payload = 0;
182
+ retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 65535], [500, 153]);
183
+ } else if (config.dptLightKelvin === "9.002") {
184
+ // Relative temperature in Kelvin. Use HUE scale.
185
+ if (msg.payload > 6535) msg.payload = 6535;
186
+ if (msg.payload < 2000) msg.payload = 2000;
187
+ retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [2000, 6535], [500, 153]);
188
+ }
189
+ state = { color_temperature: { mirek: retMirek } };
228
190
  node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
229
191
  node.setNodeStatusHue({
230
192
  fill: "green",
231
193
  shape: "dot",
232
194
  text: "KNX->HUE",
233
- payload: state,
195
+ payload: msg.payload,
234
196
  });
235
- }
236
- break;
237
- case config.GALightBrightness:
238
- msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBrightness));
239
- state = { dimming: { brightness: msg.payload } };
240
- if (node.currentHUEDevice === undefined) {
241
- // Grouped light
242
- state.on = { on: msg.payload > 0 };
243
- } else {
244
- // Light
245
- if (node.currentHUEDevice.on.on === false && msg.payload > 0) state.on = { on: true };
246
- if (node.currentHUEDevice.on.on === true && msg.payload === 0) state.on = { on: false };
247
- }
248
- node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
249
- node.setNodeStatusHue({
250
- fill: "green",
251
- shape: "dot",
252
- text: "KNX->HUE",
253
- payload: state,
254
- });
255
- break;
256
- case config.GALightColor:
257
- msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColor));
258
- let gamut = null;
259
- if (
260
- node.currentHUEDevice !== undefined
261
- && node.currentHUEDevice.color !== undefined
262
- && node.currentHUEDevice.color.gamut_type !== undefined
263
- ) {
264
- gamut = node.currentHUEDevice.color.gamut_type;
265
- }
266
- const retXY = hueColorConverter.ColorConverter.rgbToXy(msg.payload.red, msg.payload.green, msg.payload.blue, gamut);
267
- const bright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(msg.payload.red, msg.payload.green, msg.payload.blue);
268
- // state = bright > 0 ? { on: { on: true }, dimming: { brightness: bright }, color: { xy: retXY } } : { on: { on: false } }
269
- state = { dimming: { brightness: bright }, color: { xy: retXY } };
270
- if (node.currentHUEDevice === undefined) {
271
- // Grouped light
272
- state.on = { on: bright > 0 };
273
- } else {
274
- // Light
275
- if (node.currentHUEDevice.on.on === false && bright > 0) state.on = { on: true };
276
- if (node.currentHUEDevice.on.on === true && bright === 0) state = { on: { on: false }, dimming: { brightness: bright } };
277
- }
278
- node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
279
- node.setNodeStatusHue({
280
- fill: "green",
281
- shape: "dot",
282
- text: "KNX->HUE",
283
- payload: state,
284
- });
285
- break;
286
- case config.GALightBlink:
287
- const gaVal = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBlink));
288
- if (gaVal) {
289
- node.timerBlink = setInterval(() => {
290
- if (node.blinkValue === undefined) node.blinkValue = true;
291
- node.blinkValue = !node.blinkValue;
292
- msg.payload = node.blinkValue;
293
- // state = msg.payload === true ? { on: { on: true } } : { on: { on: false } }
294
- state = msg.payload === true
295
- ? { on: { on: true }, dimming: { brightness: 100 }, dynamics: { duration: 0 } }
296
- : { on: { on: false }, dimming: { brightness: 0 }, dynamics: { duration: 0 } };
197
+ break;
198
+ case config.GADaylightSensor:
199
+ node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)));
200
+ if (config.invertDayNight !== undefined && config.invertDayNight === true) node.DayTime = !node.DayTime;
201
+ node.setNodeStatusHue({
202
+ fill: "green",
203
+ shape: "dot",
204
+ text: "KNX->HUE Daytime",
205
+ payload: node.DayTime,
206
+ });
207
+
208
+ break;
209
+ case config.GALightHSV:
210
+ if (config.dptLightHSV === "3.007") {
211
+ // MDT smartbutton will dim the color temperature
212
+ // { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
213
+ // { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
214
+ msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSV));
215
+ node.hueDimmingTunableWhite(msg.payload.decr_incr, msg.payload.data, config.dimSpeed);
216
+ node.setNodeStatusHue({
217
+ fill: "green", shape: "dot", text: "KNX->HUE", payload: JSON.stringify(msg.payload),
218
+ });
219
+ }
220
+ break;
221
+ case config.GALightHSVPercentage:
222
+ if (config.dptLightHSVPercentage === "5.001") {
223
+ // 0-100% tunable white
224
+ msg.payload = 100 - dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSVPercentage));
225
+ // msg.payload = msg.payload <= 0 ? 1 : msg.payload
226
+ const retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 100], [153, 500]);
227
+ msg.payload = retMirek;
228
+ state = { color_temperature: { mirek: msg.payload } };
297
229
  node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
298
- }, 1000);
299
- } else {
300
- if (node.timerBlink !== undefined) clearInterval(node.timerBlink);
301
- node.serverHue.hueManager.writeHueQueueAdd(
302
- node.hueDevice,
303
- { on: { on: false } },
304
- node.isGrouped_light === false ? "setLight" : "setGroupedLight",
305
- );
306
- }
307
- node.setNodeStatusHue({
308
- fill: "green",
309
- shape: "dot",
310
- text: "KNX->HUE",
311
- payload: gaVal,
312
- });
313
- break;
314
- case config.GALightColorCycle:
315
- {
316
- if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle);
317
- const gaValColorCycle = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColorCycle));
318
- if (gaValColorCycle === true) {
319
- node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, { on: { on: true } }, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
320
- node.timerColorCycle = setInterval(() => {
321
- try {
322
- const red = getRandomIntInclusive(0, 255);
323
- const green = getRandomIntInclusive(0, 255);
324
- const blue = getRandomIntInclusive(0, 255);
325
- let gamut = null;
326
- if (
327
- node.currentHUEDevice !== undefined
328
- && node.currentHUEDevice.color !== undefined
329
- && node.currentHUEDevice.color.gamut_type !== undefined
330
- ) {
331
- gamut = node.currentHUEDevice.color.gamut_type;
332
- }
333
- const retXY = hueColorConverter.ColorConverter.rgbToXy(red, green, blue, gamut);
334
- const bright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(red, green, blue);
335
- state = bright > 0 ? { on: { on: true }, dimming: { brightness: bright }, color: { xy: retXY } } : { on: { on: false } };
336
- node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
337
- } catch (error) { }
338
- }, 10000);
230
+ node.setNodeStatusHue({
231
+ fill: "green",
232
+ shape: "dot",
233
+ text: "KNX->HUE",
234
+ payload: state,
235
+ });
236
+ }
237
+ break;
238
+ case config.GALightBrightness:
239
+ msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBrightness));
240
+ state = { dimming: { brightness: msg.payload } };
241
+ if (node.currentHUEDevice === undefined) {
242
+ // Grouped light
243
+ state.on = { on: msg.payload > 0 };
339
244
  } else {
340
- if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle);
245
+ // Light
246
+ if (node.currentHUEDevice.on.on === false && msg.payload > 0) state.on = { on: true };
247
+ if (node.currentHUEDevice.on.on === true && msg.payload === 0) state.on = { on: false };
248
+ }
249
+ node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
250
+ node.setNodeStatusHue({
251
+ fill: "green",
252
+ shape: "dot",
253
+ text: "KNX->HUE",
254
+ payload: state,
255
+ });
256
+ break;
257
+ case config.GALightColor:
258
+ msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColor));
259
+ let gamut = null;
260
+ if (
261
+ node.currentHUEDevice !== undefined
262
+ && node.currentHUEDevice.color !== undefined
263
+ && node.currentHUEDevice.color.gamut_type !== undefined
264
+ ) {
265
+ gamut = node.currentHUEDevice.color.gamut_type;
266
+ }
267
+ const retXY = hueColorConverter.ColorConverter.rgbToXy(msg.payload.red, msg.payload.green, msg.payload.blue, gamut);
268
+ const bright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(msg.payload.red, msg.payload.green, msg.payload.blue);
269
+ // state = bright > 0 ? { on: { on: true }, dimming: { brightness: bright }, color: { xy: retXY } } : { on: { on: false } }
270
+ state = { dimming: { brightness: bright }, color: { xy: retXY } };
271
+ if (node.currentHUEDevice === undefined) {
272
+ // Grouped light
273
+ state.on = { on: bright > 0 };
274
+ } else {
275
+ // Light
276
+ if (node.currentHUEDevice.on.on === false && bright > 0) state.on = { on: true };
277
+ if (node.currentHUEDevice.on.on === true && bright === 0) state = { on: { on: false }, dimming: { brightness: bright } };
278
+ }
279
+ node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
280
+ node.setNodeStatusHue({
281
+ fill: "green",
282
+ shape: "dot",
283
+ text: "KNX->HUE",
284
+ payload: state,
285
+ });
286
+ break;
287
+ case config.GALightBlink:
288
+ const gaVal = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBlink));
289
+ if (gaVal) {
290
+ node.timerBlink = setInterval(() => {
291
+ if (node.blinkValue === undefined) node.blinkValue = true;
292
+ node.blinkValue = !node.blinkValue;
293
+ msg.payload = node.blinkValue;
294
+ // state = msg.payload === true ? { on: { on: true } } : { on: { on: false } }
295
+ state = msg.payload === true
296
+ ? { on: { on: true }, dimming: { brightness: 100 }, dynamics: { duration: 0 } }
297
+ : { on: { on: false }, dimming: { brightness: 0 }, dynamics: { duration: 0 } };
298
+ node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
299
+ }, 1000);
300
+ } else {
301
+ if (node.timerBlink !== undefined) clearInterval(node.timerBlink);
341
302
  node.serverHue.hueManager.writeHueQueueAdd(
342
303
  node.hueDevice,
343
304
  { on: { on: false } },
@@ -348,16 +309,65 @@ module.exports = function (RED) {
348
309
  fill: "green",
349
310
  shape: "dot",
350
311
  text: "KNX->HUE",
351
- payload: gaValColorCycle,
312
+ payload: gaVal,
352
313
  });
353
- }
354
- break;
355
- default:
356
- break;
314
+ break;
315
+ case config.GALightColorCycle:
316
+ {
317
+ if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle);
318
+ const gaValColorCycle = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColorCycle));
319
+ if (gaValColorCycle === true) {
320
+ node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, { on: { on: true } }, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
321
+ node.timerColorCycle = setInterval(() => {
322
+ try {
323
+ const red = getRandomIntInclusive(0, 255);
324
+ const green = getRandomIntInclusive(0, 255);
325
+ const blue = getRandomIntInclusive(0, 255);
326
+ let gamut = null;
327
+ if (
328
+ node.currentHUEDevice !== undefined
329
+ && node.currentHUEDevice.color !== undefined
330
+ && node.currentHUEDevice.color.gamut_type !== undefined
331
+ ) {
332
+ gamut = node.currentHUEDevice.color.gamut_type;
333
+ }
334
+ const retXY = hueColorConverter.ColorConverter.rgbToXy(red, green, blue, gamut);
335
+ const bright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(red, green, blue);
336
+ state = bright > 0 ? { on: { on: true }, dimming: { brightness: bright }, color: { xy: retXY } } : { on: { on: false } };
337
+ node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
338
+ } catch (error) { }
339
+ }, 10000);
340
+ } else {
341
+ if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle);
342
+ node.serverHue.hueManager.writeHueQueueAdd(
343
+ node.hueDevice,
344
+ { on: { on: false } },
345
+ node.isGrouped_light === false ? "setLight" : "setGroupedLight",
346
+ );
347
+ }
348
+ node.setNodeStatusHue({
349
+ fill: "green",
350
+ shape: "dot",
351
+ text: "KNX->HUE",
352
+ payload: gaValColorCycle,
353
+ });
354
+ }
355
+ break;
356
+ default:
357
+ break;
358
+ }
359
+ } catch (error) {
360
+ node.status({
361
+ fill: "red",
362
+ shape: "dot",
363
+ text: `KNX->HUE errorRead ${error.message} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})`,
364
+ });
365
+ RED.log.error(`knxUltimateHueLight: node.handleSend: if (msg.knx.event !== "GroupValue_Read"): ${error.message} : ${error.stack || ""} `);
357
366
  }
367
+ }
358
368
 
359
- // I must respond to query requests (read request) sent from the KNX BUS
360
-
369
+ // I must respond to query requests (read request) sent from the KNX BUS
370
+ try {
361
371
  if (msg.knx.event === "GroupValue_Read" && node.currentHUEDevice !== undefined) {
362
372
  let ret;
363
373
  switch (msg.knx.destination) {
@@ -389,8 +399,9 @@ module.exports = function (RED) {
389
399
  node.status({
390
400
  fill: "red",
391
401
  shape: "dot",
392
- text: `KNX->HUE error ${error.message || error} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})`,
402
+ text: `KNX->HUE error :-( ${error.message} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})`,
393
403
  });
404
+ RED.log.error(`knxUltimateHueLight: node.handleSend: if (msg.knx.event === "GroupValue_Read" && node.currentHUEDevice !== undefined): ${error.message} : ${error.stack || ""} `);
394
405
  }
395
406
  };
396
407
 
@@ -588,7 +599,7 @@ module.exports = function (RED) {
588
599
  node.status({
589
600
  fill: "red",
590
601
  shape: "dot",
591
- text: `HUE->KNX error ${node.id} ${error.message}`,
602
+ text: `HUE->KNX error ${node.id} ${error.message}. Seee Log`,
592
603
  });
593
604
  RED.log.error(`knxUltimateHueLight: node.handleSendHUE = (_event): ${error.message}`);
594
605
  }
@@ -801,6 +812,6 @@ module.exports = function (RED) {
801
812
  }
802
813
  done();
803
814
  });
804
- }
815
+ };
805
816
  RED.nodes.registerType("knxUltimateHueLight", knxUltimateHueLight);
806
817
  };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=16.0.0"
5
5
  },
6
- "version": "2.2.28",
6
+ "version": "2.2.29",
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",