node-red-contrib-knx-ultimate 2.1.51 → 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 +4 -0
- package/nodes/hue-config.js +13 -18
- package/nodes/knxUltimateHueLight.html +3 -3
- package/nodes/knxUltimateHueLight.js +264 -127
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
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>
|
|
9
13
|
<p>
|
|
10
14
|
<b>Version 2.1.51</b> - October 2023<br/>
|
|
11
15
|
- HUE Light node: fixed a possible switch on brightness issue.<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,23 +54,33 @@ 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 {
|
|
82
86
|
state = { on: { on: true }, dimming: { brightness: node.currentHUEDevice.dimming.brightness } };
|
|
@@ -90,26 +94,39 @@ module.exports = function (RED) {
|
|
|
90
94
|
let jColorChoosen = { red: 23, green: 4, blue: 0 };
|
|
91
95
|
jColorChoosen = JSON.parse(config.colorAtSwitchOnNightTime || '{ "red": 23, "green": 4, "blue": 0 }');
|
|
92
96
|
let gamut = null;
|
|
93
|
-
if (
|
|
97
|
+
if (
|
|
98
|
+
node.currentHUEDevice !== undefined
|
|
99
|
+
&& node.currentHUEDevice.hasOwnProperty("color")
|
|
100
|
+
&& node.currentHUEDevice.color.hasOwnProperty("gamut_type")
|
|
101
|
+
) {
|
|
94
102
|
gamut = node.currentHUEDevice.color.gamut_type;
|
|
95
103
|
}
|
|
96
104
|
const dretXY = hueColorConverter.ColorConverter.rgbToXy(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue, gamut);
|
|
97
105
|
const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGB(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue);
|
|
98
|
-
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);
|
|
99
109
|
state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } };
|
|
100
110
|
} else {
|
|
101
111
|
state = dbright > 0 ? { on: { on: true }, color: { xy: dretXY } } : { on: { on: false } };
|
|
102
112
|
}
|
|
103
113
|
}
|
|
104
114
|
}
|
|
105
|
-
} else if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus ===
|
|
106
|
-
|
|
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 */ }
|
|
107
121
|
} else {
|
|
108
122
|
state = { on: { on: false }, dynamics: { duration: 2000 } };
|
|
109
123
|
}
|
|
110
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
124
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
111
125
|
node.setNodeStatusHue({
|
|
112
|
-
fill:
|
|
126
|
+
fill: "green",
|
|
127
|
+
shape: "dot",
|
|
128
|
+
text: "KNX->HUE",
|
|
129
|
+
payload: state,
|
|
113
130
|
});
|
|
114
131
|
break;
|
|
115
132
|
case config.GALightDIM:
|
|
@@ -117,24 +134,35 @@ module.exports = function (RED) {
|
|
|
117
134
|
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
118
135
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM));
|
|
119
136
|
if (msg.payload.data > 0) {
|
|
120
|
-
const dimDirection = msg.payload.decr_incr === 1 ?
|
|
137
|
+
const dimDirection = msg.payload.decr_incr === 1 ? "up" : "down";
|
|
121
138
|
// First, switch on the light if off
|
|
122
|
-
if (node.currentHUEDevice !== undefined && node.currentHUEDevice.on.on === false && dimDirection ===
|
|
123
|
-
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") {
|
|
124
141
|
// Starts from minimum of 5
|
|
125
|
-
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
|
+
);
|
|
126
147
|
} else {
|
|
127
148
|
// Read the last HUE brightness status and starts from there
|
|
128
149
|
const lastDimVal = node.currentHUEDevice !== undefined ? node.currentHUEDevice.dimming.brightness : 5;
|
|
129
|
-
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
|
+
);
|
|
130
155
|
}
|
|
131
156
|
}
|
|
132
157
|
node.startDimStopper(dimDirection);
|
|
133
158
|
} else {
|
|
134
|
-
node.startDimStopper(
|
|
159
|
+
node.startDimStopper("stop");
|
|
135
160
|
}
|
|
136
161
|
node.setNodeStatusHue({
|
|
137
|
-
fill:
|
|
162
|
+
fill: "green",
|
|
163
|
+
shape: "dot",
|
|
164
|
+
text: "KNX->HUE",
|
|
165
|
+
payload: msg.payload,
|
|
138
166
|
});
|
|
139
167
|
break;
|
|
140
168
|
case config.GADaylightSensor:
|
|
@@ -142,44 +170,56 @@ module.exports = function (RED) {
|
|
|
142
170
|
node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)));
|
|
143
171
|
if (config.invertDayNight !== undefined && config.invertDayNight === true) node.DayTime = !node.DayTime;
|
|
144
172
|
node.setNodeStatusHue({
|
|
145
|
-
fill:
|
|
173
|
+
fill: "green",
|
|
174
|
+
shape: "dot",
|
|
175
|
+
text: "KNX->HUE Daytime",
|
|
176
|
+
payload: node.DayTime,
|
|
146
177
|
});
|
|
147
178
|
} else {
|
|
148
179
|
node.DayTime = true;
|
|
149
180
|
}
|
|
150
181
|
break;
|
|
151
182
|
case config.GALightHSV:
|
|
152
|
-
if (config.dptLightHSV ===
|
|
183
|
+
if (config.dptLightHSV === "3.007") {
|
|
153
184
|
// MDT smartbutton will dim the color temperature
|
|
154
185
|
// { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
|
|
155
186
|
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
156
187
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSV));
|
|
157
188
|
if (msg.payload.data > 0) {
|
|
158
|
-
const dimDirectionTunableWhite = msg.payload.decr_incr === 1 ?
|
|
189
|
+
const dimDirectionTunableWhite = msg.payload.decr_incr === 1 ? "up" : "down";
|
|
159
190
|
node.startDimStopperTunableWhite(dimDirectionTunableWhite);
|
|
160
191
|
} else {
|
|
161
|
-
node.startDimStopperTunableWhite(
|
|
192
|
+
node.startDimStopperTunableWhite("stop");
|
|
162
193
|
}
|
|
163
194
|
}
|
|
164
195
|
node.setNodeStatusHue({
|
|
165
|
-
fill:
|
|
196
|
+
fill: "green",
|
|
197
|
+
shape: "dot",
|
|
198
|
+
text: "KNX->HUE",
|
|
199
|
+
payload: msg.payload,
|
|
166
200
|
});
|
|
167
201
|
break;
|
|
168
202
|
case config.GALightHSVPercentage:
|
|
169
|
-
if (config.dptLightHSVPercentage ===
|
|
203
|
+
if (config.dptLightHSVPercentage === "5.001") {
|
|
170
204
|
// 0-100% tunable white
|
|
171
205
|
msg.payload = 100 - dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightHSVPercentage));
|
|
172
206
|
// msg.payload = msg.payload <= 0 ? 1 : msg.payload
|
|
173
207
|
const retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 100], [153, 500]);
|
|
174
208
|
msg.payload = retMirek;
|
|
175
209
|
state = { color_temperature: { mirek: msg.payload } };
|
|
176
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
210
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
177
211
|
node.setNodeStatusHue({
|
|
178
|
-
fill:
|
|
212
|
+
fill: "green",
|
|
213
|
+
shape: "dot",
|
|
214
|
+
text: "KNX->HUE",
|
|
215
|
+
payload: state,
|
|
179
216
|
});
|
|
180
217
|
}
|
|
181
218
|
node.setNodeStatusHue({
|
|
182
|
-
fill:
|
|
219
|
+
fill: "green",
|
|
220
|
+
shape: "dot",
|
|
221
|
+
text: "KNX->HUE",
|
|
222
|
+
payload: msg.payload,
|
|
183
223
|
});
|
|
184
224
|
break;
|
|
185
225
|
case config.GALightBrightness:
|
|
@@ -193,15 +233,22 @@ module.exports = function (RED) {
|
|
|
193
233
|
if (node.currentHUEDevice.on.on === false && msg.payload > 0) state.on = { on: true };
|
|
194
234
|
if (node.currentHUEDevice.on.on === true && msg.payload === 0) state.on = { on: false };
|
|
195
235
|
}
|
|
196
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
236
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
197
237
|
node.setNodeStatusHue({
|
|
198
|
-
fill:
|
|
238
|
+
fill: "green",
|
|
239
|
+
shape: "dot",
|
|
240
|
+
text: "KNX->HUE",
|
|
241
|
+
payload: state,
|
|
199
242
|
});
|
|
200
243
|
break;
|
|
201
244
|
case config.GALightColor:
|
|
202
245
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColor));
|
|
203
246
|
let gamut = null;
|
|
204
|
-
if (
|
|
247
|
+
if (
|
|
248
|
+
node.currentHUEDevice !== undefined
|
|
249
|
+
&& node.currentHUEDevice.hasOwnProperty("color")
|
|
250
|
+
&& node.currentHUEDevice.color.hasOwnProperty("gamut_type")
|
|
251
|
+
) {
|
|
205
252
|
gamut = node.currentHUEDevice.color.gamut_type;
|
|
206
253
|
}
|
|
207
254
|
const retXY = hueColorConverter.ColorConverter.rgbToXy(msg.payload.red, msg.payload.green, msg.payload.blue, gamut);
|
|
@@ -216,9 +263,12 @@ module.exports = function (RED) {
|
|
|
216
263
|
if (node.currentHUEDevice.on.on === false && bright > 0) state.on = { on: true };
|
|
217
264
|
if (node.currentHUEDevice.on.on === true && bright === 0) state = { on: { on: false }, dimming: { brightness: bright } };
|
|
218
265
|
}
|
|
219
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
266
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
220
267
|
node.setNodeStatusHue({
|
|
221
|
-
fill:
|
|
268
|
+
fill: "green",
|
|
269
|
+
shape: "dot",
|
|
270
|
+
text: "KNX->HUE",
|
|
271
|
+
payload: state,
|
|
222
272
|
});
|
|
223
273
|
break;
|
|
224
274
|
case config.GALightBlink:
|
|
@@ -229,22 +279,35 @@ module.exports = function (RED) {
|
|
|
229
279
|
node.blinkValue = !node.blinkValue;
|
|
230
280
|
msg.payload = node.blinkValue;
|
|
231
281
|
// state = msg.payload === true ? { on: { on: true } } : { on: { on: false } }
|
|
232
|
-
state = msg.payload === true
|
|
233
|
-
|
|
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");
|
|
234
286
|
}, 1000);
|
|
235
287
|
} else {
|
|
236
288
|
if (node.timerBlink !== undefined) clearInterval(node.timerBlink);
|
|
237
|
-
node.serverHue.hueManager.writeHueQueueAdd(
|
|
289
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
290
|
+
config.hueDevice,
|
|
291
|
+
{ on: { on: false } },
|
|
292
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
293
|
+
);
|
|
238
294
|
}
|
|
239
295
|
node.setNodeStatusHue({
|
|
240
|
-
fill:
|
|
296
|
+
fill: "green",
|
|
297
|
+
shape: "dot",
|
|
298
|
+
text: "KNX->HUE",
|
|
299
|
+
payload: gaVal,
|
|
241
300
|
});
|
|
242
301
|
break;
|
|
243
302
|
case config.GALightColorCycle:
|
|
244
303
|
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle);
|
|
245
304
|
const gaValColorCycle = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColorCycle));
|
|
246
305
|
if (gaValColorCycle === true) {
|
|
247
|
-
node.serverHue.hueManager.writeHueQueueAdd(
|
|
306
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
307
|
+
config.hueDevice,
|
|
308
|
+
{ on: { on: true } },
|
|
309
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
310
|
+
);
|
|
248
311
|
node.timerColorCycle = setInterval(() => {
|
|
249
312
|
try {
|
|
250
313
|
function getRandomIntInclusive(min, max) {
|
|
@@ -256,29 +319,43 @@ module.exports = function (RED) {
|
|
|
256
319
|
const green = getRandomIntInclusive(0, 255);
|
|
257
320
|
const blue = getRandomIntInclusive(0, 255);
|
|
258
321
|
let gamut = null;
|
|
259
|
-
if (
|
|
322
|
+
if (
|
|
323
|
+
node.currentHUEDevice !== undefined
|
|
324
|
+
&& node.currentHUEDevice.hasOwnProperty("color")
|
|
325
|
+
&& node.currentHUEDevice.color.hasOwnProperty("gamut_type")
|
|
326
|
+
) {
|
|
260
327
|
gamut = node.currentHUEDevice.color.gamut_type;
|
|
261
328
|
}
|
|
262
329
|
const retXY = hueColorConverter.ColorConverter.rgbToXy(red, green, blue, gamut);
|
|
263
330
|
const bright = hueColorConverter.ColorConverter.getBrightnessFromRGB(red, green, blue);
|
|
264
331
|
state = bright > 0 ? { on: { on: true }, dimming: { brightness: bright }, color: { xy: retXY } } : { on: { on: false } };
|
|
265
|
-
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state,
|
|
266
|
-
} catch (error) {
|
|
267
|
-
}
|
|
332
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
333
|
+
} catch (error) { }
|
|
268
334
|
}, 10000);
|
|
269
335
|
} else {
|
|
270
336
|
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle);
|
|
271
|
-
node.serverHue.hueManager.writeHueQueueAdd(
|
|
337
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
338
|
+
config.hueDevice,
|
|
339
|
+
{ on: { on: false } },
|
|
340
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
341
|
+
);
|
|
272
342
|
}
|
|
273
343
|
node.setNodeStatusHue({
|
|
274
|
-
fill:
|
|
344
|
+
fill: "green",
|
|
345
|
+
shape: "dot",
|
|
346
|
+
text: "KNX->HUE",
|
|
347
|
+
payload: gaValColorCycle,
|
|
275
348
|
});
|
|
276
349
|
break;
|
|
277
350
|
default:
|
|
278
351
|
break;
|
|
279
352
|
}
|
|
280
353
|
} catch (error) {
|
|
281
|
-
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
|
+
});
|
|
282
359
|
}
|
|
283
360
|
};
|
|
284
361
|
|
|
@@ -290,23 +367,26 @@ module.exports = function (RED) {
|
|
|
290
367
|
node.startDimStopper = function (_direction) {
|
|
291
368
|
node.timeoutDim = 0;
|
|
292
369
|
if (node.timerDim !== undefined) clearInterval(node.timerDim);
|
|
293
|
-
if (_direction ===
|
|
370
|
+
if (_direction === "stop") {
|
|
294
371
|
return;
|
|
295
372
|
}
|
|
296
373
|
switch (_direction) {
|
|
297
|
-
case
|
|
298
|
-
node.dimDirection = { dimming_delta: { action:
|
|
374
|
+
case "up":
|
|
375
|
+
node.dimDirection = { dimming_delta: { action: "up", brightness_delta: 10 } };
|
|
299
376
|
break;
|
|
300
|
-
case
|
|
301
|
-
node.dimDirection = { dimming_delta: { action:
|
|
377
|
+
case "down":
|
|
378
|
+
node.dimDirection = { dimming_delta: { action: "down", brightness_delta: 10 } };
|
|
302
379
|
break;
|
|
303
380
|
default:
|
|
304
381
|
break;
|
|
305
382
|
}
|
|
306
383
|
node.timerDim = setInterval(() => {
|
|
307
384
|
node.timeoutDim += 1;
|
|
308
|
-
if (node.timeoutDim > 150) {
|
|
309
|
-
|
|
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");
|
|
310
390
|
}, 700);
|
|
311
391
|
};
|
|
312
392
|
// ***********************************************************
|
|
@@ -320,21 +400,28 @@ module.exports = function (RED) {
|
|
|
320
400
|
node.startDimStopperTunableWhite = function (_direction) {
|
|
321
401
|
node.timeoutDimTunableWhite = 0;
|
|
322
402
|
if (node.timerDimTunableWhite !== undefined) clearInterval(node.timerDimTunableWhite);
|
|
323
|
-
if (_direction ===
|
|
403
|
+
if (_direction === "stop") return;
|
|
324
404
|
switch (_direction) {
|
|
325
|
-
case
|
|
326
|
-
node.dimDirectionTunableWhite = { color_temperature_delta: { action:
|
|
405
|
+
case "up":
|
|
406
|
+
node.dimDirectionTunableWhite = { color_temperature_delta: { action: "up", mirek_delta: 10 } };
|
|
327
407
|
break;
|
|
328
|
-
case
|
|
329
|
-
node.dimDirectionTunableWhite = { color_temperature_delta: { action:
|
|
408
|
+
case "down":
|
|
409
|
+
node.dimDirectionTunableWhite = { color_temperature_delta: { action: "down", mirek_delta: 10 } };
|
|
330
410
|
break;
|
|
331
411
|
default:
|
|
332
412
|
break;
|
|
333
413
|
}
|
|
334
414
|
node.timerDimTunableWhite = setInterval(() => {
|
|
335
415
|
node.timeoutDimTunableWhite += 1;
|
|
336
|
-
if (node.timeoutDimTunableWhite > 150) {
|
|
337
|
-
|
|
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
|
+
);
|
|
338
425
|
}, 700);
|
|
339
426
|
};
|
|
340
427
|
// ***********************************************************
|
|
@@ -342,9 +429,9 @@ module.exports = function (RED) {
|
|
|
342
429
|
node.handleSendHUE = (_event) => {
|
|
343
430
|
try {
|
|
344
431
|
if (_event.id === config.hueDevice) {
|
|
345
|
-
if (_event.hasOwnProperty(
|
|
432
|
+
if (_event.hasOwnProperty("on")) {
|
|
346
433
|
node.updateKNXLightState(_event.on.on);
|
|
347
|
-
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus ===
|
|
434
|
+
if (config.linkBrightnessToSwitchStatus === undefined || config.linkBrightnessToSwitchStatus === "yes") {
|
|
348
435
|
// In case of switch off, set the dim to zero
|
|
349
436
|
if (_event.on.on === false) {
|
|
350
437
|
node.updateKNXBrightnessState(0);
|
|
@@ -352,55 +439,71 @@ module.exports = function (RED) {
|
|
|
352
439
|
// Restore the previous brightness value
|
|
353
440
|
try {
|
|
354
441
|
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
355
|
-
} catch (error) {
|
|
442
|
+
} catch (error) {
|
|
443
|
+
/* empty */
|
|
444
|
+
}
|
|
356
445
|
}
|
|
357
446
|
}
|
|
358
447
|
if (node.currentHUEDevice !== undefined) node.currentHUEDevice.on = _event.on; // Update the internal object representing the current light
|
|
448
|
+
return;
|
|
359
449
|
}
|
|
360
|
-
if (_event.hasOwnProperty(
|
|
450
|
+
if (_event.hasOwnProperty("color")) {
|
|
361
451
|
node.updateKNXLightColorState(_event.color);
|
|
362
452
|
if (node.currentHUEDevice !== undefined) node.currentHUEDevice.color = _event.color; // Update the internal object representing the current light
|
|
453
|
+
return;
|
|
363
454
|
}
|
|
364
|
-
if (_event.hasOwnProperty(
|
|
455
|
+
if (_event.hasOwnProperty("dimming")) {
|
|
365
456
|
// Every once time, the light transmit the brightness value of 0.39.
|
|
366
457
|
// To avoid wrongly turn light state on, exit
|
|
367
|
-
if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
|
|
368
|
-
if (node.currentHUEDevice !== undefined && node.currentHUEDevice.hasOwnProperty('dimming') && node.currentHUEDevice.dimming.brightness === _event.dimming.brightness) return;
|
|
369
458
|
if (_event.dimming.brightness === undefined) return;
|
|
370
|
-
|
|
459
|
+
if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
|
|
371
460
|
node.updateKNXBrightnessState(_event.dimming.brightness);
|
|
372
|
-
// Send true/false to switch state
|
|
373
|
-
node.updateKNXLightState(_event.dimming.brightness > 0);
|
|
374
|
-
|
|
375
|
-
// If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
|
|
376
|
-
if (_event.dimming.brightness === 0) node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, { on: { on: false } }, (node.isGrouped_light === false ? 'setLight' : 'setGroupedLight'));
|
|
377
|
-
|
|
378
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;
|
|
379
470
|
}
|
|
380
|
-
if (_event.hasOwnProperty(
|
|
471
|
+
if (_event.hasOwnProperty("color_temperature")) {
|
|
381
472
|
node.updateKNXLightHSVState(_event.color_temperature.mirek);
|
|
382
473
|
if (node.currentHUEDevice !== undefined) node.currentHUEDevice.color_temperature = _event.color_temperature; // Update the internal object representing the current light
|
|
474
|
+
return;
|
|
383
475
|
}
|
|
384
476
|
}
|
|
385
477
|
} catch (error) {
|
|
386
|
-
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
|
+
});
|
|
387
483
|
}
|
|
388
484
|
};
|
|
389
485
|
|
|
390
486
|
node.updateKNXBrightnessState = function (_value) {
|
|
391
|
-
if (config.GALightBrightnessState !== undefined && config.GALightBrightnessState !==
|
|
487
|
+
if (config.GALightBrightnessState !== undefined && config.GALightBrightnessState !== "") {
|
|
392
488
|
const knxMsgPayload = {};
|
|
393
489
|
knxMsgPayload.topic = config.GALightBrightnessState;
|
|
394
490
|
knxMsgPayload.dpt = config.dptLightBrightnessState;
|
|
395
491
|
knxMsgPayload.payload = _value;
|
|
396
492
|
// Send to KNX bus
|
|
397
|
-
if (knxMsgPayload.topic !==
|
|
493
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
398
494
|
node.server.writeQueueAdd({
|
|
399
|
-
grpaddr: knxMsgPayload.topic,
|
|
495
|
+
grpaddr: knxMsgPayload.topic,
|
|
496
|
+
payload: knxMsgPayload.payload,
|
|
497
|
+
dpt: knxMsgPayload.dpt,
|
|
498
|
+
outputtype: "write",
|
|
499
|
+
nodecallerid: node.id,
|
|
400
500
|
});
|
|
401
501
|
}
|
|
402
502
|
node.setNodeStatusHue({
|
|
403
|
-
fill:
|
|
503
|
+
fill: "blue",
|
|
504
|
+
shape: "ring",
|
|
505
|
+
text: "HUE->KNX State",
|
|
506
|
+
payload: knxMsgPayload.payload,
|
|
404
507
|
});
|
|
405
508
|
}
|
|
406
509
|
};
|
|
@@ -410,58 +513,86 @@ module.exports = function (RED) {
|
|
|
410
513
|
knxMsgPayload.topic = config.GALightState;
|
|
411
514
|
knxMsgPayload.dpt = config.dptLightState;
|
|
412
515
|
knxMsgPayload.payload = _value;
|
|
413
|
-
if (config.GALightState !== undefined && config.GALightState !==
|
|
414
|
-
if (node.currentKNXGALightState !== knxMsgPayload.payload) {
|
|
415
|
-
|
|
416
|
-
|
|
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) {
|
|
417
521
|
node.server.writeQueueAdd({
|
|
418
|
-
grpaddr: knxMsgPayload.topic,
|
|
522
|
+
grpaddr: knxMsgPayload.topic,
|
|
523
|
+
payload: knxMsgPayload.payload,
|
|
524
|
+
dpt: knxMsgPayload.dpt,
|
|
525
|
+
outputtype: "write",
|
|
526
|
+
nodecallerid: node.id,
|
|
419
527
|
});
|
|
420
528
|
}
|
|
421
529
|
node.setNodeStatusHue({
|
|
422
|
-
fill:
|
|
530
|
+
fill: "blue",
|
|
531
|
+
shape: "ring",
|
|
532
|
+
text: "HUE->KNX State",
|
|
533
|
+
payload: knxMsgPayload.payload,
|
|
423
534
|
});
|
|
424
535
|
}
|
|
425
536
|
}
|
|
426
537
|
node.currentKNXGALightState = knxMsgPayload.payload; // Stores the current value
|
|
427
|
-
} catch (error) {
|
|
538
|
+
} catch (error) {
|
|
539
|
+
/* empty */
|
|
540
|
+
}
|
|
428
541
|
};
|
|
429
542
|
|
|
430
543
|
node.updateKNXLightHSVState = function (_value) {
|
|
431
|
-
if (config.GALightHSVState !== undefined && config.GALightHSVState !==
|
|
544
|
+
if (config.GALightHSVState !== undefined && config.GALightHSVState !== "") {
|
|
432
545
|
const knxMsgPayload = {};
|
|
433
546
|
knxMsgPayload.topic = config.GALightHSVState;
|
|
434
547
|
knxMsgPayload.dpt = config.dptLightHSVState;
|
|
435
|
-
if (config.dptLightHSVState ===
|
|
548
|
+
if (config.dptLightHSVState === "5.001") {
|
|
436
549
|
const retPercent = hueColorConverter.ColorConverter.scale(_value, [153, 500], [0, 100]);
|
|
437
550
|
knxMsgPayload.payload = 100 - retPercent;
|
|
438
551
|
}
|
|
439
552
|
// Send to KNX bus
|
|
440
|
-
if (knxMsgPayload.topic !==
|
|
553
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
441
554
|
node.server.writeQueueAdd({
|
|
442
|
-
grpaddr: knxMsgPayload.topic,
|
|
555
|
+
grpaddr: knxMsgPayload.topic,
|
|
556
|
+
payload: knxMsgPayload.payload,
|
|
557
|
+
dpt: knxMsgPayload.dpt,
|
|
558
|
+
outputtype: "write",
|
|
559
|
+
nodecallerid: node.id,
|
|
443
560
|
});
|
|
444
561
|
}
|
|
445
562
|
node.setNodeStatusHue({
|
|
446
|
-
fill:
|
|
563
|
+
fill: "blue",
|
|
564
|
+
shape: "ring",
|
|
565
|
+
text: "HUE->KNX State",
|
|
566
|
+
payload: knxMsgPayload.payload,
|
|
447
567
|
});
|
|
448
568
|
}
|
|
449
569
|
};
|
|
450
570
|
|
|
451
571
|
node.updateKNXLightColorState = function (_value) {
|
|
452
|
-
if (config.GALightColorState !== undefined && config.GALightColorState !==
|
|
572
|
+
if (config.GALightColorState !== undefined && config.GALightColorState !== "") {
|
|
453
573
|
const knxMsgPayload = {};
|
|
454
574
|
knxMsgPayload.topic = config.GALightColorState;
|
|
455
575
|
knxMsgPayload.dpt = config.dptLightColorState;
|
|
456
|
-
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
|
+
);
|
|
457
581
|
// Send to KNX bus
|
|
458
|
-
if (knxMsgPayload.topic !==
|
|
582
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
459
583
|
node.server.writeQueueAdd({
|
|
460
|
-
grpaddr: knxMsgPayload.topic,
|
|
584
|
+
grpaddr: knxMsgPayload.topic,
|
|
585
|
+
payload: knxMsgPayload.payload,
|
|
586
|
+
dpt: knxMsgPayload.dpt,
|
|
587
|
+
outputtype: "write",
|
|
588
|
+
nodecallerid: node.id,
|
|
461
589
|
});
|
|
462
590
|
}
|
|
463
591
|
node.setNodeStatusHue({
|
|
464
|
-
fill:
|
|
592
|
+
fill: "blue",
|
|
593
|
+
shape: "ring",
|
|
594
|
+
text: "HUE->KNX State",
|
|
595
|
+
payload: knxMsgPayload.payload,
|
|
465
596
|
});
|
|
466
597
|
}
|
|
467
598
|
};
|
|
@@ -479,12 +610,20 @@ module.exports = function (RED) {
|
|
|
479
610
|
(async () => {
|
|
480
611
|
try {
|
|
481
612
|
node.serverHue.addClient(node);
|
|
482
|
-
await node.serverHue.hueManager.writeHueQueueAdd(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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
|
+
);
|
|
488
627
|
} catch (err) {
|
|
489
628
|
RED.log.error(`Errore knxUltimateHueLight node.currentHUEDevice ${err.message}`);
|
|
490
629
|
}
|
|
@@ -492,11 +631,9 @@ module.exports = function (RED) {
|
|
|
492
631
|
}
|
|
493
632
|
}
|
|
494
633
|
|
|
495
|
-
node.on(
|
|
496
|
-
|
|
497
|
-
});
|
|
634
|
+
node.on("input", (msg) => { });
|
|
498
635
|
|
|
499
|
-
node.on(
|
|
636
|
+
node.on("close", (done) => {
|
|
500
637
|
if (node.server) {
|
|
501
638
|
node.server.removeClient(node);
|
|
502
639
|
}
|
|
@@ -506,5 +643,5 @@ module.exports = function (RED) {
|
|
|
506
643
|
done();
|
|
507
644
|
});
|
|
508
645
|
}
|
|
509
|
-
RED.nodes.registerType(
|
|
646
|
+
RED.nodes.registerType("knxUltimateHueLight", knxUltimateHueLight);
|
|
510
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",
|