node-red-contrib-knx-ultimate 2.1.46 → 2.1.47

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
 
9
+ <p>
10
+ <b>Version 2.1.47</b> - September 2023<br/>
11
+ - HUE BRIDGE: fixed multiple HUE bridge handling.<br/>
12
+ <br/>
9
13
  <p>
10
14
  <b>Version 2.1.46</b> - September 2023<br/>
11
15
  - HUE BRIDGE: In case of https problems (certificate expired, etc...), the node will try to connect to the HUE BRIDGE in insecure http mode.<br/>
@@ -1,17 +1,21 @@
1
+ /* eslint-disable no-inner-declarations */
1
2
  /* eslint-disable max-len */
2
- const dptlib = require('../KNXEngine/src/dptlib');
3
- const HueClass = require('./utils/hueEngine').classHUE;
4
- const loggerEngine = require('./utils/sysLogger');
3
+ const dptlib = require("../KNXEngine/src/dptlib");
4
+ const HueClass = require("./utils/hueEngine").classHUE;
5
+ const loggerEngine = require("./utils/sysLogger");
5
6
  // Helpers
6
7
  const sortBy = (field) => (a, b) => {
7
- if (a[field] > b[field]) { return 1; } return -1;
8
+ if (a[field] > b[field]) {
9
+ return 1;
10
+ }
11
+ return -1;
8
12
  };
9
13
 
10
- const onlyDptKeys = (kv) => kv[0].startsWith('DPT');
14
+ const onlyDptKeys = (kv) => kv[0].startsWith("DPT");
11
15
 
12
16
  const extractBaseNo = (kv) => ({
13
17
  subtypes: kv[1].subtypes,
14
- base: parseInt(kv[1].id.replace('DPT', '')),
18
+ base: parseInt(kv[1].id.replace("DPT", "")),
15
19
  });
16
20
 
