node-red-contrib-knx-ultimate 2.1.57 → 2.1.58
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 +66 -30
- package/nodes/knxUltimateHueLight.html +31 -3
- package/nodes/knxUltimateHueLight.js +0 -12
- package/nodes/utils/hueEngine.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
<p>
|
|
9
|
+
<b>Version 2.1.58</b> - October 2023<br/>
|
|
10
|
+
- HUE Light: NEW color picker. Just click a button to automatically fill the node's "color" properties<br/>
|
|
11
|
+
</p>
|
|
12
|
+
<p>
|
|
9
13
|
<b>Version 2.1.57</b> - October 2023<br/>
|
|
10
14
|
- HUE Light: NEW Behaviour "KNX Brightness Status"<br/>
|
|
11
15
|
- HUE Light: the light now remembers the last brightness value after switch off<br/>
|
package/nodes/hue-config.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const dptlib = require("../KNXEngine/src/dptlib");
|
|
4
4
|
const HueClass = require("./utils/hueEngine").classHUE;
|
|
5
5
|
const loggerEngine = require("./utils/sysLogger");
|
|
6
|
+
const hueColorConverter = require("./utils/hueColorConverter");
|
|
7
|
+
|
|
6
8
|
// Helpers
|
|
7
9
|
const sortBy = (field) => (a, b) => {
|
|
8
10
|
if (a[field] > b[field]) {
|
|
@@ -30,14 +32,12 @@ const convertSubtype = (baseType) => (kv) => {
|
|
|
30
32
|
|
|
31
33
|
const toConcattedSubtypes = (acc, baseType) => {
|
|
32
34
|
const subtypes = Object.entries(baseType.subtypes).sort(sortBy(0)).map(convertSubtype(baseType));
|
|
33
|
-
|
|
34
35
|
return acc.concat(subtypes);
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
module.exports = (RED) => {
|
|
38
39
|
RED.httpAdmin.get("/knxUltimateDpts", RED.auth.needsPermission("hue-config.read"), (req, res) => {
|
|
39
40
|
const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy("base")).reduce(toConcattedSubtypes, []);
|
|
40
|
-
|
|
41
41
|
res.json(dpts);
|
|
42
42
|
});
|
|
43
43
|
|
|
@@ -53,6 +53,7 @@ module.exports = (RED) => {
|
|
|
53
53
|
} catch (error) {
|
|
54
54
|
/* empty */
|
|
55
55
|
}
|
|
56
|
+
|
|
56
57
|
node.name = config.name === undefined || config.name === "" ? node.host : config.name;
|
|
57
58
|
|
|
58
59
|
// Init HUE Utility
|
|
@@ -83,38 +84,13 @@ module.exports = (RED) => {
|
|
|
83
84
|
});
|
|
84
85
|
// Initialize the http wrapper, to use the provided key.
|
|
85
86
|
// This http wrapper is used to get the data from HUE brigde
|
|
86
|
-
|
|
87
|
-
// Load all resources, to avoid too many call to the HUE bridge and speed up the showing of the device mnames, during typing in the config window
|
|
88
|
-
node.hueAllResources = await node.hueManager.hueApiV2.get("/resource");
|
|
89
|
-
node.hueAllRooms = await node.hueManager.hueApiV2.get("/resource/room");
|
|
90
|
-
node.hueAllDevices = await node.hueManager.hueApiV2.get("/resource/device");
|
|
91
|
-
} catch (error) {
|
|
92
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null) {
|
|
93
|
-
this.sysLogger.error(`KNXUltimatehueEngine: classHUE: getting resources: ${error.message}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
87
|
+
await node.refreshResources();
|
|
96
88
|
};
|
|
97
89
|
|
|
98
90
|
(async () => {
|
|
99
91
|
await node.ConnectToHueBridge();
|
|
100
92
|
})();
|
|
101
93
|
|
|
102
|
-
RED.httpAdmin.get("/KNXUltimateGetResourcesHUE", RED.auth.needsPermission("hue-config.read"), (req, res) => {
|
|
103
|
-
try {
|
|
104
|
-
// °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
|
|
105
|
-
const serverNode = RED.nodes.getNode(req.query.nodeID); // Retrieve node.id of the config node.
|
|
106
|
-
const jRet = serverNode.getResources(req.query.rtype);
|
|
107
|
-
res.json(jRet);
|
|
108
|
-
// °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
|
|
109
|
-
} catch (error) {
|
|
110
|
-
RED.log.error(`Errore KNXUltimateGetResourcesHUE non gestito ${error.message}`);
|
|
111
|
-
res.json({ devices: error.message });
|
|
112
|
-
(async () => {
|
|
113
|
-
await node.ConnectToHueBridge();
|
|
114
|
-
})();
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
94
|
// Get all devices and join it with relative rooms, by adding the room name to the device name
|
|
119
95
|
node.getResources = (_rtype) => {
|
|
120
96
|
try {
|
|
@@ -123,7 +99,6 @@ module.exports = (RED) => {
|
|
|
123
99
|
if (typeof s !== "string") return "";
|
|
124
100
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
125
101
|
}
|
|
126
|
-
|
|
127
102
|
const retArray = [];
|
|
128
103
|
let allResources;
|
|
129
104
|
if (_rtype === "light" || _rtype === "grouped_light") {
|
|
@@ -230,6 +205,40 @@ module.exports = (RED) => {
|
|
|
230
205
|
return { devices: error.message };
|
|
231
206
|
}
|
|
232
207
|
};
|
|
208
|
+
node.refreshResources = () => new Promise((resolve, reject) => {
|
|
209
|
+
(async () => {
|
|
210
|
+
// Reload all resources
|
|
211
|
+
try {
|
|
212
|
+
node.hueAllResources = await node.hueManager.hueApiV2.get("/resource");
|
|
213
|
+
node.hueAllRooms = node.hueAllResources.filter((a) => a.type === "room");
|
|
214
|
+
resolve(true);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null) {
|
|
217
|
+
this.sysLogger.error(`KNXUltimatehueEngine: getting resources: ${error.message}`);
|
|
218
|
+
reject(error.message);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
})();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Get all devices and join it with relative rooms, by adding the room name to the device name
|
|
225
|
+
node.getColorFromHueLight = (_lightId) => new Promise((resolve, reject) => {
|
|
226
|
+
(async () => {
|
|
227
|
+
try {
|
|
228
|
+
await node.refreshResources();
|
|
229
|
+
const oLight = node.hueAllResources.filter((a) => a.id === _lightId)[0];
|
|
230
|
+
const ret = hueColorConverter.ColorConverter.xyBriToRgb(
|
|
231
|
+
oLight.color.xy.x,
|
|
232
|
+
oLight.color.xy.y,
|
|
233
|
+
oLight.dimming.brightness,
|
|
234
|
+
);
|
|
235
|
+
resolve(JSON.stringify(ret));
|
|
236
|
+
} catch (error) {
|
|
237
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: getColorFromHueLight: error ${error.message}`);
|
|
238
|
+
reject(error.message);
|
|
239
|
+
}
|
|
240
|
+
})();
|
|
241
|
+
});
|
|
233
242
|
|
|
234
243
|
node.addClient = (_Node) => {
|
|
235
244
|
// Check if node already exists
|
|
@@ -248,7 +257,7 @@ module.exports = (RED) => {
|
|
|
248
257
|
// Remove the client node from the clients array
|
|
249
258
|
try {
|
|
250
259
|
node.nodeClients = node.nodeClients.filter((x) => x.id !== _Node.id);
|
|
251
|
-
} catch (error) { }
|
|
260
|
+
} catch (error) { /* empty */ }
|
|
252
261
|
};
|
|
253
262
|
|
|
254
263
|
node.on("close", (done) => {
|
|
@@ -271,6 +280,33 @@ module.exports = (RED) => {
|
|
|
271
280
|
done();
|
|
272
281
|
}
|
|
273
282
|
});
|
|
283
|
+
|
|
284
|
+
RED.httpAdmin.get("/knxUltimateGetHueColor", RED.auth.needsPermission("hue-config.read"), (req, res) => {
|
|
285
|
+
(async () => {
|
|
286
|
+
try {
|
|
287
|
+
const rgbColor = await node.getColorFromHueLight(req.query.id);
|
|
288
|
+
res.json(rgbColor);
|
|
289
|
+
} catch (error) {
|
|
290
|
+
res.json("Select the device first!");
|
|
291
|
+
}
|
|
292
|
+
})();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
RED.httpAdmin.get("/KNXUltimateGetResourcesHUE", RED.auth.needsPermission("hue-config.read"), (req, res) => {
|
|
296
|
+
try {
|
|
297
|
+
// °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
|
|
298
|
+
const serverNode = RED.nodes.getNode(req.query.nodeID); // Retrieve node.id of the config node.
|
|
299
|
+
const jRet = serverNode.getResources(req.query.rtype);
|
|
300
|
+
res.json(jRet);
|
|
301
|
+
// °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
|
|
302
|
+
} catch (error) {
|
|
303
|
+
RED.log.error(`Errore KNXUltimateGetResourcesHUE non gestito ${error.message}`);
|
|
304
|
+
res.json({ devices: error.message });
|
|
305
|
+
(async () => {
|
|
306
|
+
await node.ConnectToHueBridge();
|
|
307
|
+
})();
|
|
308
|
+
}
|
|
309
|
+
});
|
|
274
310
|
}
|
|
275
311
|
|
|
276
312
|
// RED.nodes.registerType("hue-config", hue-config);
|
|
@@ -96,6 +96,13 @@
|
|
|
96
96
|
var oNodeServer = RED.nodes.node($("#node-input-server").val()); // Store the config-node
|
|
97
97
|
var oNodeServerHue = RED.nodes.node($("#node-input-serverHue").val()); // Store the config-node
|
|
98
98
|
|
|
99
|
+
// var colorPicker = new iro.ColorPicker("#picker", {
|
|
100
|
+
// // Set the size of the color picker
|
|
101
|
+
// width: 320,
|
|
102
|
+
// // Set the initial color to pure red
|
|
103
|
+
// color: "#f00"
|
|
104
|
+
// });
|
|
105
|
+
|
|
99
106
|
$("#tabs").tabs();
|
|
100
107
|
|
|
101
108
|
// 19/02/2020 Used to get the server sooner als deploy.
|
|
@@ -268,6 +275,7 @@
|
|
|
268
275
|
} else {
|
|
269
276
|
$('#node-input-hueDevice').val(ui.item.hueDevice + "#light");
|
|
270
277
|
}
|
|
278
|
+
$('#tabs').show();
|
|
271
279
|
}
|
|
272
280
|
});
|
|
273
281
|
|
|
@@ -293,8 +301,26 @@
|
|
|
293
301
|
});
|
|
294
302
|
});
|
|
295
303
|
|
|
296
|
-
// ########################
|
|
297
304
|
|
|
305
|
+
$("#getHueColorButton").on("click", function () {
|
|
306
|
+
// Get the HUE capabilities to enable/disable UI parts
|
|
307
|
+
$("#getHueColorButton").text("Wait...")
|
|
308
|
+
$.getJSON("knxUltimateGetHueColor?id=" + $('#node-input-hueDevice').val().split('#')[0], (data) => {
|
|
309
|
+
$('#node-input-colorAtSwitchOnDayTime').val(data.toString());
|
|
310
|
+
$("#getHueColorButton").text("Get current")
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
$("#getColorAtSwitchOnNightTime").on("click", function () {
|
|
314
|
+
// Get the HUE capabilities to enable/disable UI parts
|
|
315
|
+
$("#getColorAtSwitchOnNightTime").text("Wait...")
|
|
316
|
+
$.getJSON("knxUltimateGetHueColor?id=" + $('#node-input-hueDevice').val().split('#')[0], (data) => {
|
|
317
|
+
$('#node-input-colorAtSwitchOnNightTime').val(data.toString());
|
|
318
|
+
$("#getColorAtSwitchOnNightTime").text("Get current")
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// ########################
|
|
323
|
+
if (this.hueDevice !== "") $('#tabs').show();
|
|
298
324
|
|
|
299
325
|
},
|
|
300
326
|
oneditsave: function () {
|
|
@@ -308,6 +334,7 @@
|
|
|
308
334
|
|
|
309
335
|
</script>
|
|
310
336
|
<script src="https://kit.fontawesome.com/11f26b4500.js" crossorigin="anonymous"></script>
|
|
337
|
+
<!-- <script src="https://cdn.jsdelivr.net/npm/@jaames/iro@5"></script> -->
|
|
311
338
|
|
|
312
339
|
<script type="text/html" data-template-name="knxUltimateHueLight">
|
|
313
340
|
|
|
@@ -337,7 +364,6 @@
|
|
|
337
364
|
<input type="text" id="node-input-serverHue" />
|
|
338
365
|
</div>
|
|
339
366
|
|
|
340
|
-
|
|
341
367
|
<br/>
|
|
342
368
|
<p>
|
|
343
369
|
<b>Philips HUE</b>
|
|
@@ -353,7 +379,7 @@
|
|
|
353
379
|
<br/>
|
|
354
380
|
|
|
355
381
|
|
|
356
|
-
<div id="tabs">
|
|
382
|
+
<div id="tabs" style="width:680px" hidden>
|
|
357
383
|
<ul>
|
|
358
384
|
<li><a href="#tabs-1">Switching</a></li>
|
|
359
385
|
<li><a href="#tabs-2">Dim/Brightness</a></li>
|
|
@@ -559,6 +585,7 @@
|
|
|
559
585
|
</label>
|
|
560
586
|
<input type="text" id="node-input-colorAtSwitchOnDayTime"
|
|
561
587
|
placeholder='Leave blank or, for example, {"red":255, "green":255, "blue":255}' style="width:260px">
|
|
588
|
+
<button id="getHueColorButton" type="button" class="red-ui-button">Get current</button>
|
|
562
589
|
</div>
|
|
563
590
|
<div class="form-row">
|
|
564
591
|
<label for="node-input-enableDayNightLighting" style="width:260px;">
|
|
@@ -576,6 +603,7 @@
|
|
|
576
603
|
</label>
|
|
577
604
|
<input type="text" id="node-input-colorAtSwitchOnNightTime"
|
|
578
605
|
placeholder='Example {"red":100, "green":0, "blue":50}' style="width:260px">
|
|
606
|
+
<button id="getColorAtSwitchOnNightTime" type="button" class="red-ui-button">Get current</button>
|
|
579
607
|
</div>
|
|
580
608
|
<div class="form-row">
|
|
581
609
|
<label for="node-input-nameDaylightSensor" style="width:110px;"><i class="fa fa-clock-o"></i>
|
|
@@ -119,18 +119,6 @@ module.exports = function (RED) {
|
|
|
119
119
|
const dimDirection = msg.payload.decr_incr === 1 ? "up" : "down";
|
|
120
120
|
// First, switch on the light if off
|
|
121
121
|
if (node.currentHUEDevice.hasOwnProperty('on') !== undefined && node.currentHUEDevice.on.on === false && dimDirection === "up") {
|
|
122
|
-
// if (config.specifySwitchOnBrightness === undefined || config.specifySwitchOnBrightness === "yes") {
|
|
123
|
-
// // Starts from minimum of 5
|
|
124
|
-
// node.serverHue.hueManager.writeHueQueueAdd(
|
|
125
|
-
// config.hueDevice,
|
|
126
|
-
// { on: { on: true }, dimming: { brightness: 5 } },
|
|
127
|
-
// node.isGrouped_light === false ? "setLight" : "setGroupedLight"
|
|
128
|
-
// );
|
|
129
|
-
// } else {
|
|
130
|
-
// Read the last HUE brightness status and starts from there
|
|
131
|
-
//const lastDimVal = node.currentHUEDevice !== undefined ? node.currentHUEDevice.dimming.brightness : 5;
|
|
132
|
-
//node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, { on: { on: true }, dimming: { brightness: lastDimVal } }, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
133
|
-
// }
|
|
134
122
|
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, { on: { on: true } }, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
135
123
|
}
|
|
136
124
|
node.startDimStopper(dimDirection);
|
package/nodes/utils/hueEngine.js
CHANGED
|
@@ -171,7 +171,7 @@ class classHUE extends EventEmitter {
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
// The Hue bridge allows about 10 telegram per second, so i need to make a queue manager
|
|
174
|
-
this.timerwriteQueueAdd = setTimeout(this.handleQueue,
|
|
174
|
+
this.timerwriteQueueAdd = setTimeout(this.handleQueue, 200);
|
|
175
175
|
};
|
|
176
176
|
|
|
177
177
|
writeHueQueueAdd = async (_lightID, _state, _operation, _callback) => {
|
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.58",
|
|
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",
|