node-red-contrib-knx-ultimate 2.2.26 → 2.2.27
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 +6 -0
- package/nodes/hue-config.js +70 -19
- package/nodes/knxUltimateHueLight.html +378 -318
- package/nodes/knxUltimateHueLight.js +41 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 2.2.27** - 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: the UI now changes, to adapt to lamp type.<br/>
|
|
12
|
+
- HUE Light: "Get current" color button, now works for grouped light as well, by reading the first light belongin to the group.<br/>
|
|
13
|
+
- WARNING: the new HUE Light options are to be considered **BETA (= in testing with user feedback)**.<br/>
|
|
14
|
+
|
|
9
15
|
**Version 2.2.26** - November 2023<br/>
|
|
10
16
|
This is an interim version, to quick fix some issues. Please report any issue with HUE Nodes, on gitHub.<br/>
|
|
11
17
|
- HUE Light: fixed some spurious node status errors.<br/>
|
package/nodes/hue-config.js
CHANGED
|
@@ -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
|
|
234
|
-
const
|
|
235
|
-
if (
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
449
|
-
|
|
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
|
-
|
|
457
|
-
|
|
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}`);
|
|
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
|
-
|
|
8
|
-
|
|
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($(
|
|
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($(
|
|
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
|
-
//
|
|
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 = "
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
$("
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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 (
|
|
305
|
+
if (node.specifySwitchOnBrightness === "yes") {
|
|
318
306
|
$("#divColorsAtSwitchOn").show();
|
|
319
307
|
$("#divTemperatureAtSwitchOn").hide();
|
|
320
|
-
} else if (
|
|
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 (
|
|
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 (
|
|
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 =
|
|
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
|
-
|
|
523
|
-
|
|
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(
|
|
440
|
+
json = JSON.parse(node.colorAtSwitchOnDayTime);
|
|
526
441
|
} catch (error) {
|
|
527
|
-
console.log("json = JSON.parse(
|
|
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 (
|
|
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 (
|
|
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(
|
|
545
|
-
if (
|
|
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(
|
|
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 (
|
|
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 (
|
|
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(
|
|
568
|
-
if (
|
|
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(
|
|
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(
|
|
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
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
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
|
-
|
|
633
|
-
|
|
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
|
-
|
|
637
|
-
|
|
686
|
+
const parseValue = (value, max) => {
|
|
687
|
+
value = value.trim();
|
|
638
688
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
let alpha;
|
|
689
|
+
if (value.endsWith('%')) {
|
|
690
|
+
return Math.min(Number.parseFloat(value) * max / 100, max);
|
|
691
|
+
}
|
|
643
692
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
}
|
|
693
|
+
return Math.min(Number.parseFloat(value), max);
|
|
694
|
+
};
|
|
647
695
|
|
|
648
|
-
|
|
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
|
-
|
|
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
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
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
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
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
|
-
|
|
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
|
-
|
|
743
|
+
alpha = '';
|
|
682
744
|
}
|
|
683
745
|
|
|
684
|
-
|
|
685
|
-
} else {
|
|
686
|
-
alpha = '';
|
|
746
|
+
return toHex(red, green, blue, alpha);
|
|
687
747
|
}
|
|
688
748
|
|
|
689
|
-
|
|
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:
|
|
1023
|
-
<select style="width:
|
|
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
|
-
|
|
103
|
-
let
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
111
|
-
|
|
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
|
|
133
|
+
if (node.currentHUEDevice.color.gamut_type !== undefined) {
|
|
115
134
|
gamut = node.currentHUEDevice.color.gamut_type;
|
|
116
135
|
}
|
|
117
|
-
const dretXY = hueColorConverter.ColorConverter.rgbToXy(
|
|
118
|
-
const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(
|
|
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 (
|
|
141
|
+
} else if (temperatureChoosen !== undefined) {
|
|
123
142
|
// Kelvin
|
|
124
|
-
const
|
|
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 =
|
|
145
|
+
node.currentHUEDevice.dimming.brightness = brightnessChoosen;
|
|
128
146
|
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
129
147
|
// Kelvin temp
|
|
130
|
-
state =
|
|
131
|
-
} else if (
|
|
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 {
|
|
@@ -506,10 +526,10 @@ module.exports = function (RED) {
|
|
|
506
526
|
try {
|
|
507
527
|
const firstLightInGroup = node.serverHue.getFirstLightInGroup(_event.id);
|
|
508
528
|
if (firstLightInGroup !== null && firstLightInGroup !== undefined) {
|
|
509
|
-
if (_event.color === undefined
|
|
529
|
+
if (_event.color === undefined) {
|
|
510
530
|
_event.color = firstLightInGroup.color;
|
|
511
531
|
}
|
|
512
|
-
if (_event.color_temperature === undefined
|
|
532
|
+
if (_event.color_temperature === undefined) {
|
|
513
533
|
_event.color_temperature = firstLightInGroup.color_temperature;
|
|
514
534
|
}
|
|
515
535
|
}
|
|
@@ -537,7 +557,7 @@ module.exports = function (RED) {
|
|
|
537
557
|
}
|
|
538
558
|
|
|
539
559
|
if (_event.hasOwnProperty("dimming") && _event.dimming.brightness !== undefined) {
|
|
540
|
-
//
|
|
560
|
+
// Once upon n a time, the light transmit the brightness value of 0.39.
|
|
541
561
|
// To avoid wrongly turn light state on, exit
|
|
542
562
|
if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
|
|
543
563
|
if (node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0) {
|
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.27",
|
|
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",
|