17
21
  const convertSubtype = (baseType) => (kv) => {
@@ -25,20 +29,14 @@ const convertSubtype = (baseType) => (kv) => {
25
29
  };
26
30
 
27
31
  const toConcattedSubtypes = (acc, baseType) => {
28
- const subtypes = Object.entries(baseType.subtypes)
29
- .sort(sortBy(0))
30
- .map(convertSubtype(baseType));
32
+ const subtypes = Object.entries(baseType.subtypes).sort(sortBy(0)).map(convertSubtype(baseType));
31
33
 
32
34
  return acc.concat(subtypes);
33
35
  };
34
36
 
35
37
  module.exports = (RED) => {
36
- RED.httpAdmin.get('/knxUltimateDpts', RED.auth.needsPermission('hue-config.read'), (req, res) => {
37
- const dpts = Object.entries(dptlib)
38
- .filter(onlyDptKeys)
39
- .map(extractBaseNo)
40
- .sort(sortBy('base'))
41
- .reduce(toConcattedSubtypes, []);
38
+ RED.httpAdmin.get("/knxUltimateDpts", RED.auth.needsPermission("hue-config.read"), (req, res) => {
39
+ const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy("base")).reduce(toConcattedSubtypes, []);
42
40
 
43
41
  res.json(dpts);
44
42
  });
@@ -48,12 +46,14 @@ module.exports = (RED) => {
48
46
  const node = this;
49
47
  node.host = config.host;
50
48
  node.nodeClients = []; // Stores the registered clients
51
- node.loglevel = config.loglevel !== undefined ? config.loglevel : 'error'; // 18/02/2020 Loglevel default error
49
+ node.loglevel = config.loglevel !== undefined ? config.loglevel : "error"; // 18/02/2020 Loglevel default error
52
50
  node.sysLogger = null;
53
51
  try {
54
52
  node.sysLogger = loggerEngine.get({ loglevel: node.loglevel }); // New logger to adhere to the loglevel selected in the config-window
55
- } catch (error) { /* empty */ }
56
- node.name = (config.name === undefined || config.name === '') ? node.host : config.name;
53
+ } catch (error) {
54
+ /* empty */
55
+ }
56
+ node.name = config.name === undefined || config.name === "" ? node.host : config.name;
57
57
 
58
58
  // Init HUE Utility
59
59
  node.hueManager = new HueClass(node.host, node.credentials.username, node.credentials.clientkey, config.bridgeid, node.sysLogger);
@@ -64,8 +64,10 @@ module.exports = (RED) => {
64
64
  // Handle events
65
65
  try {
66
66
  node.hueManager.removeAllListeners();
67
- } catch (error) { /* empty */ }
68
- node.hueManager.on('event', (_event) => {
67
+ } catch (error) {
68
+ /* empty */
69
+ }
70
+ node.hueManager.on("event", (_event) => {
69
71
  node.nodeClients.forEach((_oClient) => {
70
72
  const oClient = _oClient;
71
73
  try {
@@ -76,18 +78,20 @@ module.exports = (RED) => {
76
78
  });
77
79
  });
78
80
  // Connected
79
- node.hueManager.on('connected', () => {
80
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info('node.hueManager connected event');
81
+ node.hueManager.on("connected", () => {
82
+ if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("node.hueManager connected event");
81
83
  });
82
84
  // Initialize the http wrapper, to use the provided key.
83
85
  // This http wrapper is used to get the data from HUE brigde
84
86
  try {
85
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
86
- node.hueAllResources = await node.hueManager.hueApiV2.get('/resource');
87
- node.hueAllRooms = await node.hueManager.hueApiV2.get('/resource/room');
88
- node.hueAllDevices = await node.hueManager.hueApiV2.get('/resource/device');
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");
89
91
  } catch (error) {
90
- if (this.sysLogger !== undefined && this.sysLogger !== null) this.sysLogger.error(`KNXUltimatehueEngine: classHUE: getting resources: ${error.message}`);
92
+ if (this.sysLogger !== undefined && this.sysLogger !== null) {
93
+ this.sysLogger.error(`KNXUltimatehueEngine: classHUE: getting resources: ${error.message}`);
94
+ }
91
95
  }
92
96
  };
93
97
 
@@ -95,10 +99,11 @@ module.exports = (RED) => {
95
99
  await node.ConnectToHueBridge();
96
100
  })();
97
101
 
98
- RED.httpAdmin.get('/KNXUltimateGetResourcesHUE', RED.auth.needsPermission('hue-config.read'), (req, res) => {
102
+ RED.httpAdmin.get("/KNXUltimateGetResourcesHUE", RED.auth.needsPermission("hue-config.read"), (req, res) => {
99
103
  try {
100
104
  // °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
101
- const jRet = node.getResources(req.query.rtype);
105
+ const serverNode = RED.nodes.getNode(req.query.nodeID); // Retrieve node.id of the config node.
106
+ const jRet = serverNode.getResources(req.query.rtype);
102
107
  res.json(jRet);
103
108
  // °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
104
109
  } catch (error) {
@@ -117,14 +122,14 @@ module.exports = (RED) => {
117
122
 
118
123
  // Returns capitalized string
119
124
  function capStr(s) {
120
- if (typeof s !== 'string') return '';
125
+ if (typeof s !== "string") return "";
121
126
  return s.charAt(0).toUpperCase() + s.slice(1);
122
127
  }
123
128
 
124
129
  const retArray = [];
125
130
  let allResources;
126
- if (_rtype === 'light' || _rtype === 'grouped_light') {
127
- allResources = node.hueAllResources.filter((a) => a.type === 'light' || a.type === 'grouped_light');
131
+ if (_rtype === "light" || _rtype === "grouped_light") {
132
+ allResources = node.hueAllResources.filter((a) => a.type === "light" || a.type === "grouped_light");
128
133
  } else {
129
134
  allResources = node.hueAllResources.filter((a) => a.type === _rtype);
130
135
  }
@@ -132,69 +137,104 @@ module.exports = (RED) => {
132
137
  const resource = allResources[index];
133
138
  // Get the owner
134
139
  try {
135
- let resourceName = '';
136
- let sRoom = '';
137
- if (_rtype === 'light' || _rtype === 'grouped_light') {
140
+ let resourceName = "";
141
+ let sRoom = "";
142
+ if (_rtype === "light" || _rtype === "grouped_light") {
138
143
  // It's a service, having a owner
139
144
  const owners = node.hueAllResources.filter((a) => a.id === resource.owner.rid);
140
145
  for (let index = 0; index < owners.length; index++) {
141
146
  const owner = owners[index];
142
- if (owner.type === 'bridge_home') {
143
- resourceName += 'ALL GROUPS and ';
147
+ if (owner.type === "bridge_home") {
148
+ resourceName += "ALL GROUPS and ";
144
149
  } else {
145
150
  resourceName += `${owner.metadata.name} and `;
146
151
  const room = node.hueAllRooms.find((child) => child.children.find((a) => a.rid === owner.id));
147
- sRoom += room !== undefined ? `${room.metadata.name} + ` : ' + ';
152
+ sRoom += room !== undefined ? `${room.metadata.name} + ` : " + ";
148
153
  }
149
154
  }
150
- sRoom = sRoom.slice(0, -(' + '.length));
151
- resourceName = resourceName.slice(0, -(' and '.length));
152
- resourceName += sRoom !== '' ? ` - Room: ${sRoom}` : '';
153
- retArray.push({ name: `${capStr(resource.type)}: ${resourceName}`, id: resource.id, deviceObject: resource });
155
+ sRoom = sRoom.slice(0, -" + ".length);
156
+ resourceName = resourceName.slice(0, -" and ".length);
157
+ resourceName += sRoom !== "" ? ` - Room: ${sRoom}` : "";
158
+ retArray.push({
159
+ name: `${capStr(resource.type)}: ${resourceName}`,
160
+ id: resource.id,
161
+ deviceObject: resource,
162
+ });
154
163
  }
155
- if (_rtype === 'scene') {
156
- resourceName = resource.metadata.name || '**Name Not Found**';
164
+ if (_rtype === "scene") {
165
+ resourceName = resource.metadata.name || "**Name Not Found**";
157
166
  // Get the linked zone
158
167
  const zone = node.hueAllResources.find((res) => res.id === resource.group.rid);
159
168
  resourceName += ` - ${capStr(resource.group.rtype)}: ${zone.metadata.name}`;
160
- retArray.push({ name: `${capStr(_rtype)}: ${resourceName}`, id: resource.id });
169
+ retArray.push({
170
+ name: `${capStr(_rtype)}: ${resourceName}`,
171
+ id: resource.id,
172
+ });
161
173
  }
162
- if (_rtype === 'button') {
163
- const linkedDevName = node.hueAllResources.find((dev) => dev.type === 'device' && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || '';
164
- const controlID = resource.metadata !== undefined ? (resource.metadata.control_id || '') : '';
165
- retArray.push({ name: `${capStr(_rtype)}: ${linkedDevName}, button ${controlID}`, id: resource.id });
174
+ if (_rtype === "button") {
175
+ const linkedDevName =
176
+ node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
177
+ const controlID = resource.metadata !== undefined ? resource.metadata.control_id || "" : "";
178
+ retArray.push({
179
+ name: `${capStr(_rtype)}: ${linkedDevName}, button ${controlID}`,
180
+ id: resource.id,
181
+ });
166
182
  }
167
- if (_rtype === 'motion') {
168
- const linkedDevName = node.hueAllResources.find((dev) => dev.type === 'device' && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || '';
169
- retArray.push({ name: `${capStr(_rtype)}: ${linkedDevName}`, id: resource.id });
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 || "";
186
+ retArray.push({
187
+ name: `${capStr(_rtype)}: ${linkedDevName}`,
188
+ id: resource.id,
189
+ });
170
190
  }
171
- if (_rtype === 'relative_rotary') {
172
- const linkedDevName = node.hueAllResources.find((dev) => dev.type === 'device' && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || '';
173
- retArray.push({ name: `Rotary: ${linkedDevName}`, id: resource.id });
191
+ 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 || "";
194
+ retArray.push({
195
+ name: `Rotary: ${linkedDevName}`,
196
+ id: resource.id,
197
+ });
174
198
  }
175
- if (_rtype === 'light_level') {
199
+ if (_rtype === "light_level") {
176
200
  const Room = node.hueAllRooms.find((room) => room.children.find((child) => child.rid === resource.owner.rid));
177
- const linkedDevName = node.hueAllResources.find((dev) => dev.type === 'device' && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || '';
178
- retArray.push({ name: `Light Level: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ''}`, id: resource.id });
201
+ const linkedDevName =
202
+ node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
203
+ retArray.push({
204
+ name: `Light Level: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ""}`,
205
+ id: resource.id,
206
+ });
179
207
  }
180
- if (_rtype === 'temperature') {
208
+ if (_rtype === "temperature") {
181
209
  const Room = node.hueAllRooms.find((room) => room.children.find((child) => child.rid === resource.owner.rid));
182
- const linkedDevName = node.hueAllResources.find((dev) => dev.type === 'device' && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || '';
183
- retArray.push({ name: `Temperature: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ''}`, id: resource.id });
210
+ const linkedDevName =
211
+ node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
212
+ retArray.push({
213
+ name: `Temperature: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ""}`,
214
+ id: resource.id,
215
+ });
184
216
  }
185
- if (_rtype === 'device_power') {
217
+ if (_rtype === "device_power") {
186
218
  const Room = node.hueAllRooms.find((room) => room.children.find((child) => child.rid === resource.owner.rid));
187
- const linkedDevName = node.hueAllResources.find((dev) => dev.type === 'device' && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || '';
188
- retArray.push({ name: `Battery: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ''}`, id: resource.id });
219
+ const linkedDevName =
220
+ node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
221
+ retArray.push({
222
+ name: `Battery: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ""}`,
223
+ id: resource.id,
224
+ });
189
225
  }
190
226
  } catch (error) {
191
- retArray.push({ name: `${_rtype}: ERROR ${error.message}`, id: resource.id });
227
+ retArray.push({
228
+ name: `${_rtype}: ERROR ${error.message}`,
229
+ id: resource.id,
230
+ });
192
231
  }
193
232
  }
194
233
  return { devices: retArray };
195
234
  } catch (error) {
196
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: classHUE: getDevices: error ${error.message}`);
197
- return ({ devices: error.message });
235
+ if (node.sysLogger !== undefined && node.sysLogger !== null)
236
+ node.sysLogger.error(`KNXUltimateHue: hueEngine: classHUE: getDevices: error ${error.message}`);
237
+ return { devices: error.message };
198
238
  }
199
239
  };
200
240
 
@@ -202,7 +242,11 @@ module.exports = (RED) => {
202
242
  // Check if node already exists
203
243
  if (node.nodeClients.filter((x) => x.id === _Node.id).length === 0) {
204
244
  // Add _Node to the clients array
205
- _Node.setNodeStatusHue({ fill: 'grey', shape: 'ring', text: 'Hue initialized.' });
245
+ _Node.setNodeStatusHue({
246
+ fill: "grey",
247
+ shape: "ring",
248
+ text: "Hue initialized.",
249
+ });
206
250
  node.nodeClients.push(_Node);
207
251
  }
208
252
  };
@@ -211,12 +255,13 @@ module.exports = (RED) => {
211
255
  // Remove the client node from the clients array
212
256
  try {
213
257
  node.nodeClients = node.nodeClients.filter((x) => x.id !== _Node.id);
214
- } catch (error) { }
258
+ } catch (error) {}
215
259
  };
216
260
 
217
- node.on('close', (done) => {
261
+ node.on("close", (done) => {
218
262
  try {
219
- if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger = null; loggerEngine.destroy();
263
+ if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger = null;
264
+ loggerEngine.destroy();
220
265
  node.nodeClients = [];
221
266
  node.hueManager.removeAllListeners();
222
267
  (async () => {
@@ -224,7 +269,9 @@ module.exports = (RED) => {
224
269
  await node.hueManager.close();
225
270
  node.hueManager = null;
226
271
  delete node.hueManager;
227
- } catch (error) { /* empty */ }
272
+ } catch (error) {
273
+ /* empty */
274
+ }
228
275
  done();
229
276
  })();
230
277
  } catch (error) {
@@ -234,10 +281,10 @@ module.exports = (RED) => {
234
281
  }
235
282
 
236
283
  // RED.nodes.registerType("hue-config", hue-config);
237
- RED.nodes.registerType('hue-config', hueConfig, {
284
+ RED.nodes.registerType("hue-config", hueConfig, {
238
285
  credentials: {
239
- username: { type: 'password' },
240
- clientkey: { type: 'password' },
286
+ username: { type: "password" },
287
+ clientkey: { type: "password" },
241
288
  },
242
289
  });
243
290
  };
@@ -111,21 +111,7 @@
111
111
 
112
112
 
113
113
  // 14/08/2021 Elimino il file delle persistenze di questo nodo
114
- $.getJSON("deletePersistGAFile?nodeID=" + node.id, (data) => {
115
- // var myNotification = RED.notify("Persistence group addresses file for this gateway has been deleted. That's normal.",
116
- // {
117
- // modal: false,
118
- // fixed: false,
119
- // type: 'info',
120
- // buttons: [
121
- // {
122
- // text: "OK",
123
- // click: function (e) {
124
- // myNotification.close();
125
- // }
126
- // }]
127
- // })
128
- });
114
+ $.getJSON("deletePersistGAFile?nodeID=" + node.id, (data) => {});
129
115
 
130
116
  // 06/07/2023 Tabs
131
117
  // *****************************