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 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/>
@@ -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
- try {
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);
@@ -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, 100);
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.57",
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",