node-red-contrib-knx-ultimate 2.1.50 → 2.1.52
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 +11 -5
- package/nodes/hue-config.js +13 -18
- package/nodes/knxUltimateHueLight.html +3 -3
- package/nodes/knxUltimateHueLight.js +269 -128
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,18 +6,24 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
<p>
|
|
10
|
+
<b>Version 2.1.52</b> - October 2023<br/>
|
|
11
|
+
- HUE Light node: fixed another possible switch on brightness issue.<br/>
|
|
12
|
+
</p>
|
|
13
|
+
<p>
|
|
14
|
+
<b>Version 2.1.51</b> - October 2023<br/>
|
|
15
|
+
- HUE Light node: fixed a possible switch on brightness issue.<br/>
|
|
16
|
+
</p>
|
|
9
17
|
<p>
|
|
10
18
|
<b>Version 2.1.50</b> - October 2023<br/>
|
|
11
19
|
- KNXUltimateViewer node: fixed too large text in custom template..<br/>
|
|
12
|
-
|
|
13
|
-
<p>
|
|
20
|
+
</p>
|
|
14
21
|
<b>Version 2.1.47</b> - September 2023<br/>
|
|
15
22
|
- HUE BRIDGE: fixed multiple HUE bridge handling.<br/>
|
|
16
|
-
|
|
17
|
-
<p>
|
|
23
|
+
</p>
|
|
18
24
|
<b>Version 2.1.46</b> - September 2023<br/>
|
|
19
25
|
- HUE BRIDGE: In case of https problems (certificate expired, etc...), the node will try to connect to the HUE BRIDGE in insecure http mode.<br/>
|
|
20
|
-
|
|
26
|
+
</p>
|
|
21
27
|
<p>
|
|
22
28
|
<b>Version 2.1.45</b> - August 2023<br/>
|
|
23
29
|
- HUE Light: now it correctly sets the KNX brightness if you turn on/off the light via HUE app.<br/>
|
package/nodes/hue-config.js
CHANGED
|
@@ -138,7 +138,7 @@ module.exports = (RED) => {
|
|
|
138
138
|
// Get the owner
|
|
139
139
|
try {
|
|
140
140
|
let resourceName = "";
|
|
141
|
-
let
|
|
141
|
+
let sType = "";
|
|
142
142
|
if (_rtype === "light" || _rtype === "grouped_light") {
|
|
143
143
|
// It's a service, having a owner
|
|
144
144
|
const owners = node.hueAllResources.filter((a) => a.id === resource.owner.rid);
|
|
@@ -148,13 +148,14 @@ module.exports = (RED) => {
|
|
|
148
148
|
resourceName += "ALL GROUPS and ";
|
|
149
149
|
} else {
|
|
150
150
|
resourceName += `${owner.metadata.name} and `;
|
|
151
|
-
const room = node.hueAllRooms.find((child) => child.children.find((a) => a.rid === owner.id));
|
|
152
|
-
sRoom += room !== undefined ? `${room.metadata.name} + ` : " + ";
|
|
151
|
+
//const room = node.hueAllRooms.find((child) => child.children.find((a) => a.rid === owner.id));
|
|
152
|
+
//sRoom += room !== undefined ? `${room.metadata.name} + ` : " + ";
|
|
153
|
+
sType += capStr(owner.type) + ' + ';
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
|
-
|
|
156
|
+
sType = sType.slice(0, -" + ".length);
|
|
156
157
|
resourceName = resourceName.slice(0, -" and ".length);
|
|
157
|
-
resourceName +=
|
|
158
|
+
resourceName += sType !== "" ? ' (' + sType + ')' : "";
|
|
158
159
|
retArray.push({
|
|
159
160
|
name: `${capStr(resource.type)}: ${resourceName}`,
|
|
160
161
|
id: resource.id,
|
|
@@ -172,8 +173,7 @@ module.exports = (RED) => {
|
|
|
172
173
|
});
|
|
173
174
|
}
|
|
174
175
|
if (_rtype === "button") {
|
|
175
|
-
const linkedDevName =
|
|
176
|
-
node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
176
|
+
const linkedDevName = node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
177
177
|
const controlID = resource.metadata !== undefined ? resource.metadata.control_id || "" : "";
|
|
178
178
|
retArray.push({
|
|
179
179
|
name: `${capStr(_rtype)}: ${linkedDevName}, button ${controlID}`,
|
|
@@ -181,16 +181,14 @@ module.exports = (RED) => {
|
|
|
181
181
|
});
|
|
182
182
|
}
|
|
183
183
|
if (_rtype === "motion") {
|
|
184
|
-
const linkedDevName =
|
|
185
|
-
node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
184
|
+
const linkedDevName = node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
186
185
|
retArray.push({
|
|
187
186
|
name: `${capStr(_rtype)}: ${linkedDevName}`,
|
|
188
187
|
id: resource.id,
|
|
189
188
|
});
|
|
190
189
|
}
|
|
191
190
|
if (_rtype === "relative_rotary") {
|
|
192
|
-
const linkedDevName =
|
|
193
|
-
node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
191
|
+
const linkedDevName = node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
194
192
|
retArray.push({
|
|
195
193
|
name: `Rotary: ${linkedDevName}`,
|
|
196
194
|
id: resource.id,
|
|
@@ -198,8 +196,7 @@ module.exports = (RED) => {
|
|
|
198
196
|
}
|
|
199
197
|
if (_rtype === "light_level") {
|
|
200
198
|
const Room = node.hueAllRooms.find((room) => room.children.find((child) => child.rid === resource.owner.rid));
|
|
201
|
-
const linkedDevName =
|
|
202
|
-
node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
199
|
+
const linkedDevName = node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
203
200
|
retArray.push({
|
|
204
201
|
name: `Light Level: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ""}`,
|
|
205
202
|
id: resource.id,
|
|
@@ -207,8 +204,7 @@ module.exports = (RED) => {
|
|
|
207
204
|
}
|
|
208
205
|
if (_rtype === "temperature") {
|
|
209
206
|
const Room = node.hueAllRooms.find((room) => room.children.find((child) => child.rid === resource.owner.rid));
|
|
210
|
-
const linkedDevName =
|
|
211
|
-
node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
207
|
+
const linkedDevName = node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
212
208
|
retArray.push({
|
|
213
209
|
name: `Temperature: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ""}`,
|
|
214
210
|
id: resource.id,
|
|
@@ -216,8 +212,7 @@ module.exports = (RED) => {
|
|
|
216
212
|
}
|
|
217
213
|
if (_rtype === "device_power") {
|
|
218
214
|
const Room = node.hueAllRooms.find((room) => room.children.find((child) => child.rid === resource.owner.rid));
|
|
219
|
-
const linkedDevName =
|
|
220
|
-
node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
215
|
+
const linkedDevName = node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
221
216
|
retArray.push({
|
|
222
217
|
name: `Battery: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ""}`,
|
|
223
218
|
id: resource.id,
|
|
@@ -255,7 +250,7 @@ module.exports = (RED) => {
|
|
|
255
250
|
// Remove the client node from the clients array
|
|
256
251
|
try {
|
|
257
252
|
node.nodeClients = node.nodeClients.filter((x) => x.id !== _Node.id);
|
|
258
|
-
} catch (error) {}
|
|
253
|
+
} catch (error) { }
|
|
259
254
|
};
|
|
260
255
|
|
|
261
256
|
node.on("close", (done) => {
|
|
@@ -535,7 +535,7 @@
|
|
|
535
535
|
<p>
|
|
536
536
|
<div class="form-row">
|
|
537
537
|
<label for="node-input-linkBrightnessToSwitchStatus" style="width:260px;">
|
|
538
|
-
<i class="fa fa-tag"></i>
|
|
538
|
+
<i class="fa fa-tag"></i> Specify switch on brightness
|
|
539
539
|
</label>
|
|
540
540
|
<select id="node-input-linkBrightnessToSwitchStatus">
|
|
541
541
|
<option value="yes">Yes</option>
|
|
@@ -660,8 +660,8 @@ Start typing in the GA field, the name or group address of your KNX device, the
|
|
|
660
660
|
|
|
661
661
|
|Property|Description|
|
|
662
662
|
|--|--|
|
|
663
|
-
|
|
|
664
|
-
| Switch On - color/brightness | You can choose the color/brightness of your light, at switch on. Set it as JSON object, for example **{ "red": 255, "green": 255, "blue": 255 }
|
|
663
|
+
| Specify switch on brightness | It enables the brightness value to follow the on/off status of the light. If you change the HUE brightness value to 0% (from the HUE App), an "off" telegram is also sent to the KNX bus; if you set it other than 0%, an "on" telegram is also sent to the KNX bus. This is valid also vice-versa: if you change the brightness via KNX bus, the HUE on/off value is also sent to the lamp. If you set it to **No**, the previous HUE light brightness value is retained. Default value is **Yes**. |
|
|
664
|
+
| Switch On - color/brightness | You can choose the color/brightness of your light, at switch on. Set it as JSON object, for example **{ "red": 255, "green": 255, "blue": 255 }** |
|
|
665
665
|
| Night Lighting | It allows to set a particular light color/brightness at nighttime. If **checked**, a further set of option shows up and the light changes the behaviour based on these options, everytime you switch the light *on*. |
|
|
666
666
|
| Switch On - color/brightness at Nighttime | You can choose the color/brightness of your light, at switch on, on night time. Set it as JSON object. Default value if you leave blank is **{ "red": 100, "green": 0, "blue": 0 }** |
|
|
667
667
|
| Day/Night | Select the group address used to set the day/night behaviour. The group address value is *true* if daytime, *false* if nighttime. |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* eslint-disable max-len */
|
|
2
2
|
/* eslint-disable no-lonely-if */
|
|
3
3
|
module.exports = function (RED) {
|
|
4
|
-
const dptlib = require(
|
|
5
|
-
const hueColorConverter = require(
|
|
4
|
+
const dptlib = require("../KNXEngine/src/dptlib");
|
|
5
|
+
const hueColorConverter = require("./utils/hueColorConverter");
|
|
6
6
|
|
|
7
7
|
function knxUltimateHueLight(config) {
|
|
8
8
|
RED.nodes.createNode(this, config);
|
|
@@ -10,43 +10,37 @@ module.exports = function (RED) {
|
|
|
10
10
|
node.server = RED.nodes.getNode(config.server);
|
|
11
11
|
node.serverHue = RED.nodes.getNode(config.serverHue);
|
|
12
12
|
node.topic = node.name;
|
|
13
|
-
node.name = config.name === undefined ?
|
|
13
|
+
node.name = config.name === undefined ? "Hue" : config.name;
|
|
14
14
|
node.outputtopic = node.name;
|
|
15
|
-
node.dpt =
|
|
15
|
+
node.dpt = "";
|
|
16
16
|
node.notifyreadrequest = false;
|
|
17
|
-
node.notifyreadrequestalsorespondtobus =
|
|
18
|
-
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized =
|
|
17
|
+
node.notifyreadrequestalsorespondtobus = "false";
|
|
18
|
+
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = "";
|
|
19
19
|
node.notifyresponse = false;
|
|
20
20
|
node.notifywrite = true;
|
|
21
21
|
node.initialread = true;
|
|
22
22
|
node.listenallga = true; // Don't remove
|
|
23
|
-
node.outputtype =
|
|
23
|
+
node.outputtype = "write";
|
|
24
24
|
node.outputRBE = false; // Apply or not RBE to the output (Messages coming from flow)
|
|
25
25
|
node.inputRBE = false; // Apply or not RBE to the input (Messages coming from BUS)
|
|
26
|
-
node.currentPayload =
|
|
27
|
-
node.passthrough =
|
|
26
|
+
node.currentPayload = ""; // Current value for the RBE input and for the .previouspayload msg
|
|
27
|
+
node.passthrough = "no";
|
|
28
28
|
node.formatmultiplyvalue = 1;
|
|
29
|
-
node.formatnegativevalue =
|
|
29
|
+
node.formatnegativevalue = "leave";
|
|
30
30
|
node.formatdecimalsvalue = 2;
|
|
31
31
|
node.currentHUEDevice = undefined; // At start, this value is filled by a call to HUE api. It stores a value representing the current light status.
|
|
32
32
|
node.currentKNXGALightState = false; // Stores the current KNX value for the GA
|
|
33
33
|
node.DayTime = true;
|
|
34
|
-
node.isGrouped_light = config.hueDevice.split(
|
|
35
|
-
config.hueDevice = config.hueDevice.split(
|
|
34
|
+
node.isGrouped_light = config.hueDevice.split("#")[1] === "grouped_light";
|
|
35
|
+
config.hueDevice = config.hueDevice.split("#")[0];
|
|
36
36
|
|
|
37
37
|
// Used to call the status update from the config node.
|
|
38
|
-
node.setNodeStatus = ({
|
|
39
|
-
fill, shape, text, payload,
|
|
40
|
-
}) => {
|
|
41
|
-
|
|
42
|
-
};
|
|
38
|
+
node.setNodeStatus = ({ fill, shape, text, payload }) => { };
|
|
43
39
|
// Used to call the status update from the HUE config node.
|
|
44
|
-
node.setNodeStatusHue = ({
|
|
45
|
-
fill, shape, text, payload,
|
|
46
|
-
}) => {
|
|
40
|
+
node.setNodeStatusHue = ({ fill, shape, text, payload }) => {
|
|
47
41
|
if (payload === undefined) return;
|
|
48
42
|
const dDate = new Date();
|
|
49
|
-
payload = typeof payload ===
|
|
43
|
+
payload = typeof payload === "object" ? JSON.stringify(payload) : payload.toString();
|
|
50
44
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
51
45
|
};
|
|
52
46
|
|
|
@@ -60,25 +54,39 @@ module.exports = function (RED) {
|
|
|
60
54
|
if (msg.payload === true) {
|
|
61
55
|
if (node.DayTime) {
|
|
62
56
|
// Day Time
|
|
63
|
-
if (config.colorAtSwitchOnDayTime !== undefined && config.colorAtSwitchOnDayTime.toString().trim() !==
|
|
57
|
+
if (config.colorAtSwitchOnDayTime !== undefined && config.colorAtSwitchOnDayTime.toString().trim() !== "") {
|
|
64
58
|
// The user selected specific color/brightness at switch on.
|
|
65
59
|
let jColorChoosen = { red: 255, green: 255, blue: 255 };
|
|
66
60
|
jColorChoosen = JSON.parse(config.colorAtSwitchOnDayTime || '{ "red": 255, "green": 255, "blue": 255 }');
|
|
67
61
|
let gamut = null;
|
|
68
|
-
if (
|
|
62
|
+
if (
|
|
63
|
+
node.currentHUEDevice !== undefined
|
|
64
|
+
&& node.currentHUEDevice.hasOwnProperty("color")
|
|
65
|
+
&& node.currentHUEDevice.color.hasOwnProperty("gamut_type")
|
|
66
|
+
) {
|
|
69
67
|
gamut = node.currentHUEDevice.color.gamut_type;
|
|
70
68
|
}
|
|
71
69
|
const dretXY = hueColorConverter.ColorConverter.rgbToXy(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue, gamut);
|
|
72
70
|
const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGB(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue);
|
|
73
|
-
|
|
71
|
+
node.currentHUEDevice.dimming.brightness = dbright;
|
|
72
|
+
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
73
|
+
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus === "yes") {
|
|
74
74
|
state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } };
|
|
75
75
|
} else {
|
|
76
76
|
state = dbright > 0 ? { on: { on: true }, color: { xy: dretXY } } : { on: { on: false } };
|
|
77
77
|
}
|
|
78
|
-
} else if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus ===
|
|
79
|
-
|
|
78
|
+
} else if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus === "yes") {
|
|
79
|
+
try {
|
|
80
|
+
node.currentHUEDevice.dimming.brightness = 100;
|
|
81
|
+
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
82
|
+
} catch (error) { /* empty */ }
|
|
83
|
+
state = { on: { on: true }, dimming: { brightness: node.currentHUEDevice.dimming.brightness } };
|
|
80
84
|
} else {
|
|
81
|
-
|
|
85
|
+
try {
|
|
86
|
+
state = { on: { on: true }, dimming: { brightness: node.currentHUEDevice.dimming.brightness } };
|
|
87
|
+
} catch (error) {
|
|
88
|
+
state = { on: { on: true } };
|
|
89
|
+
}
|
|
82
90
|
}
|
|
83
91
|
} else {
|
|
84
92
|
// Night Time
|
|
@@ -86,26 +94,39 @@ module.exports = function (RED) {
|
|
|
86
94
|
let jColorChoosen = { red: 23, green: 4, blue: 0 };
|
|
87
95
|
jColorChoosen = JSON.parse(config.colorAtSwitchOnNightTime || '{ "red": 23, "green": 4, "blue": 0 }');
|
|
88
96
|
let gamut = null;
|
|
89
|
-
if (
|
|
97
|
+
if (
|
|
98
|
+
node.currentHUEDevice !== undefined
|
|
99
|
+
&& node.currentHUEDevice.hasOwnProperty("color")
|
|
100
|
+
&& node.currentHUEDevice.color.hasOwnProperty("gamut_type")
|
|
101
|
+
) {
|
|
90
102
|
gamut = node.currentHUEDevice.color.gamut_type;
|
|
91
103
|
}
|
|
92
104
|
const dretXY = hueColorConverter.ColorConverter.rgbToXy(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue, gamut);
|
|
93
105
|
const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGB(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue);
|
|
94
|
-
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus ===
|
|
106
|
+
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus === "yes") {
|
|
107
|
+
node.currentHUEDevice.dimming.brightness = dbright;
|
|
108
|
+
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
95
109
|
state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } };
|
|
96
110
|
} else {
|
|
97
111
|
state = dbright > 0 ? { on: { on: true }, color: { xy: dretXY } } : { on: { on: false } };
|
|
98
112
|
}
|
|
99
113
|
}
|
|
100
114
|
}
|
|
101
|
-
} else if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus ===
|
|
102
|
-
|
|
115
|
+
} else if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus === "yes") {
|
|
116
|
+
try {
|
|
117
|
+
node.currentHUEDevice.dimming.brightness = 0;
|
|
118
|
+
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
119
|
+
state = { on: { on: false }, dimming: { brightness: node.currentHUEDevice.dimming.brightness }, dynamics: { duration: 2000 } };
|
|
120
|
+
} catch (error) { /* empty */ }
|
|
103
121
|
} else {
|
|
104
122
|
state = { on: { on: false }, dynamics: { duration: 2000 } };
|
|
105
123
|
}
|
|
106
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
124
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
107
125
|
node.setNodeStatusHue({
|
|
108
|
-
fill:
|
|
126
|
+
fill: "green",
|
|
127
|
+
shape: "dot",
|
|
128
|
+
text: "KNX->HUE",
|
|
129
|
+
payload: state,
|
|
109
130
|
});
|
|
110
131
|
break;
|
|
111
132
|
case config.GALightDIM:
|
|
@@ -113,24 +134,35 @@ module.exports = function (RED) {
|
|
|
113
134
|
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
114
135
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM));
|
|
115
136
|
if (msg.payload.data > 0) {
|
|
116
|
-
const dimDirection = msg.payload.decr_incr === 1 ?
|
|
137
|
+
const dimDirection = msg.payload.decr_incr === 1 ? "up" : "down";
|
|
117
138
|
// First, switch on the light if off
|
|
118
|
-
if (node.currentHUEDevice !== undefined && node.currentHUEDevice.on.on === false && dimDirection ===
|
|
119
|
-
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus ===
|
|
139
|
+
if (node.currentHUEDevice !== undefined && node.currentHUEDevice.on.on === false && dimDirection === "up") {
|
|
140
|
+
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus === "yes") {
|
|
120
141
|
// Starts from minimum of 5
|
|
121
|
-
node.serverHue.hueManager.writeHueQueueAdd(
|
|
142
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
143
|
+
config.hueDevice,
|
|
144
|
+
{ on: { on: true }, dimming: { brightness: 5 } },
|
|
145
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
146
|
+
);
|
|
122
147
|
} else {
|
|
123
148
|
// Read the last HUE brightness status and starts from there
|
|
124
149
|
const lastDimVal = node.currentHUEDevice !== undefined ? node.currentHUEDevice.dimming.brightness : 5;
|
|
125
|
-
node.serverHue.hueManager.writeHueQueueAdd(
|
|
150
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
151
|
+
config.hueDevice,
|
|
152
|
+
{ on: { on: true }, dimming: { brightness: lastDimVal } },
|
|
153
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
154
|
+
);
|
|
126
155
|
}
|
|
127
156
|
}
|
|
128
157
|
node.startDimStopper(dimDirection);
|
|
129
158
|
} else {
|
|
130
|
-
node.startDimStopper(
|
|
159
|
+
node.startDimStopper("stop");
|
|
131
160
|
}
|
|
132
161
|
node.setNodeStatusHue({
|
|
133
|
-
fill:
|
|
162
|
+
fill: "green",
|
|
163
|
+
shape: "dot",
|
|
164
|
+
text: "KNX->HUE",
|
|
165
|
+
payload: msg.payload,
|
|
134
166
|
});
|
|
135
167
|
break;
|
|
136
168
|
case config.GADaylightSensor:
|
|
@@ -138,44 +170,56 @@ module.exports = function (RED) {
|
|
|
138
170
|
node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)));
|
|
139
171
|
if (config.invertDayNight !== undefined && config.invertDayNight === true) node.DayTime = !node.DayTime;
|
|
140
172
|
node.setNodeStatusHue({
|
|
141
|
-
fill:
|
|
173
|
+
fill: "green",
|
|
174
|
+
shape: "dot",
|
|
175
|
+
text: "KNX->HUE Daytime",
|
|
176
|
+
payload: node.DayTime,
|
|
142
177
|
});
|
|
143
178
|
} else {
|
|
144
179
|
node.DayTime = true;
|
|
145
180
|
}
|
|
146
181
|
break;
|
|
147
182
|
case config.GALightHSV:
|
|
148
|
-
if (config.dptLightHSV ===
|
|
183
|
+
if (config.dptLightHSV === "3.007") {
|
|
149
184
|
// MDT smartbutton will dim the color temperature
|
|
150
185
|
// { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
|
|
151
186
|
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
152
187
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSV));
|
|
153
188
|
if (msg.payload.data > 0) {
|
|
154
|
-
const dimDirectionTunableWhite = msg.payload.decr_incr === 1 ?
|
|
189
|
+
const dimDirectionTunableWhite = msg.payload.decr_incr === 1 ? "up" : "down";
|
|
155
190
|
node.startDimStopperTunableWhite(dimDirectionTunableWhite);
|
|
156
191
|
} else {
|
|
157
|
-
node.startDimStopperTunableWhite(
|
|
192
|
+
node.startDimStopperTunableWhite("stop");
|
|
158
193
|
}
|
|
159
194
|
}
|
|
160
195
|
node.setNodeStatusHue({
|
|
161
|
-
fill:
|
|
196
|
+
fill: "green",
|
|
197
|
+
shape: "dot",
|
|
198
|
+
text: "KNX->HUE",
|
|
199
|
+
payload: msg.payload,
|
|
162
200
|
});
|
|
163
201
|
break;
|
|
164
202
|
case config.GALightHSVPercentage:
|
|
165
|
-
if (config.dptLightHSVPercentage ===
|
|
203
|
+
if (config.dptLightHSVPercentage === "5.001") {
|
|
166
204
|
// 0-100% tunable white
|
|
167
205
|
msg.payload = 100 - dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSVPercentage));
|
|
168
206
|
// msg.payload = msg.payload <= 0 ? 1 : msg.payload
|
|
169
207
|
const retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 100], [153, 500]);
|
|
170
208
|
msg.payload = retMirek;
|
|
171
209
|
state = { color_temperature: { mirek: msg.payload } };
|
|
172
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
210
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
173
211
|
node.setNodeStatusHue({
|
|
174
|
-
fill:
|
|
212
|
+
fill: "green",
|
|
213
|
+
shape: "dot",
|
|
214
|
+
text: "KNX->HUE",
|
|
215
|
+
payload: state,
|
|
175
216
|
});
|
|
176
217
|
}
|
|
177
218
|
node.setNodeStatusHue({
|
|
178
|
-
fill:
|
|
219
|
+
fill: "green",
|
|
220
|
+
shape: "dot",
|
|
221
|
+
text: "KNX->HUE",
|
|
222
|
+
payload: msg.payload,
|
|
179
223
|
});
|
|
180
224
|
break;
|
|
181
225
|
case config.GALightBrightness:
|
|
@@ -189,15 +233,22 @@ module.exports = function (RED) {
|
|
|
189
233
|
if (node.currentHUEDevice.on.on === false && msg.payload > 0) state.on = { on: true };
|
|
190
234
|
if (node.currentHUEDevice.on.on === true && msg.payload === 0) state.on = { on: false };
|
|
191
235
|
}
|
|
192
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
236
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
193
237
|
node.setNodeStatusHue({
|
|
194
|
-
fill:
|
|
238
|
+
fill: "green",
|
|
239
|
+
shape: "dot",
|
|
240
|
+
text: "KNX->HUE",
|
|
241
|
+
payload: state,
|
|
195
242
|
});
|
|
196
243
|
break;
|
|
197
244
|
case config.GALightColor:
|
|
198
245
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColor));
|
|
199
246
|
let gamut = null;
|
|
200
|
-
if (
|
|
247
|
+
if (
|
|
248
|
+
node.currentHUEDevice !== undefined
|
|
249
|
+
&& node.currentHUEDevice.hasOwnProperty("color")
|
|
250
|
+
&& node.currentHUEDevice.color.hasOwnProperty("gamut_type")
|
|
251
|
+
) {
|
|
201
252
|
gamut = node.currentHUEDevice.color.gamut_type;
|
|
202
253
|
}
|
|
203
254
|
const retXY = hueColorConverter.ColorConverter.rgbToXy(msg.payload.red, msg.payload.green, msg.payload.blue, gamut);
|
|
@@ -212,9 +263,12 @@ module.exports = function (RED) {
|
|
|
212
263
|
if (node.currentHUEDevice.on.on === false && bright > 0) state.on = { on: true };
|
|
213
264
|
if (node.currentHUEDevice.on.on === true && bright === 0) state = { on: { on: false }, dimming: { brightness: bright } };
|
|
214
265
|
}
|
|
215
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
266
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
216
267
|
node.setNodeStatusHue({
|
|
217
|
-
fill:
|
|
268
|
+
fill: "green",
|
|
269
|
+
shape: "dot",
|
|
270
|
+
text: "KNX->HUE",
|
|
271
|
+
payload: state,
|
|
218
272
|
});
|
|
219
273
|
break;
|
|
220
274
|
case config.GALightBlink:
|
|
@@ -225,22 +279,35 @@ module.exports = function (RED) {
|
|
|
225
279
|
node.blinkValue = !node.blinkValue;
|
|
226
280
|
msg.payload = node.blinkValue;
|
|
227
281
|
// state = msg.payload === true ? { on: { on: true } } : { on: { on: false } }
|
|
228
|
-
state = msg.payload === true
|
|
229
|
-
|
|
282
|
+
state = msg.payload === true
|
|
283
|
+
? { on: { on: true }, dimming: { brightness: 100 }, dynamics: { duration: 0 } }
|
|
284
|
+
: { on: { on: false }, dynamics: { duration: 0 } };
|
|
285
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
230
286
|
}, 1000);
|
|
231
287
|
} else {
|
|
232
288
|
if (node.timerBlink !== undefined) clearInterval(node.timerBlink);
|
|
233
|
-
node.serverHue.hueManager.writeHueQueueAdd(
|
|
289
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
290
|
+
config.hueDevice,
|
|
291
|
+
{ on: { on: false } },
|
|
292
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
293
|
+
);
|
|
234
294
|
}
|
|
235
295
|
node.setNodeStatusHue({
|
|
236
|
-
fill:
|
|
296
|
+
fill: "green",
|
|
297
|
+
shape: "dot",
|
|
298
|
+
text: "KNX->HUE",
|
|
299
|
+
payload: gaVal,
|
|
237
300
|
});
|
|
238
301
|
break;
|
|
239
302
|
case config.GALightColorCycle:
|
|
240
303
|
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle);
|
|
241
304
|
const gaValColorCycle = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColorCycle));
|
|
242
305
|
if (gaValColorCycle === true) {
|
|
243
|
-
node.serverHue.hueManager.writeHueQueueAdd(
|
|
306
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
307
|
+
config.hueDevice,
|
|
308
|
+
{ on: { on: true } },
|
|
309
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
310
|
+
);
|
|
244
311
|
node.timerColorCycle = setInterval(() => {
|
|
245
312
|
try {
|
|
246
313
|
function getRandomIntInclusive(min, max) {
|
|
@@ -252,29 +319,43 @@ module.exports = function (RED) {
|
|
|
252
319
|
const green = getRandomIntInclusive(0, 255);
|
|
253
320
|
const blue = getRandomIntInclusive(0, 255);
|
|
254
321
|
let gamut = null;
|
|
255
|
-
if (
|
|
322
|
+
if (
|
|
323
|
+
node.currentHUEDevice !== undefined
|
|
324
|
+
&& node.currentHUEDevice.hasOwnProperty("color")
|
|
325
|
+
&& node.currentHUEDevice.color.hasOwnProperty("gamut_type")
|
|
326
|
+
) {
|
|
256
327
|
gamut = node.currentHUEDevice.color.gamut_type;
|
|
257
328
|
}
|
|
258
329
|
const retXY = hueColorConverter.ColorConverter.rgbToXy(red, green, blue, gamut);
|
|
259
330
|
const bright = hueColorConverter.ColorConverter.getBrightnessFromRGB(red, green, blue);
|
|
260
331
|
state = bright > 0 ? { on: { on: true }, dimming: { brightness: bright }, color: { xy: retXY } } : { on: { on: false } };
|
|
261
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
262
|
-
} catch (error) {
|
|
263
|
-
}
|
|
332
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
333
|
+
} catch (error) { }
|
|
264
334
|
}, 10000);
|
|
265
335
|
} else {
|
|
266
336
|
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle);
|
|
267
|
-
node.serverHue.hueManager.writeHueQueueAdd(
|
|
337
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
338
|
+
config.hueDevice,
|
|
339
|
+
{ on: { on: false } },
|
|
340
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
341
|
+
);
|
|
268
342
|
}
|
|
269
343
|
node.setNodeStatusHue({
|
|
270
|
-
fill:
|
|
344
|
+
fill: "green",
|
|
345
|
+
shape: "dot",
|
|
346
|
+
text: "KNX->HUE",
|
|
347
|
+
payload: gaValColorCycle,
|
|
271
348
|
});
|
|
272
349
|
break;
|
|
273
350
|
default:
|
|
274
351
|
break;
|
|
275
352
|
}
|
|
276
353
|
} catch (error) {
|
|
277
|
-
node.status({
|
|
354
|
+
node.status({
|
|
355
|
+
fill: "red",
|
|
356
|
+
shape: "dot",
|
|
357
|
+
text: `KNX->HUE error ${error.message || error} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})`,
|
|
358
|
+
});
|
|
278
359
|
}
|
|
279
360
|
};
|
|
280
361
|
|
|
@@ -286,23 +367,26 @@ module.exports = function (RED) {
|
|
|
286
367
|
node.startDimStopper = function (_direction) {
|
|
287
368
|
node.timeoutDim = 0;
|
|
288
369
|
if (node.timerDim !== undefined) clearInterval(node.timerDim);
|
|
289
|
-
if (_direction ===
|
|
370
|
+
if (_direction === "stop") {
|
|
290
371
|
return;
|
|
291
372
|
}
|
|
292
373
|
switch (_direction) {
|
|
293
|
-
case
|
|
294
|
-
node.dimDirection = { dimming_delta: { action:
|
|
374
|
+
case "up":
|
|
375
|
+
node.dimDirection = { dimming_delta: { action: "up", brightness_delta: 10 } };
|
|
295
376
|
break;
|
|
296
|
-
case
|
|
297
|
-
node.dimDirection = { dimming_delta: { action:
|
|
377
|
+
case "down":
|
|
378
|
+
node.dimDirection = { dimming_delta: { action: "down", brightness_delta: 10 } };
|
|
298
379
|
break;
|
|
299
380
|
default:
|
|
300
381
|
break;
|
|
301
382
|
}
|
|
302
383
|
node.timerDim = setInterval(() => {
|
|
303
384
|
node.timeoutDim += 1;
|
|
304
|
-
if (node.timeoutDim > 150) {
|
|
305
|
-
|
|
385
|
+
if (node.timeoutDim > 150) {
|
|
386
|
+
node.timeoutDim = 0;
|
|
387
|
+
clearInterval(node.timerDim);
|
|
388
|
+
}
|
|
389
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, node.dimDirection, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
306
390
|
}, 700);
|
|
307
391
|
};
|
|
308
392
|
// ***********************************************************
|
|
@@ -316,21 +400,28 @@ module.exports = function (RED) {
|
|
|
316
400
|
node.startDimStopperTunableWhite = function (_direction) {
|
|
317
401
|
node.timeoutDimTunableWhite = 0;
|
|
318
402
|
if (node.timerDimTunableWhite !== undefined) clearInterval(node.timerDimTunableWhite);
|
|
319
|
-
if (_direction ===
|
|
403
|
+
if (_direction === "stop") return;
|
|
320
404
|
switch (_direction) {
|
|
321
|
-
case
|
|
322
|
-
node.dimDirectionTunableWhite = { color_temperature_delta: { action:
|
|
405
|
+
case "up":
|
|
406
|
+
node.dimDirectionTunableWhite = { color_temperature_delta: { action: "up", mirek_delta: 10 } };
|
|
323
407
|
break;
|
|
324
|
-
case
|
|
325
|
-
node.dimDirectionTunableWhite = { color_temperature_delta: { action:
|
|
408
|
+
case "down":
|
|
409
|
+
node.dimDirectionTunableWhite = { color_temperature_delta: { action: "down", mirek_delta: 10 } };
|
|
326
410
|
break;
|
|
327
411
|
default:
|
|
328
412
|
break;
|
|
329
413
|
}
|
|
330
414
|
node.timerDimTunableWhite = setInterval(() => {
|
|
331
415
|
node.timeoutDimTunableWhite += 1;
|
|
332
|
-
if (node.timeoutDimTunableWhite > 150) {
|
|
333
|
-
|
|
416
|
+
if (node.timeoutDimTunableWhite > 150) {
|
|
417
|
+
node.timeoutDimTunableWhite = 0;
|
|
418
|
+
clearInterval(node.timerDimTunableWhite);
|
|
419
|
+
}
|
|
420
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
421
|
+
config.hueDevice,
|
|
422
|
+
node.dimDirectionTunableWhite,
|
|
423
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
424
|
+
);
|
|
334
425
|
}, 700);
|
|
335
426
|
};
|
|
336
427
|
// ***********************************************************
|
|
@@ -338,9 +429,9 @@ module.exports = function (RED) {
|
|
|
338
429
|
node.handleSendHUE = (_event) => {
|
|
339
430
|
try {
|
|
340
431
|
if (_event.id === config.hueDevice) {
|
|
341
|
-
if (_event.hasOwnProperty(
|
|
432
|
+
if (_event.hasOwnProperty("on")) {
|
|
342
433
|
node.updateKNXLightState(_event.on.on);
|
|
343
|
-
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus ===
|
|
434
|
+
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus === "yes") {
|
|
344
435
|
// In case of switch off, set the dim to zero
|
|
345
436
|
if (_event.on.on === false) {
|
|
346
437
|
node.updateKNXBrightnessState(0);
|
|
@@ -348,55 +439,71 @@ module.exports = function (RED) {
|
|
|
348
439
|
// Restore the previous brightness value
|
|
349
440
|
try {
|
|
350
441
|
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
351
|
-
} catch (error) {
|
|
442
|
+
} catch (error) {
|
|
443
|
+
/* empty */
|
|
444
|
+
}
|
|
352
445
|
}
|
|
353
446
|
}
|
|
354
447
|
if (node.currentHUEDevice !== undefined) node.currentHUEDevice.on = _event.on; // Update the internal object representing the current light
|
|
448
|
+
return;
|
|
355
449
|
}
|
|
356
|
-
if (_event.hasOwnProperty(
|
|
450
|
+
if (_event.hasOwnProperty("color")) {
|
|
357
451
|
node.updateKNXLightColorState(_event.color);
|
|
358
452
|
if (node.currentHUEDevice !== undefined) node.currentHUEDevice.color = _event.color; // Update the internal object representing the current light
|
|
453
|
+
return;
|
|
359
454
|
}
|
|
360
|
-
if (_event.hasOwnProperty(
|
|
455
|
+
if (_event.hasOwnProperty("dimming")) {
|
|
361
456
|
// Every once time, the light transmit the brightness value of 0.39.
|
|
362
457
|
// To avoid wrongly turn light state on, exit
|
|
363
|
-
if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
|
|
364
|
-
if (node.currentHUEDevice !== undefined && node.currentHUEDevice.hasOwnProperty('dimming') && node.currentHUEDevice.dimming.brightness === _event.dimming.brightness) return;
|
|
365
458
|
if (_event.dimming.brightness === undefined) return;
|
|
366
|
-
|
|
459
|
+
if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
|
|
367
460
|
node.updateKNXBrightnessState(_event.dimming.brightness);
|
|
368
|
-
// Send true/false to switch state
|
|
369
|
-
node.updateKNXLightState(_event.dimming.brightness > 0);
|
|
370
|
-
|
|
371
|
-
// If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
|
|
372
|
-
if (_event.dimming.brightness === 0) node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, { on: { on: false } }, (node.isGrouped_light === false ? 'setLight' : 'setGroupedLight'));
|
|
373
|
-
|
|
374
461
|
if (node.currentHUEDevice !== undefined) node.currentHUEDevice.dimming = _event.dimming; // Update the internal object representing the current light
|
|
462
|
+
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus === "yes") {
|
|
463
|
+
node.updateKNXLightState(_event.dimming.brightness > 0);
|
|
464
|
+
}
|
|
465
|
+
// If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
|
|
466
|
+
if (_event.dimming.brightness === 0) {
|
|
467
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, { on: { on: false } }, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
468
|
+
}
|
|
469
|
+
return;
|
|
375
470
|
}
|
|
376
|
-
if (_event.hasOwnProperty(
|
|
471
|
+
if (_event.hasOwnProperty("color_temperature")) {
|
|
377
472
|
node.updateKNXLightHSVState(_event.color_temperature.mirek);
|
|
378
473
|
if (node.currentHUEDevice !== undefined) node.currentHUEDevice.color_temperature = _event.color_temperature; // Update the internal object representing the current light
|
|
474
|
+
return;
|
|
379
475
|
}
|
|
380
476
|
}
|
|
381
477
|
} catch (error) {
|
|
382
|
-
node.status({
|
|
478
|
+
node.status({
|
|
479
|
+
fill: "red",
|
|
480
|
+
shape: "dot",
|
|
481
|
+
text: `HUE->KNX error ${knxMsgPayload.topic} ${error.message} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})`,
|
|
482
|
+
});
|
|
383
483
|
}
|
|
384
484
|
};
|
|
385
485
|
|
|
386
486
|
node.updateKNXBrightnessState = function (_value) {
|
|
387
|
-
if (config.GALightBrightnessState !== undefined && config.GALightBrightnessState !==
|
|
487
|
+
if (config.GALightBrightnessState !== undefined && config.GALightBrightnessState !== "") {
|
|
388
488
|
const knxMsgPayload = {};
|
|
389
489
|
knxMsgPayload.topic = config.GALightBrightnessState;
|
|
390
490
|
knxMsgPayload.dpt = config.dptLightBrightnessState;
|
|
391
491
|
knxMsgPayload.payload = _value;
|
|
392
492
|
// Send to KNX bus
|
|
393
|
-
if (knxMsgPayload.topic !==
|
|
493
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
394
494
|
node.server.writeQueueAdd({
|
|
395
|
-
grpaddr: knxMsgPayload.topic,
|
|
495
|
+
grpaddr: knxMsgPayload.topic,
|
|
496
|
+
payload: knxMsgPayload.payload,
|
|
497
|
+
dpt: knxMsgPayload.dpt,
|
|
498
|
+
outputtype: "write",
|
|
499
|
+
nodecallerid: node.id,
|
|
396
500
|
});
|
|
397
501
|
}
|
|
398
502
|
node.setNodeStatusHue({
|
|
399
|
-
fill:
|
|
503
|
+
fill: "blue",
|
|
504
|
+
shape: "ring",
|
|
505
|
+
text: "HUE->KNX State",
|
|
506
|
+
payload: knxMsgPayload.payload,
|
|
400
507
|
});
|
|
401
508
|
}
|
|
402
509
|
};
|
|
@@ -406,58 +513,86 @@ module.exports = function (RED) {
|
|
|
406
513
|
knxMsgPayload.topic = config.GALightState;
|
|
407
514
|
knxMsgPayload.dpt = config.dptLightState;
|
|
408
515
|
knxMsgPayload.payload = _value;
|
|
409
|
-
if (config.GALightState !== undefined && config.GALightState !==
|
|
410
|
-
if (node.currentKNXGALightState !== knxMsgPayload.payload) {
|
|
411
|
-
|
|
412
|
-
|
|
516
|
+
if (config.GALightState !== undefined && config.GALightState !== "") {
|
|
517
|
+
if (node.currentKNXGALightState !== knxMsgPayload.payload) {
|
|
518
|
+
// Check not to have already sent the value
|
|
519
|
+
// Send to KNX bus
|
|
520
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
413
521
|
node.server.writeQueueAdd({
|
|
414
|
-
grpaddr: knxMsgPayload.topic,
|
|
522
|
+
grpaddr: knxMsgPayload.topic,
|
|
523
|
+
payload: knxMsgPayload.payload,
|
|
524
|
+
dpt: knxMsgPayload.dpt,
|
|
525
|
+
outputtype: "write",
|
|
526
|
+
nodecallerid: node.id,
|
|
415
527
|
});
|
|
416
528
|
}
|
|
417
529
|
node.setNodeStatusHue({
|
|
418
|
-
fill:
|
|
530
|
+
fill: "blue",
|
|
531
|
+
shape: "ring",
|
|
532
|
+
text: "HUE->KNX State",
|
|
533
|
+
payload: knxMsgPayload.payload,
|
|
419
534
|
});
|
|
420
535
|
}
|
|
421
536
|
}
|
|
422
537
|
node.currentKNXGALightState = knxMsgPayload.payload; // Stores the current value
|
|
423
|
-
} catch (error) {
|
|
538
|
+
} catch (error) {
|
|
539
|
+
/* empty */
|
|
540
|
+
}
|
|
424
541
|
};
|
|
425
542
|
|
|
426
543
|
node.updateKNXLightHSVState = function (_value) {
|
|
427
|
-
if (config.GALightHSVState !== undefined && config.GALightHSVState !==
|
|
544
|
+
if (config.GALightHSVState !== undefined && config.GALightHSVState !== "") {
|
|
428
545
|
const knxMsgPayload = {};
|
|
429
546
|
knxMsgPayload.topic = config.GALightHSVState;
|
|
430
547
|
knxMsgPayload.dpt = config.dptLightHSVState;
|
|
431
|
-
if (config.dptLightHSVState ===
|
|
548
|
+
if (config.dptLightHSVState === "5.001") {
|
|
432
549
|
const retPercent = hueColorConverter.ColorConverter.scale(_value, [153, 500], [0, 100]);
|
|
433
550
|
knxMsgPayload.payload = 100 - retPercent;
|
|
434
551
|
}
|
|
435
552
|
// Send to KNX bus
|
|
436
|
-
if (knxMsgPayload.topic !==
|
|
553
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
437
554
|
node.server.writeQueueAdd({
|
|
438
|
-
grpaddr: knxMsgPayload.topic,
|
|
555
|
+
grpaddr: knxMsgPayload.topic,
|
|
556
|
+
payload: knxMsgPayload.payload,
|
|
557
|
+
dpt: knxMsgPayload.dpt,
|
|
558
|
+
outputtype: "write",
|
|
559
|
+
nodecallerid: node.id,
|
|
439
560
|
});
|
|
440
561
|
}
|
|
441
562
|
node.setNodeStatusHue({
|
|
442
|
-
fill:
|
|
563
|
+
fill: "blue",
|
|
564
|
+
shape: "ring",
|
|
565
|
+
text: "HUE->KNX State",
|
|
566
|
+
payload: knxMsgPayload.payload,
|
|
443
567
|
});
|
|
444
568
|
}
|
|
445
569
|
};
|
|
446
570
|
|
|
447
571
|
node.updateKNXLightColorState = function (_value) {
|
|
448
|
-
if (config.GALightColorState !== undefined && config.GALightColorState !==
|
|
572
|
+
if (config.GALightColorState !== undefined && config.GALightColorState !== "") {
|
|
449
573
|
const knxMsgPayload = {};
|
|
450
574
|
knxMsgPayload.topic = config.GALightColorState;
|
|
451
575
|
knxMsgPayload.dpt = config.dptLightColorState;
|
|
452
|
-
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBriToRgb(
|
|
576
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBriToRgb(
|
|
577
|
+
_value.xy.x,
|
|
578
|
+
_value.xy.y,
|
|
579
|
+
node.currentHUEDevice !== undefined ? node.currentHUEDevice.dimming.brightness : 100
|
|
580
|
+
);
|
|
453
581
|
// Send to KNX bus
|
|
454
|
-
if (knxMsgPayload.topic !==
|
|
582
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
455
583
|
node.server.writeQueueAdd({
|
|
456
|
-
grpaddr: knxMsgPayload.topic,
|
|
584
|
+
grpaddr: knxMsgPayload.topic,
|
|
585
|
+
payload: knxMsgPayload.payload,
|
|
586
|
+
dpt: knxMsgPayload.dpt,
|
|
587
|
+
outputtype: "write",
|
|
588
|
+
nodecallerid: node.id,
|
|
457
589
|
});
|
|
458
590
|
}
|
|
459
591
|
node.setNodeStatusHue({
|
|
460
|
-
fill:
|
|
592
|
+
fill: "blue",
|
|
593
|
+
shape: "ring",
|
|
594
|
+
text: "HUE->KNX State",
|
|
595
|
+
payload: knxMsgPayload.payload,
|
|
461
596
|
});
|
|
462
597
|
}
|
|
463
598
|
};
|
|
@@ -475,12 +610,20 @@ module.exports = function (RED) {
|
|
|
475
610
|
(async () => {
|
|
476
611
|
try {
|
|
477
612
|
node.serverHue.addClient(node);
|
|
478
|
-
await node.serverHue.hueManager.writeHueQueueAdd(
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
613
|
+
await node.serverHue.hueManager.writeHueQueueAdd(
|
|
614
|
+
config.hueDevice,
|
|
615
|
+
null,
|
|
616
|
+
node.isGrouped_light === false ? "getLight" : "getGroupedLight",
|
|
617
|
+
(jLight) => {
|
|
618
|
+
node.currentHUEDevice = jLight;
|
|
619
|
+
node.setNodeStatusHue({
|
|
620
|
+
fill: "blue",
|
|
621
|
+
shape: "ring",
|
|
622
|
+
text: "Connected. Is on: ",
|
|
623
|
+
payload: node.currentHUEDevice.on.on === true,
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
);
|
|
484
627
|
} catch (err) {
|
|
485
628
|
RED.log.error(`Errore knxUltimateHueLight node.currentHUEDevice ${err.message}`);
|
|
486
629
|
}
|
|
@@ -488,11 +631,9 @@ module.exports = function (RED) {
|
|
|
488
631
|
}
|
|
489
632
|
}
|
|
490
633
|
|
|
491
|
-
node.on(
|
|
492
|
-
|
|
493
|
-
});
|
|
634
|
+
node.on("input", (msg) => { });
|
|
494
635
|
|
|
495
|
-
node.on(
|
|
636
|
+
node.on("close", (done) => {
|
|
496
637
|
if (node.server) {
|
|
497
638
|
node.server.removeClient(node);
|
|
498
639
|
}
|
|
@@ -502,5 +643,5 @@ module.exports = function (RED) {
|
|
|
502
643
|
done();
|
|
503
644
|
});
|
|
504
645
|
}
|
|
505
|
-
RED.nodes.registerType(
|
|
646
|
+
RED.nodes.registerType("knxUltimateHueLight", knxUltimateHueLight);
|
|
506
647
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=16.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.1.
|
|
6
|
+
"version": "2.1.52",
|
|
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 handling.",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"binary-parser": "2.2.1",
|