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 +5 -0
- package/nodes/hue-config.js +12 -9
- package/nodes/knxUltimateHueLight.js +245 -234
- package/package.json +1 -1
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/>
|
package/nodes/hue-config.js
CHANGED
|
@@ -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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (node.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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:
|
|
156
|
+
state = { on: { on: false } };
|
|
153
157
|
}
|
|
154
|
-
} else {
|
|
155
|
-
state = { on: { on: false } };
|
|
156
|
-
}
|
|
157
158
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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.
|
|
214
|
-
node.
|
|
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
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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:
|
|
195
|
+
payload: msg.payload,
|
|
234
196
|
});
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
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:
|
|
312
|
+
payload: gaVal,
|
|
352
313
|
});
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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",
|