node-red-contrib-knx-ultimate 2.2.5 → 2.2.9
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 +13 -0
- package/nodes/hue-config.js +15 -12
- package/nodes/knxUltimate-config.js +1 -1
- package/nodes/knxUltimateHueBattery.html +19 -10
- package/nodes/knxUltimateHueBattery.js +22 -18
- package/nodes/knxUltimateHueButton.html +0 -1
- package/nodes/knxUltimateHueButton.js +5 -0
- package/nodes/knxUltimateHueLight.html +112 -42
- package/nodes/knxUltimateHueLight.js +52 -34
- package/nodes/knxUltimateHueLightSensor.html +9 -1
- package/nodes/knxUltimateHueLightSensor.js +5 -0
- package/nodes/knxUltimateHueMotion.html +1 -1
- package/nodes/knxUltimateHueMotion.js +6 -0
- package/nodes/knxUltimateHueScene.html +1 -0
- package/nodes/knxUltimateHueScene.js +4 -0
- package/nodes/knxUltimateHueTapDial.html +0 -4
- package/nodes/knxUltimateHueTapDial.js +11 -0
- package/nodes/utils/hueColorConverter.js +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,8 +6,21 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
<b>Version 2.2.9</b> - November 2023<br/>
|
|
10
|
+
- Fixed errors in Iobroker.<br/>
|
|
11
|
+
</p>
|
|
12
|
+
<b>Version 2.2.8</b> - November 2023<br/>
|
|
13
|
+
- HUE Light: NEW: color selection show now the temperature in kelvin.<br/>
|
|
14
|
+
- HUE Light: NEW: Tunable White: added control and status in kelvin (DPT 7.600). This is in BETA testing.<br/>
|
|
15
|
+
- Removed some options in button and scene nodes, because they are unnecessary.<br/>
|
|
16
|
+
</p>
|
|
17
|
+
<b>Version 2.2.6</b> - October 2023<br/>
|
|
18
|
+
- Fix: fixed HUE button sending a KNX telegram at startup. Fixed also other nodes.<br/>
|
|
19
|
+
- HUE Nodes: added the option to inizialize at startup or not.<br/>
|
|
20
|
+
</p>
|
|
9
21
|
<b>Version 2.2.5</b> - October 2023<br/>
|
|
10
22
|
- Fix: fixed some HUE nodes not able to register to the event notification service.<br/>
|
|
23
|
+
- Restyle GUI of KNX Device node.<br/>
|
|
11
24
|
</p>
|
|
12
25
|
<b>Version 2.2.4</b> - October 2023<br/>
|
|
13
26
|
- HUE Light: fixed some status hiccups and better handling of async hue bridge functions.<br/>
|
package/nodes/hue-config.js
CHANGED
|
@@ -58,7 +58,7 @@ module.exports = (RED) => {
|
|
|
58
58
|
node.nodeClientsAwaitingInit = []; // Stores the nodes client to be initialized
|
|
59
59
|
node.loglevel = config.loglevel !== undefined ? config.loglevel : "error"; // 18/02/2020 Loglevel default error
|
|
60
60
|
node.sysLogger = null;
|
|
61
|
-
node.hueAllResources =
|
|
61
|
+
node.hueAllResources = undefined;
|
|
62
62
|
try {
|
|
63
63
|
node.sysLogger = loggerEngine.get({ loglevel: node.loglevel }); // New logger to adhere to the loglevel selected in the config-window
|
|
64
64
|
} catch (error) {
|
|
@@ -91,14 +91,15 @@ module.exports = (RED) => {
|
|
|
91
91
|
});
|
|
92
92
|
// Connected
|
|
93
93
|
node.hueManager.on("connected", () => {
|
|
94
|
-
(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
(async () => {
|
|
96
|
+
try {
|
|
97
|
+
await node.loadResourcesFromHUEBridge(); // Then, you can use node.getResources, that works locally and doesn't query the HUE Bridge.
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("hue-Config node.hueManager.on('connected' " + error.message);
|
|
100
|
+
}
|
|
101
|
+
})();
|
|
102
|
+
}, 5000);
|
|
102
103
|
});
|
|
103
104
|
};
|
|
104
105
|
|
|
@@ -119,7 +120,7 @@ module.exports = (RED) => {
|
|
|
119
120
|
node.nodeClientsAwaitingInit = [];
|
|
120
121
|
}
|
|
121
122
|
node.nodeClients.forEach((nodeClient) => {
|
|
122
|
-
if (nodeClient.hueDevice !== undefined) {
|
|
123
|
+
if (nodeClient.hueDevice !== undefined && node.hueAllResources !== undefined) {
|
|
123
124
|
const oHUEDevice = node.hueAllResources.filter((a) => a.id === nodeClient.hueDevice)[0];
|
|
124
125
|
if (oHUEDevice !== undefined) {
|
|
125
126
|
// Add _Node to the clients array
|
|
@@ -129,6 +130,7 @@ module.exports = (RED) => {
|
|
|
129
130
|
text: "Ready :-)",
|
|
130
131
|
});
|
|
131
132
|
nodeClient.currentHUEDevice = oHUEDevice;
|
|
133
|
+
oHUEDevice.initializingAtStart = true; // Signalling first connection after restart.
|
|
132
134
|
nodeClient.handleSendHUE(oHUEDevice);
|
|
133
135
|
}
|
|
134
136
|
}
|
|
@@ -273,11 +275,12 @@ module.exports = (RED) => {
|
|
|
273
275
|
|
|
274
276
|
node.addClient = (_Node) => {
|
|
275
277
|
// Update the node hue device, as soon as a node register itself to hue-config nodeClients
|
|
276
|
-
if (node.hueAllResources !== null) {
|
|
278
|
+
if (node.hueAllResources !== undefined && node.hueAllResources !== null) {
|
|
277
279
|
if (node.nodeClients.filter((x) => x.id === _Node.id).length === 0) { // At first start, due to the async method for retrieving hueAllResources, hueAllResources is still null. The first start is handled in node.hueManager.on("connected")
|
|
278
280
|
const oHUEDevice = node.hueAllResources.filter((a) => a.id === _Node.hueDevice)[0];
|
|
279
281
|
_Node.currentHUEDevice = oHUEDevice;
|
|
280
|
-
|
|
282
|
+
oHUEDevice.initializingAtStart = true; // Signalling first connection after restart.
|
|
283
|
+
_Node.handleSendHUE(oHUEDevice);
|
|
281
284
|
node.nodeClients.push(_Node);
|
|
282
285
|
// Add _Node to the clients array
|
|
283
286
|
_Node.setNodeStatusHue({
|
|
@@ -2110,7 +2110,7 @@ return msg;`,
|
|
|
2110
2110
|
node.allowLauch_initKNXConnection = true; // Next cycle, launch initKNXConnection, so it pauses more and leave more time
|
|
2111
2111
|
const t = setTimeout(() => {
|
|
2112
2112
|
// 21/03/2022 fixed possible memory leak. Previously was setTimeout without "let t = ".
|
|
2113
|
-
node.setAllClientsStatus("
|
|
2113
|
+
node.setAllClientsStatus("Retry connection", "grey", "");
|
|
2114
2114
|
}, 1000);
|
|
2115
2115
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.debug(
|
|
2116
2116
|
"knxUltimate-config: Waiting next cycle to reconect. node.LinkStatus: " + node.linkStatus + ", node.autoReconnect:" + node.autoReconnect,
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
namebatterysensor: { value: "" },
|
|
12
12
|
GAbatterysensor: { value: "" },
|
|
13
13
|
dptbatterysensor: { value: "" },
|
|
14
|
+
readStatusAtStartup: { value: "no" },
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
hueDevice: { value: "" }
|
|
16
18
|
},
|
|
@@ -212,8 +214,13 @@
|
|
|
212
214
|
<input type="text" id="node-input-namebatterysensor" style="width:200px;margin-left: 5px; text-align: left;">
|
|
213
215
|
</div>
|
|
214
216
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
+
<div class="form-row">
|
|
218
|
+
<label style="width:180px" for="node-input-readStatusAtStartup"><i class="fa fa-play-circle"></i> Read status at startup</label>
|
|
219
|
+
<select id="node-input-readStatusAtStartup">
|
|
220
|
+
<option value="no">No</option>
|
|
221
|
+
<option value="yes">Yes, and emit KNX telegrams.</option>
|
|
222
|
+
</select>
|
|
223
|
+
</div>
|
|
217
224
|
<br/>
|
|
218
225
|
<br/>
|
|
219
226
|
<br/>
|
|
@@ -222,11 +229,12 @@
|
|
|
222
229
|
</script>
|
|
223
230
|
<script src="https://kit.fontawesome.com/11f26b4500.js" crossorigin="anonymous"></script>
|
|
224
231
|
|
|
225
|
-
<script type="text/markdown" data-help-name="knxUltimateHueBattery"
|
|
226
|
-
This node lets you get the battery level from your HUE device.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
Start typing in the GA field, the name or group address of your KNX device, the avaiable devices start showing up while
|
|
232
|
+
<script type="text/markdown" data-help-name="knxUltimateHueBattery">
|
|
233
|
+
This node lets you get the battery level from your HUE device. Here you can get the HUE battery level events, that represents a percentage 0-100% value, evetytime the
|
|
234
|
+
battery level changes.
|
|
235
|
+
|
|
236
|
+
Start typing in the GA field, the name or group address of your KNX device, the avaiable devices start showing up while
|
|
237
|
+
you're typing.
|
|
230
238
|
|
|
231
239
|
**General**
|
|
232
240
|
|Property|Description|
|
|
@@ -234,16 +242,17 @@ Start typing in the GA field, the name or group address of your KNX device, the
|
|
|
234
242
|
| KNX GW | Select the KNX gateway to be used |
|
|
235
243
|
| HUE Bridge | Select the HUE Bridge to be used |
|
|
236
244
|
| Hue Sensor | HUE sensor to be used. The avaiable devices start showing up while you're typing.|
|
|
245
|
+
| Read status at startup | Read the status at startup and emit the event to the KNX bus at startup/reconnection. (Default "no")|
|
|
237
246
|
|
|
238
247
|
|Property|Description|
|
|
239
248
|
|--|--|
|
|
240
249
|
| Level | The battery level group address. The group address must be a percentage 0-100% (5.001) |
|
|
241
250
|
|
|
242
251
|
|
|
243
|
-
<br/>
|
|
252
|
+
<br />
|
|
244
253
|
|
|
245
254
|
[Find it useful?](https://www.paypal.me/techtoday)
|
|
246
255
|
|
|
247
|
-
<br/>
|
|
256
|
+
<br />
|
|
248
257
|
|
|
249
|
-
|
|
258
|
+
</script>
|
|
@@ -47,30 +47,34 @@ module.exports = function (RED) {
|
|
|
47
47
|
node.handleSendHUE = (_event) => {
|
|
48
48
|
try {
|
|
49
49
|
if (_event.id === config.hueDevice) {
|
|
50
|
+
|
|
51
|
+
// IMPORTANT: exit if no event presen.
|
|
52
|
+
if (_event.initializingAtStart === true && (config.readStatusAtStartup === undefined || config.readStatusAtStartup === "no")) return;
|
|
53
|
+
if (!_event.hasOwnProperty("power_state") || _event.power_state.battery_level === undefined) return;
|
|
54
|
+
|
|
50
55
|
const knxMsgPayload = {};
|
|
51
56
|
knxMsgPayload.topic = config.GAbatterysensor;
|
|
52
57
|
knxMsgPayload.dpt = config.dptbatterysensor;
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
node.
|
|
59
|
-
grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Setup the output msg
|
|
64
|
-
knxMsgPayload.name = node.name;
|
|
65
|
-
knxMsgPayload.event = 'power_state';
|
|
66
|
-
|
|
67
|
-
// Send payload
|
|
68
|
-
knxMsgPayload.rawEvent = _event;
|
|
69
|
-
node.send(knxMsgPayload);
|
|
70
|
-
node.setNodeStatusHue({
|
|
71
|
-
fill: 'blue', shape: 'ring', text: 'HUE->KNX', payload: knxMsgPayload.payload,
|
|
59
|
+
knxMsgPayload.payload = _event.power_state.battery_level;
|
|
60
|
+
// Send to KNX bus
|
|
61
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
62
|
+
node.server.writeQueueAdd({
|
|
63
|
+
grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id,
|
|
72
64
|
});
|
|
73
65
|
}
|
|
66
|
+
|
|
67
|
+
// Setup the output msg
|
|
68
|
+
knxMsgPayload.name = node.name;
|
|
69
|
+
knxMsgPayload.event = 'power_state';
|
|
70
|
+
|
|
71
|
+
// Send payload
|
|
72
|
+
knxMsgPayload.rawEvent = _event;
|
|
73
|
+
node.send(knxMsgPayload);
|
|
74
|
+
node.setNodeStatusHue({
|
|
75
|
+
fill: 'blue', shape: 'ring', text: 'HUE->KNX', payload: knxMsgPayload.payload,
|
|
76
|
+
});
|
|
77
|
+
|
|
74
78
|
}
|
|
75
79
|
} catch (error) {
|
|
76
80
|
node.status({ fill: 'red', shape: 'dot', text: `HUE->KNX error ${error.message} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})` });
|
|
@@ -76,6 +76,11 @@ module.exports = function (RED) {
|
|
|
76
76
|
node.handleSendHUE = (_event) => {
|
|
77
77
|
try {
|
|
78
78
|
if (_event.id === config.hueDevice) {
|
|
79
|
+
|
|
80
|
+
// IMPORTANT: exit if no button last_event present.
|
|
81
|
+
if (_event.initializingAtStart === true) return;
|
|
82
|
+
if (!_event.hasOwnProperty("button") || _event.button.last_event === undefined) return;
|
|
83
|
+
|
|
79
84
|
const knxMsgPayload = {};
|
|
80
85
|
let flowMsgPayload = true;
|
|
81
86
|
// Handling events with toggles
|
|
@@ -85,11 +85,20 @@
|
|
|
85
85
|
GADaylightSensor: { value: "" },
|
|
86
86
|
dptDaylightSensor: { value: "" },
|
|
87
87
|
|
|
88
|
+
nameLightKelvin: { value: "" },
|
|
89
|
+
GALightKelvin: { value: "" },
|
|
90
|
+
dptLightKelvin: { value: "" },
|
|
91
|
+
|
|
92
|
+
nameLightKelvinState: { value: "" },
|
|
93
|
+
GALightKelvinState: { value: "" },
|
|
94
|
+
dptLightKelvinState: { value: "" },
|
|
95
|
+
|
|
88
96
|
specifySwitchOnBrightness: { value: "yes" },
|
|
89
97
|
updateKNXBrightnessStatusOnHUEOnOff: { value: "no" },
|
|
90
98
|
dimSpeed: { value: 5000, required: false },
|
|
91
99
|
minDimLevelLight: { value: 10, required: false },
|
|
92
100
|
maxDimLevelLight: { value: 100, required: false },
|
|
101
|
+
readStatusAtStartup: { value: "yes" },
|
|
93
102
|
|
|
94
103
|
hueDevice: { value: "" },
|
|
95
104
|
},
|
|
@@ -127,23 +136,25 @@
|
|
|
127
136
|
<div class="red-ui-sidebar-header">Color Selector</div>
|
|
128
137
|
</head>
|
|
129
138
|
<div style='position:relative;height:100%;margin:10px'>
|
|
130
|
-
<p>Choose the desired color/temperature,
|
|
139
|
+
<p>Choose the desired color/temperature, then click <b>Apply</b></p>
|
|
131
140
|
<div>
|
|
132
|
-
<h3>Color</h3>
|
|
141
|
+
<h3>Color RGB</h3>
|
|
133
142
|
<div id="colorPicker"></div>
|
|
134
143
|
</div>
|
|
135
|
-
</br>
|
|
144
|
+
</br>
|
|
145
|
+
<div>
|
|
146
|
+
<input style="width:100%" type="text" id="resultRGB">
|
|
147
|
+
<input type="hidden" id="tabNRColor_destinationTextbox">
|
|
148
|
+
</div>
|
|
149
|
+
</br>
|
|
136
150
|
<div>
|
|
137
|
-
<h3>Temperature</h3>
|
|
151
|
+
<h3>Temperature Kelvin</h3>
|
|
138
152
|
<div id="kelvinPicker"></div>
|
|
139
153
|
</div>
|
|
140
|
-
</br>
|
|
154
|
+
</br>
|
|
141
155
|
<div>
|
|
142
|
-
<
|
|
143
|
-
<
|
|
144
|
-
<input style="width:100%" type="text" id="resultRGB">
|
|
145
|
-
<input type="hidden" id="tabNRColor_destinationTextbox">
|
|
146
|
-
</div>
|
|
156
|
+
<input style="width:100%" type="text" id="resultKelvin">
|
|
157
|
+
<input type="hidden" id="tabNRColor_destinationTextbox">
|
|
147
158
|
</div>
|
|
148
159
|
<div id="tabNRColor_divApplyCancel" hidden>
|
|
149
160
|
<button id="tabNRColor_colorSelectorTABApplyTextButton" type="button" class="red-ui-button">Apply</button>
|
|
@@ -185,7 +196,18 @@
|
|
|
185
196
|
node.kelvinPicker.on("color:change", function (color) {
|
|
186
197
|
const resultRGBForNode = '{"red": ' + color.rgb.r + ', "green": ' + color.rgb.g + ', "blue": ' + color.rgb.b + "}";
|
|
187
198
|
$("#resultRGB").val(resultRGBForNode);
|
|
199
|
+
$("#resultKelvin").val(Math.round(color.kelvin, 0));
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
$("#resultKelvin").on("keyup", function () {
|
|
203
|
+
setIroColorKelvin();
|
|
188
204
|
});
|
|
205
|
+
function setIroColorKelvin() {
|
|
206
|
+
try {
|
|
207
|
+
const color = JSON.parse($("#resultKelvin").val());
|
|
208
|
+
node.kelvinPicker.color.setChannel("kelvin", color);
|
|
209
|
+
} catch (error) { }
|
|
210
|
+
}
|
|
189
211
|
|
|
190
212
|
// Color
|
|
191
213
|
node.colorPicker = new iro.ColorPicker("#colorPicker", {
|
|
@@ -212,6 +234,7 @@
|
|
|
212
234
|
const resultRGBForNode = '{"red": ' + color.rgb.r + ', "green": ' + color.rgb.g + ', "blue": ' + color.rgb.b + "}";
|
|
213
235
|
$("#resultRGB").val(resultRGBForNode);
|
|
214
236
|
});
|
|
237
|
+
|
|
215
238
|
$("#resultRGB").on("keyup", function () {
|
|
216
239
|
setIroColor();
|
|
217
240
|
});
|
|
@@ -229,7 +252,12 @@
|
|
|
229
252
|
// navigator.clipboard.writeText(aa)
|
|
230
253
|
const destTextBox = "#" + $("#tabNRColor_destinationTextbox").val();
|
|
231
254
|
const resultRGB = $("#resultRGB").val();
|
|
232
|
-
|
|
255
|
+
const resultKelvin = node.kelvinPicker.colors[0].kelvin;
|
|
256
|
+
if (destTextBox === "#node-input-colorAtSwitchOnNightTime" || destTextBox === "#node-input-colorAtSwitchOnDayTime") {
|
|
257
|
+
$(destTextBox).val(resultRGB);
|
|
258
|
+
} else {
|
|
259
|
+
$(destTextBox).val(resultKelvin);
|
|
260
|
+
}
|
|
233
261
|
// Flash the destination control
|
|
234
262
|
$(destTextBox).css("background-color", "lightgreen");
|
|
235
263
|
$("#tabNRColor_divApplyCancel").hide();
|
|
@@ -379,6 +407,13 @@
|
|
|
379
407
|
getDPT("1.", "#node-input-dptDaylightSensor");
|
|
380
408
|
getGroupAddress("#node-input-GADaylightSensor", "#node-input-nameDaylightSensor", "#node-input-dptDaylightSensor", " 1.");
|
|
381
409
|
|
|
410
|
+
getDPT("7.600", "#node-input-dptLightKelvin");
|
|
411
|
+
getGroupAddress("#node-input-GALightKelvin", "#node-input-nameLightKelvin", "#node-input-dptLightKelvin", " 7.600");
|
|
412
|
+
|
|
413
|
+
getDPT("7.600", "#node-input-dptLightKelvinState");
|
|
414
|
+
getGroupAddress("#node-input-GALightKelvinState", "#node-input-nameLightKelvinState", "#node-input-dptLightKelvinState", " 7.600");
|
|
415
|
+
|
|
416
|
+
|
|
382
417
|
// Show/Hide and enable/disable day/night Lighting behaviour
|
|
383
418
|
if (this.enableDayNightLighting === "yes") {
|
|
384
419
|
$("#divEnableDayNightLighting").show();
|
|
@@ -483,7 +518,6 @@
|
|
|
483
518
|
});
|
|
484
519
|
|
|
485
520
|
$("#getColorAtSwitchOnDayTimeButton").on("click", function () {
|
|
486
|
-
// Get the HUE capabilities to enable/disable UI parts
|
|
487
521
|
$("#getColorAtSwitchOnDayTimeButton").text("Wait...");
|
|
488
522
|
$.getJSON("knxUltimateGetHueColor?id=" + $("#node-input-hueDevice").val().split("#")[0], (data) => {
|
|
489
523
|
$("#node-input-colorAtSwitchOnDayTime").val(data.toString());
|
|
@@ -495,7 +529,6 @@
|
|
|
495
529
|
});
|
|
496
530
|
});
|
|
497
531
|
$("#getColorAtSwitchOnNightTimeButton").on("click", function () {
|
|
498
|
-
// Get the HUE capabilities to enable/disable UI parts
|
|
499
532
|
$("#getColorAtSwitchOnNightTimeButton").text("Wait...");
|
|
500
533
|
$.getJSON("knxUltimateGetHueColor?id=" + $("#node-input-hueDevice").val().split("#")[0], (data) => {
|
|
501
534
|
$("#node-input-colorAtSwitchOnNightTime").val(data.toString());
|
|
@@ -527,6 +560,8 @@
|
|
|
527
560
|
$("#node-input-maxDimLevelLight").val(node.maxDimLevelLight);
|
|
528
561
|
|
|
529
562
|
if (this.hueDevice !== "") $("#tabs").show();
|
|
563
|
+
|
|
564
|
+
|
|
530
565
|
},
|
|
531
566
|
oneditsave: function () {
|
|
532
567
|
RED.sidebar.removeTab("tabNRColor");
|
|
@@ -664,43 +699,68 @@
|
|
|
664
699
|
</div>
|
|
665
700
|
<div id="tabs-3">
|
|
666
701
|
<p>
|
|
667
|
-
|
|
668
|
-
|
|
702
|
+
<div class="form-row">
|
|
703
|
+
<label for="node-input-nameLightHSV" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control dim</label>
|
|
669
704
|
|
|
670
|
-
|
|
671
|
-
|
|
705
|
+
<label for="node-input-GALightHSV" style="width:20px;">GA</label>
|
|
706
|
+
<input type="text" id="node-input-GALightHSV" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
672
707
|
|
|
673
|
-
|
|
674
|
-
|
|
708
|
+
<label for="node-input-dptLightHSV" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
|
|
709
|
+
<select id="node-input-dptLightHSV" style="width:140px;"></select>
|
|
675
710
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
711
|
+
<label for="node-input-nameLightHSV" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
712
|
+
<input type="text" id="node-input-nameLightHSV" style="width:190px;margin-left: 5px; text-align: left;">
|
|
713
|
+
</div>
|
|
714
|
+
<div class="form-row">
|
|
715
|
+
<label for="node-input-nameLightHSVPercentage" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control %</label>
|
|
716
|
+
|
|
717
|
+
<label for="node-input-GALightHSVPercentage" style="width:20px;">GA</label>
|
|
718
|
+
<input type="text" id="node-input-GALightHSVPercentage" placeholder="Ex: 1/1/1"
|
|
719
|
+
style="width:70px;margin-left: 5px; text-align: left;">
|
|
720
|
+
|
|
721
|
+
<label for="node-input-dptLightHSVPercentage" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
|
|
722
|
+
<select id="node-input-dptLightHSVPercentage" style="width:140px;"></select>
|
|
723
|
+
|
|
724
|
+
<label for="node-input-nameLightHSVPercentage" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
725
|
+
<input type="text" id="node-input-nameLightHSVPercentage" style="width:190px;margin-left: 5px; text-align: left;">
|
|
726
|
+
</div>
|
|
727
|
+
<div class="form-row">
|
|
728
|
+
<label for="node-input-nameLightKelvin" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control Kelvin</label>
|
|
681
729
|
|
|
682
|
-
<label for="node-input-
|
|
683
|
-
<input type="text" id="node-input-
|
|
730
|
+
<label for="node-input-GALightKelvin" style="width:20px;">GA</label>
|
|
731
|
+
<input type="text" id="node-input-GALightKelvin" placeholder="Ex: 1/1/1"
|
|
684
732
|
style="width:70px;margin-left: 5px; text-align: left;">
|
|
685
733
|
|
|
686
|
-
<label for="node-input-
|
|
687
|
-
<select id="node-input-
|
|
734
|
+
<label for="node-input-dptLightKelvin" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
|
|
735
|
+
<select id="node-input-dptLightKelvin" style="width:140px;"></select>
|
|
688
736
|
|
|
689
|
-
<label for="node-input-
|
|
690
|
-
<input type="text" id="node-input-
|
|
737
|
+
<label for="node-input-nameLightKelvin" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
738
|
+
<input type="text" id="node-input-nameLightKelvin" style="width:190px;margin-left: 5px; text-align: left;">
|
|
691
739
|
</div>
|
|
692
|
-
|
|
693
|
-
|
|
740
|
+
<div class="form-row">
|
|
741
|
+
<label for="node-input-nameLightHSVState" style="width:110px;"><i class="fa fa-play-circle-o"></i> Status %</label>
|
|
694
742
|
|
|
695
|
-
|
|
696
|
-
|
|
743
|
+
<label for="node-input-GALightHSVState" style="width:20px;"><span data-i18n="knxUltimateHueLight.node-input-GALightState"></span></label>
|
|
744
|
+
<input type="text" id="node-input-GALightHSVState" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
697
745
|
|
|
698
|
-
|
|
699
|
-
|
|
746
|
+
<label for="node-input-dptLightHSVState" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
|
|
747
|
+
<select id="node-input-dptLightHSVState" style="width:140px;"></select>
|
|
700
748
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
749
|
+
<label for="node-input-nameLightHSVState" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
750
|
+
<input type="text" id="node-input-nameLightHSVState" style="width:190px;margin-left: 5px; text-align: left;">
|
|
751
|
+
</div>
|
|
752
|
+
<div class="form-row">
|
|
753
|
+
<label for="node-input-nameLightKelvinState" style="width:110px;"><i class="fa fa-play-circle-o"></i> Status Kelvin</label>
|
|
754
|
+
|
|
755
|
+
<label for="node-input-GALightKelvinState" style="width:20px;">GA</label>
|
|
756
|
+
<input type="text" id="node-input-GALightKelvinState" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
757
|
+
|
|
758
|
+
<label for="node-input-dptLightKelvinState" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
|
|
759
|
+
<select id="node-input-dptLightKelvinState" style="width:140px;"></select>
|
|
760
|
+
|
|
761
|
+
<label for="node-input-nameLightKelvinState" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
762
|
+
<input type="text" id="node-input-nameLightKelvinState" style="width:190px;margin-left: 5px; text-align: left;">
|
|
763
|
+
</div>
|
|
704
764
|
</p>
|
|
705
765
|
</div>
|
|
706
766
|
<div id="tabs-4">
|
|
@@ -765,7 +825,14 @@
|
|
|
765
825
|
<div id="tabs-6">
|
|
766
826
|
<p>
|
|
767
827
|
<div class="form-row">
|
|
768
|
-
|
|
828
|
+
<label style="width:260px;" for="node-input-readStatusAtStartup"><i class="fa fa-play-circle"></i> Read status at startup</label>
|
|
829
|
+
<select id="node-input-readStatusAtStartup">
|
|
830
|
+
<option value="no">No</option>
|
|
831
|
+
<option value="yes">Yes, and emit KNX telegrams.</option>
|
|
832
|
+
</select>
|
|
833
|
+
</div>
|
|
834
|
+
<div class="form-row">
|
|
835
|
+
<label style="width:260px;" for="node-input-updateKNXBrightnessStatusOnHUEOnOff">
|
|
769
836
|
<i class="fa fa-tag"></i> KNX Brightness Status
|
|
770
837
|
</label>
|
|
771
838
|
<select id="node-input-updateKNXBrightnessStatusOnHUEOnOff">
|
|
@@ -899,9 +966,11 @@
|
|
|
899
966
|
**Tunable white**
|
|
900
967
|
|Property|Description|
|
|
901
968
|
|--|--|
|
|
902
|
-
| Control| Changes the HUE light's white temperature, using DPT 3.007 dimming. You can set the dimming speed in the **_Behaviour_** tab.|
|
|
969
|
+
| Control dim | Changes the HUE light's white temperature, using DPT 3.007 dimming. You can set the dimming speed in the **_Behaviour_** tab.|
|
|
903
970
|
| Control % | Changes the HUE light's white temperature, using the DPT 5.001. A value of 0 is full warm, a value of 100 is full cold.|
|
|
904
|
-
|
|
|
971
|
+
| Control kelvin | Changes the HUE light's temperature in Kelvin degrees, using the DPT 7.600. |
|
|
972
|
+
| Status %| Link this to the light temperature status group address. Datapoint is 5.001 absolute value. 0 is full warm, 100 is full cold.|
|
|
973
|
+
| Status kelvin | Link this to the light temperature status group address. Datapoint 7.600. |
|
|
905
974
|
|
|
906
975
|
<br/>
|
|
907
976
|
|
|
@@ -935,6 +1004,7 @@
|
|
|
935
1004
|
| Dim Speed (ms) | The dimming speed, in Milliseconds. This applies to the **light** and also to the **tunable white** dimming datapoints. It' calculated from 0% to 100%. |
|
|
936
1005
|
| Min Dim brightness | Tha Minimum brightness that the lamp can reach. For example, if you are dimming the light down, the light will stop dimming at the specified brightness %. |
|
|
937
1006
|
| Max Dim brightness | Tha Maximum brightness that the lamp can reach. For example, if you are dimming the light up, the light will stop dimming at the specified brightness %. |
|
|
1007
|
+
| Read status at startup | Read the status at startup and emit the event to the KNX bus at startup/reconnection. (Default "no")|
|
|
938
1008
|
|
|
939
1009
|
### Note
|
|
940
1010
|
|
|
@@ -35,6 +35,8 @@ module.exports = function (RED) {
|
|
|
35
35
|
node.DayTime = true;
|
|
36
36
|
node.isGrouped_light = config.hueDevice.split("#")[1] === "grouped_light";
|
|
37
37
|
node.hueDevice = config.hueDevice.split("#")[0];
|
|
38
|
+
node.readStatusAtStartup = config.readStatusAtStartup;
|
|
39
|
+
if (config.readStatusAtStartup === undefined) node.readStatusAtStartup = "yes";
|
|
38
40
|
|
|
39
41
|
// Used to call the status update from the config node.
|
|
40
42
|
node.setNodeStatus = ({
|
|
@@ -58,9 +60,9 @@ module.exports = function (RED) {
|
|
|
58
60
|
node.handleSend = (msg) => {
|
|
59
61
|
if (node.currentHUEDevice === undefined) {
|
|
60
62
|
node.setNodeStatusHue({
|
|
61
|
-
fill: "
|
|
63
|
+
fill: "grey",
|
|
62
64
|
shape: "ring",
|
|
63
|
-
text: "
|
|
65
|
+
text: "Initializing. Please wait.",
|
|
64
66
|
payload: "",
|
|
65
67
|
});
|
|
66
68
|
return;
|
|
@@ -124,6 +126,18 @@ module.exports = function (RED) {
|
|
|
124
126
|
fill: "green", shape: "dot", text: "KNX->HUE", payload: JSON.stringify(msg.payload),
|
|
125
127
|
});
|
|
126
128
|
break;
|
|
129
|
+
case config.GALightKelvin:
|
|
130
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvin));
|
|
131
|
+
let retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 65535], [153, 500]);
|
|
132
|
+
state = { color_temperature: { mirek: retMirek } };
|
|
133
|
+
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
134
|
+
node.setNodeStatusHue({
|
|
135
|
+
fill: "green",
|
|
136
|
+
shape: "dot",
|
|
137
|
+
text: "KNX->HUE",
|
|
138
|
+
payload: state,
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
127
141
|
case config.GADaylightSensor:
|
|
128
142
|
if (config.enableDayNightLighting === "yes") {
|
|
129
143
|
node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)));
|
|
@@ -166,12 +180,6 @@ module.exports = function (RED) {
|
|
|
166
180
|
payload: state,
|
|
167
181
|
});
|
|
168
182
|
}
|
|
169
|
-
node.setNodeStatusHue({
|
|
170
|
-
fill: "green",
|
|
171
|
-
shape: "dot",
|
|
172
|
-
text: "KNX->HUE",
|
|
173
|
-
payload: msg.payload,
|
|
174
|
-
});
|
|
175
183
|
break;
|
|
176
184
|
case config.GALightBrightness:
|
|
177
185
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBrightness));
|
|
@@ -419,6 +427,9 @@ module.exports = function (RED) {
|
|
|
419
427
|
});
|
|
420
428
|
return;
|
|
421
429
|
}
|
|
430
|
+
// IMPORTANT: exit if no button last_event present.
|
|
431
|
+
if (_event.initializingAtStart === true && node.readStatusAtStartup === "no") return;
|
|
432
|
+
|
|
422
433
|
if (_event.hasOwnProperty("on")) {
|
|
423
434
|
node.updateKNXLightState(_event.on.on);
|
|
424
435
|
// In case of switch off, set the dim to zero
|
|
@@ -428,13 +439,6 @@ module.exports = function (RED) {
|
|
|
428
439
|
) {
|
|
429
440
|
node.updateKNXBrightnessState(0);
|
|
430
441
|
node.currentHUEDevice.dimming.brightness = 0;
|
|
431
|
-
} else {
|
|
432
|
-
// // Sends the previous brightness value
|
|
433
|
-
// try {
|
|
434
|
-
// node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
435
|
-
// } catch (error) {
|
|
436
|
-
// /* empty */
|
|
437
|
-
// }
|
|
438
442
|
}
|
|
439
443
|
node.currentHUEDevice.on.on = _event.on.on;
|
|
440
444
|
}
|
|
@@ -468,24 +472,9 @@ module.exports = function (RED) {
|
|
|
468
472
|
}
|
|
469
473
|
if (_event.hasOwnProperty("color_temperature") && _event.color_temperature.mirek !== undefined) {
|
|
470
474
|
node.updateKNXLightHSVState(_event.color_temperature.mirek);
|
|
475
|
+
node.updateKNXLightKelvinState(_event.color_temperature.mirek);
|
|
471
476
|
node.currentHUEDevice.color_temperature.mirek = _event.color_temperature.mirek;
|
|
472
477
|
}
|
|
473
|
-
|
|
474
|
-
// // Update the current HUE Device with the new _event
|
|
475
|
-
// function copiaOggettoRicorsivo(objDestinazione, objOrigine) {
|
|
476
|
-
// for (const prop in objOrigine) {
|
|
477
|
-
// if (typeof objOrigine[prop] === "object" && objOrigine[prop] !== null) {
|
|
478
|
-
// // Se la proprietà è un oggetto, copiamola in modo ricorsivo
|
|
479
|
-
// objDestinazione[prop] = objDestinazione[prop] || {};
|
|
480
|
-
// copiaOggettoRicorsivo(objDestinazione[prop], objOrigine[prop]);
|
|
481
|
-
// } else {
|
|
482
|
-
// // Altrimenti, copia il valore della proprietà
|
|
483
|
-
// objDestinazione[prop] = objOrigine[prop];
|
|
484
|
-
// }
|
|
485
|
-
// }
|
|
486
|
-
// }
|
|
487
|
-
// // Copia l'oggettoOrigine nell'oggettoDestinazione mantenendo le proprietà esistenti
|
|
488
|
-
// copiaOggettoRicorsivo(node.currentHUEDevice, _event);
|
|
489
478
|
}
|
|
490
479
|
} catch (error) {
|
|
491
480
|
node.status({
|
|
@@ -612,7 +601,32 @@ module.exports = function (RED) {
|
|
|
612
601
|
}
|
|
613
602
|
};
|
|
614
603
|
|
|
615
|
-
|
|
604
|
+
node.updateKNXLightKelvinState = function updateKNXLightKelvinState(_value) {
|
|
605
|
+
if (config.GALightKelvinState !== undefined && config.GALightKelvinState !== "") {
|
|
606
|
+
const knxMsgPayload = {};
|
|
607
|
+
knxMsgPayload.topic = config.GALightKelvinState;
|
|
608
|
+
knxMsgPayload.dpt = config.dptLightKelvinState;
|
|
609
|
+
if (config.dptLightKelvinState === "7.600") {
|
|
610
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.scale(_value, [153, 500], [0, 65535]);
|
|
611
|
+
// Send to KNX bus
|
|
612
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
613
|
+
node.server.writeQueueAdd({
|
|
614
|
+
grpaddr: knxMsgPayload.topic,
|
|
615
|
+
payload: knxMsgPayload.payload,
|
|
616
|
+
dpt: knxMsgPayload.dpt,
|
|
617
|
+
outputtype: "write",
|
|
618
|
+
nodecallerid: node.id,
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
node.setNodeStatusHue({
|
|
622
|
+
fill: "blue",
|
|
623
|
+
shape: "ring",
|
|
624
|
+
text: "HUE->KNX HSV",
|
|
625
|
+
payload: knxMsgPayload.payload,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
};
|
|
616
630
|
|
|
617
631
|
// On each deploy, unsubscribe+resubscribe
|
|
618
632
|
if (node.server) {
|
|
@@ -620,8 +634,12 @@ module.exports = function (RED) {
|
|
|
620
634
|
node.server.addClient(node);
|
|
621
635
|
}
|
|
622
636
|
if (node.serverHue) {
|
|
623
|
-
|
|
624
|
-
|
|
637
|
+
try {
|
|
638
|
+
node.serverHue.removeClient(node);
|
|
639
|
+
node.serverHue.addClient(node);
|
|
640
|
+
} catch (error) {
|
|
641
|
+
RED.log.error("knxUltimateHueLight: if (node.server): " + error.message);
|
|
642
|
+
}
|
|
625
643
|
}
|
|
626
644
|
|
|
627
645
|
node.on("input", (msg) => { });
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
namelightsensor: { value: "" },
|
|
12
12
|
GAlightsensor: { value: "" },
|
|
13
13
|
dptlightsensor: { value: "" },
|
|
14
|
+
readStatusAtStartup: { value: "no" },
|
|
14
15
|
|
|
15
16
|
hueDevice: { value: "" }
|
|
16
17
|
},
|
|
@@ -211,7 +212,13 @@
|
|
|
211
212
|
<input type="text" id="node-input-namelightsensor" style="width:200px;margin-left: 5px; text-align: left;">
|
|
212
213
|
</div>
|
|
213
214
|
|
|
214
|
-
|
|
215
|
+
<div class="form-row">
|
|
216
|
+
<label style="width:180px" for="node-input-readStatusAtStartup"><i class="fa fa-play-circle"></i> Read status at startup</label>
|
|
217
|
+
<select id="node-input-readStatusAtStartup">
|
|
218
|
+
<option value="no">No</option>
|
|
219
|
+
<option value="yes">Yes, and emit KNX telegrams.</option>
|
|
220
|
+
</select>
|
|
221
|
+
</div>
|
|
215
222
|
|
|
216
223
|
|
|
217
224
|
<br/>
|
|
@@ -234,6 +241,7 @@ Start typing in the GA field, the name or group address of your KNX device, the
|
|
|
234
241
|
| KNX GW | Select the KNX gateway to be used |
|
|
235
242
|
| HUE Bridge | Select the HUE Bridge to be used |
|
|
236
243
|
| Hue Sensor | HUE sensor to be used. The avaiable buttons start showing up while you're typing.|
|
|
244
|
+
| Read status at startup | Read the status at startup and emit the event to the KNX bus at startup/reconnection. (Default "no")|
|
|
237
245
|
|
|
238
246
|
|Property|Description|
|
|
239
247
|
|--|--|
|
|
@@ -43,6 +43,11 @@ module.exports = function (RED) {
|
|
|
43
43
|
node.handleSendHUE = _event => {
|
|
44
44
|
try {
|
|
45
45
|
if (_event.id === config.hueDevice) {
|
|
46
|
+
|
|
47
|
+
// IMPORTANT: exit if no event presen.
|
|
48
|
+
if (_event.initializingAtStart === true && (config.readStatusAtStartup === undefined || config.readStatusAtStartup === "no")) return;
|
|
49
|
+
if (!_event.hasOwnProperty('light') || _event.light.light_level === undefined) return;
|
|
50
|
+
|
|
46
51
|
const knxMsgPayload = {};
|
|
47
52
|
knxMsgPayload.topic = config.GAlightsensor;
|
|
48
53
|
knxMsgPayload.dpt = config.dptlightsensor;
|
|
@@ -235,7 +235,7 @@ Start typing in the GA field, the name or group address of your KNX device, the
|
|
|
235
235
|
|Property|Description|
|
|
236
236
|
|--|--|
|
|
237
237
|
| Motion | As soon as someone moves in the motion device's range, a *true* KNX value is sent to this group address, otherwise *false* is sent. |
|
|
238
|
-
|
|
238
|
+
|
|
239
239
|
### Outputs
|
|
240
240
|
|
|
241
241
|
1. Standard output
|
|
@@ -40,6 +40,12 @@ module.exports = function (RED) {
|
|
|
40
40
|
node.handleSendHUE = (_event) => {
|
|
41
41
|
try {
|
|
42
42
|
if (_event.id === config.hueDevice) {
|
|
43
|
+
|
|
44
|
+
// IMPORTANT: exit if no event presen.
|
|
45
|
+
if (_event.initializingAtStart === true) return;
|
|
46
|
+
if (!_event.hasOwnProperty("motion") || _event.motion.motion === undefined) return;
|
|
47
|
+
|
|
48
|
+
|
|
43
49
|
const knxMsgPayload = {};
|
|
44
50
|
knxMsgPayload.topic = config.GAmotion;
|
|
45
51
|
knxMsgPayload.dpt = config.dptmotion;
|
|
@@ -78,6 +78,10 @@ module.exports = function (RED) {
|
|
|
78
78
|
node.handleSendHUE = _event => {
|
|
79
79
|
try {
|
|
80
80
|
if (_event.id === config.hueDevice) {
|
|
81
|
+
|
|
82
|
+
// IMPORTANT: exit if no event presen.
|
|
83
|
+
if (_event.initializingAtStart === true) return;
|
|
84
|
+
|
|
81
85
|
// const knxMsgPayload = {}
|
|
82
86
|
// knxMsgPayload.topic = config.GAmotion
|
|
83
87
|
// knxMsgPayload.dpt = config.dptmotion
|
|
@@ -49,6 +49,17 @@ module.exports = function (RED) {
|
|
|
49
49
|
node.handleSendHUE = (_event) => {
|
|
50
50
|
try {
|
|
51
51
|
if (_event.id === config.hueDevice) {
|
|
52
|
+
|
|
53
|
+
// IMPORTANT: exit if no event presen.
|
|
54
|
+
if (_event.initializingAtStart === true) return;
|
|
55
|
+
if (!_event.hasOwnProperty("relative_rotary")
|
|
56
|
+
|| !_event.relative_rotary.hasOwnProperty("last_event")
|
|
57
|
+
|| _event.relative_rotary.last_event === undefined
|
|
58
|
+
|| !_event.relative_rotary.last_event.hasOwnProperty("rotation")
|
|
59
|
+
|| !_event.relative_rotary.last_event.rotation.direction === undefined
|
|
60
|
+
|| _event.relative_rotary.last_event.action === undefined) return;
|
|
61
|
+
|
|
62
|
+
|
|
52
63
|
const knxMsgPayload = {};
|
|
53
64
|
knxMsgPayload.topic = config.GArepeat;
|
|
54
65
|
knxMsgPayload.dpt = config.dptrepeat;
|
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.9",
|
|
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",
|