node-red-contrib-huemagic 4.0.0 → 4.0.4

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.
@@ -10,7 +10,7 @@ module.exports = function(RED)
10
10
  const axios = require('axios');
11
11
  const https = require('https');
12
12
 
13
- // READABLE RESSOURCE MESSAGES
13
+ // READABLE RESOURCE MESSAGES
14
14
  const { HueBridgeMessage,
15
15
  HueLightMessage,
16
16
  HueGroupMessage,
@@ -28,35 +28,41 @@ module.exports = function(RED)
28
28
  // STATES
29
29
  this.nodeActive = true;
30
30
  this.config = config;
31
- this.ressources = {};
32
- this.ressourcesInGroups = {};
31
+ this.resources = {};
32
+ this.resourcesInGroups = {};
33
33
  this.lastStates = {};
34
34
  this.events = new events.EventEmitter();
35
35
 
36
+ // RESOURCE ID PATTERN
37
+ this.validResourceID = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi;
38
+
39
+ // FIRMWARE UPDATE TIMEOUT
40
+ this.firmwareUpdateTimeout = null;
41
+
36
42
  // CREATE NODE
37
43
  RED.nodes.createNode(scope, config);
38
44
 
39
45
  // INITIALIZE
40
46
  this.start = function()
41
47
  {
42
- scope.log("Initializing the bridge…");
43
- API.init({ ip: config.bridge, key: config.key })
48
+ scope.log("Initializing the bridge ("+config.bridge+")…");
49
+ API.init({ config: config })
44
50
  .then(function(bridge) {
45
51
  scope.log("Connected to bridge");
46
- return scope.getAllRessources();
52
+ return scope.getAllResources();
47
53
  })
48
- .then(function(allRessources)
54
+ .then(function(allResources)
49
55
  {
50
- scope.log("Process ressources…");
51
- return API.processRessources(allRessources);
56
+ scope.log("Processing bridge resources…");
57
+ return API.processResources(allResources);
52
58
  })
53
- .then(function(allRessources)
59
+ .then(function(allResources)
54
60
  {
55
- // SAVE CURRENT RESSOURCES
56
- scope.ressources = allRessources;
61
+ // SAVE CURRENT RESOURCES
62
+ scope.resources = allResources;
57
63
 
58
64
  // EMIT INITIAL STATES -> NODES
59
- scope.log("Initial emit of ressource states…");
65
+ scope.log("Initial emit of resource states…");
60
66
  return scope.emitInitialStates();
61
67
  })
62
68
  .then(function(emitted)
@@ -77,22 +83,22 @@ module.exports = function(RED)
77
83
  }
78
84
 
79
85
  // FETCH BRIDGE INFORMATION
80
- this.getBridgeInformation = function(replaceRessources = false)
86
+ this.getBridgeInformation = function(replaceResources = false)
81
87
  {
82
88
  return new Promise(function(resolve, reject)
83
89
  {
84
- API.request({ ressource: "/config", version: 1 })
90
+ API.request({ config: config, resource: "/config", version: 1 })
85
91
  .then(function(bridgeInformation)
86
92
  {
87
- // PREPARE TO MATCH V2 RESSOURCES
93
+ // PREPARE TO MATCH V2 RESOURCES
88
94
  bridgeInformation.id = "bridge";
89
95
  bridgeInformation.id_v1 = "/config";
90
96
  bridgeInformation.updated = dayjs().format();
91
97
 
92
- // ALSO REPLACE CURRENT RESSOURCE?
93
- if(replaceRessources === true)
98
+ // ALSO REPLACE CURRENT RESOURCE?
99
+ if(replaceResources === true)
94
100
  {
95
- scope.ressources[bridgeInformation.id] = bridgeInformation;
101
+ scope.resources[bridgeInformation.id] = bridgeInformation;
96
102
  }
97
103
 
98
104
  // GIVE BACK
@@ -105,30 +111,30 @@ module.exports = function(RED)
105
111
  });
106
112
  }
107
113
 
108
- // GET ALL RESSOURCES + RULES
109
- this.getAllRessources = function()
114
+ // GET ALL RESOURCES + RULES
115
+ this.getAllResources = function()
110
116
  {
111
117
  return new Promise(function(resolve, reject)
112
118
  {
113
- var allRessources = [];
119
+ var allResources = [];
114
120
 
115
121
  // GET BRIDGE INFORMATION
116
122
  scope.getBridgeInformation()
117
123
  .then(function(bridgeInformation)
118
124
  {
119
- // PUSH TO RESSOURCES
120
- allRessources.push(bridgeInformation);
125
+ // PUSH TO RESOURCES
126
+ allResources.push(bridgeInformation);
121
127
 
122
- // CONTINUE WITH ALL RESSOURCES
123
- return API.request({ ressource: "all" });
128
+ // CONTINUE WITH ALL RESOURCES
129
+ return API.request({ config: config, resource: "all" });
124
130
  })
125
- .then(function(v2Ressources)
131
+ .then(function(v2Resources)
126
132
  {
127
- // MERGE RESSOURCES
128
- allRessources = allRessources.concat(v2Ressources);
133
+ // MERGE RESOURCES
134
+ allResources = allResources.concat(v2Resources);
129
135
 
130
136
  // GET RULES (LEGACY API)
131
- return API.request({ ressource: "/rules", version: 1 });
137
+ return API.request({ config: config, resource: "/rules", version: 1 });
132
138
  })
133
139
  .then(function(rules)
134
140
  {
@@ -146,17 +152,17 @@ module.exports = function(RED)
146
152
  rule["type"] = "rule";
147
153
 
148
154
  // PUSH RULES
149
- allRessources.push(rule);
155
+ allResources.push(rule);
150
156
  }
151
157
 
152
- resolve(allRessources);
158
+ resolve(allResources);
153
159
  })
154
160
  .catch(function(error) { reject(error); });
155
161
  });
156
162
  }
157
163
 
158
164
  // EMIT INITIAL STATES -> NODES
159
- this.emitInitialStates = function(ressources = false)
165
+ this.emitInitialStates = function(resources = false)
160
166
  {
161
167
  return new Promise(function(resolve, reject)
162
168
  {
@@ -164,9 +170,9 @@ module.exports = function(RED)
164
170
  setTimeout(function()
165
171
  {
166
172
  // PUSH ALL STATES
167
- for (const [id, ressource] of Object.entries(scope.ressources))
173
+ for (const [id, resource] of Object.entries(scope.resources))
168
174
  {
169
- scope.pushUpdatedState(ressource, ressource.type, true);
175
+ scope.pushUpdatedState(resource, resource.type, true);
170
176
  }
171
177
 
172
178
  resolve(true);
@@ -190,69 +196,69 @@ module.exports = function(RED)
190
196
  this.refreshStatesSSE = function()
191
197
  {
192
198
  scope.log("Subscribing to bridge events…");
193
- API.subscribe(function(updates)
199
+ API.subscribe(config, function(updates)
194
200
  {
195
201
  const currentDateTime = dayjs().format();
196
202
 
197
- for(let ressource of updates)
203
+ for(let resource of updates)
198
204
  {
199
- let id = ressource.id;
200
- let type = ressource.type;
205
+ let id = resource.id;
206
+ let type = resource.type;
201
207
 
202
208
  let previousState = false;
203
209
 
204
210
  // HAS OWNER?
205
- if(ressource["owner"])
211
+ if(resource["owner"])
206
212
  {
207
- let targetId = ressource["owner"]["rid"];
213
+ let targetId = resource["owner"]["rid"];
208
214
 
209
- if(scope.ressources[targetId])
215
+ if(scope.resources[targetId])
210
216
  {
211
217
  // GET PREVIOUS STATE
212
- previousState = scope.ressources[targetId]["services"][type][id];
218
+ previousState = scope.resources[targetId]["services"][type][id];
213
219
 
214
220
  // IS BUTTON? -> REMOVE PREVIOUS STATES
215
221
  if(type === "button")
216
222
  {
217
- for (const [oneButtonID, oneButton] of Object.entries(scope.ressources[targetId]["services"]["button"]))
223
+ for (const [oneButtonID, oneButton] of Object.entries(scope.resources[targetId]["services"]["button"]))
218
224
  {
219
- delete scope.ressources[targetId]["services"]["button"][oneButtonID]["button"];
225
+ delete scope.resources[targetId]["services"]["button"][oneButtonID]["button"];
220
226
  }
221
227
  }
222
228
  }
223
229
  }
224
- else if(scope.ressources[id])
230
+ else if(scope.resources[id])
225
231
  {
226
232
  // GET PREVIOUS STATE
227
- previousState = scope.ressources[id];
233
+ previousState = scope.resources[id];
228
234
  }
229
235
 
230
236
  // NO PREVIOUS STATE?
231
237
  if(!previousState) { return false; }
232
238
 
233
239
  // CHECK DIFFERENCES
234
- const mergedState = merge.deep(previousState, ressource);
235
- const updatedRessources = diff(previousState, mergedState);
240
+ const mergedState = merge.deep(previousState, resource);
241
+ const updatedResources = diff(previousState, mergedState);
236
242
 
237
- if(Object.values(updatedRessources).length > 0)
243
+ if(Object.values(updatedResources).length > 0)
238
244
  {
239
- if(ressource["owner"])
245
+ if(resource["owner"])
240
246
  {
241
- let targetId = ressource["owner"]["rid"];
247
+ let targetId = resource["owner"]["rid"];
242
248
 
243
- scope.ressources[targetId]["services"][type][id] = mergedState;
244
- scope.ressources[targetId]["updated"] = currentDateTime;
249
+ scope.resources[targetId]["services"][type][id] = mergedState;
250
+ scope.resources[targetId]["updated"] = currentDateTime;
245
251
 
246
252
  // PUSH STATE
247
- scope.pushUpdatedState(scope.ressources[targetId], ressource.type);
253
+ scope.pushUpdatedState(scope.resources[targetId], resource.type);
248
254
  }
249
255
  else
250
256
  {
251
- scope.ressources[id] = mergedState;
252
- scope.ressources[id]["updated"] = currentDateTime;
257
+ scope.resources[id] = mergedState;
258
+ scope.resources[id]["updated"] = currentDateTime;
253
259
 
254
260
  // PUSH STATE
255
- scope.pushUpdatedState(scope.ressources[id], ressource.type);
261
+ scope.pushUpdatedState(scope.resources[id], resource.type);
256
262
  }
257
263
  }
258
264
  }
@@ -260,42 +266,42 @@ module.exports = function(RED)
260
266
  }
261
267
 
262
268
  // PUSH UPDATED STATE
263
- this.pushUpdatedState = function(ressource, updatedType, suppressMessage = false)
269
+ this.pushUpdatedState = function(resource, updatedType, suppressMessage = false)
264
270
  {
265
- const msg = { id: ressource.id, type: ressource.type, updatedType: updatedType, services: ressource["services"] ? Object.keys(ressource["services"]) : [], suppressMessage: suppressMessage };
266
- this.events.emit(ressource.id, msg);
267
- this.events.emit("globalRessourceUpdates", msg);
271
+ const msg = { id: resource.id, type: resource.type, updatedType: updatedType, services: resource["services"] ? Object.keys(resource["services"]) : [], suppressMessage: suppressMessage };
272
+ this.events.emit(config.id + "_" + resource.id, msg);
273
+ this.events.emit(config.id + "_" + "globalResourceUpdates", msg);
268
274
 
269
- // RESSOURCE CONTAINS SERVICES? -> SERVICE IN GROUP? -> EMIT CHANGES TO GROUPS ALSO
270
- if(this.ressources["_groupsOf"][ressource.id])
275
+ // RESOURCE CONTAINS SERVICES? -> SERVICE IN GROUP? -> EMIT CHANGES TO GROUPS ALSO
276
+ if(this.resources["_groupsOf"][resource.id])
271
277
  {
272
- for (var g = this.ressources["_groupsOf"][ressource.id].length - 1; g >= 0; g--)
278
+ for (var g = this.resources["_groupsOf"][resource.id].length - 1; g >= 0; g--)
273
279
  {
274
- const groupID = this.ressources["_groupsOf"][ressource.id][g];
280
+ const groupID = this.resources["_groupsOf"][resource.id][g];
275
281
  const groupMessage = { id: groupID, type: "group", updatedType: updatedType, services: [], suppressMessage: suppressMessage };
276
282
 
277
- this.events.emit(groupID, groupMessage);
278
- this.events.emit("globalRessourceUpdates", groupMessage);
283
+ this.events.emit(config.id + "_" + groupID, groupMessage);
284
+ this.events.emit(config.id + "_" + "globalResourceUpdates", groupMessage);
279
285
  }
280
286
  }
281
287
  }
282
288
 
283
- // GET RESSOURCE (FROM NODES)
289
+ // GET RESOURCE (FROM NODES)
284
290
  this.get = function(type, id = false, options = {})
285
291
  {
286
- // GET SPECIFIC RESSOURCE
292
+ // GET SPECIFIC RESOURCE
287
293
  if(id)
288
294
  {
289
- // RESSOURCE EXISTS? -> PROCEED
290
- if(scope.ressources[id])
295
+ // RESOURCE EXISTS? -> PROCEED
296
+ if(scope.resources[id])
291
297
  {
292
298
  // RESOLVE LINKS
293
- const targetRessource = scope.ressources[id];
294
- const lastState = scope.lastStates[type+targetRessource.id] ? Object.assign({}, scope.lastStates[type+targetRessource.id]) : false;
299
+ const targetResource = scope.resources[id];
300
+ const lastState = scope.lastStates[type+targetResource.id] ? Object.assign({}, scope.lastStates[type+targetResource.id]) : false;
295
301
 
296
302
  if(type == "bridge")
297
303
  {
298
- const message = new HueBridgeMessage(targetRessource, options);
304
+ const message = new HueBridgeMessage(targetResource, options);
299
305
 
300
306
  // GET CURRENT STATE MESSAGE
301
307
  let currentState = message.msg;
@@ -303,11 +309,11 @@ module.exports = function(RED)
303
309
  }
304
310
  else if(type == "light")
305
311
  {
306
- const message = new HueLightMessage(targetRessource, options);
312
+ const message = new HueLightMessage(targetResource, options);
307
313
 
308
314
  // GET & SAVE LAST STATE AND DIFFERENCES
309
315
  let currentState = message.msg;
310
- scope.lastStates[type+targetRessource.id] = Object.assign({}, currentState);
316
+ scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
311
317
  currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
312
318
  currentState.lastState = lastState;
313
319
 
@@ -316,11 +322,11 @@ module.exports = function(RED)
316
322
  else if(type == "group")
317
323
  {
318
324
  // GET MESSAGE
319
- const message = new HueGroupMessage(targetRessource, { ressources: scope.ressources, ...options});
325
+ const message = new HueGroupMessage(targetResource, { resources: scope.resources, ...options});
320
326
 
321
327
  // GET & SAVE LAST STATE AND DIFFERENCES
322
328
  let currentState = message.msg;
323
- scope.lastStates[type+targetRessource.id] = Object.assign({}, currentState);
329
+ scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
324
330
  currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
325
331
  currentState.lastState = lastState;
326
332
 
@@ -328,11 +334,11 @@ module.exports = function(RED)
328
334
  }
329
335
  else if(type == "button")
330
336
  {
331
- const message = new HueButtonsMessage(targetRessource, options);
337
+ const message = new HueButtonsMessage(targetResource, options);
332
338
 
333
339
  // GET & SAVE LAST STATE AND DIFFERENCES
334
340
  let currentState = message.msg;
335
- scope.lastStates[type+targetRessource.id] = Object.assign({}, currentState);
341
+ scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
336
342
  currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
337
343
  currentState.lastState = lastState;
338
344
 
@@ -340,11 +346,11 @@ module.exports = function(RED)
340
346
  }
341
347
  else if(type == "motion")
342
348
  {
343
- const message = new HueMotionMessage(targetRessource, options);
349
+ const message = new HueMotionMessage(targetResource, options);
344
350
 
345
351
  // GET & SAVE LAST STATE AND DIFFERENCES
346
352
  let currentState = message.msg;
347
- scope.lastStates[type+targetRessource.id] = Object.assign({}, currentState);
353
+ scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
348
354
  currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
349
355
  currentState.lastState = lastState;
350
356
 
@@ -352,11 +358,11 @@ module.exports = function(RED)
352
358
  }
353
359
  else if(type == "temperature")
354
360
  {
355
- const message = new HueTemperatureMessage(targetRessource, options);
361
+ const message = new HueTemperatureMessage(targetResource, options);
356
362
 
357
363
  // GET & SAVE LAST STATE AND DIFFERENCES
358
364
  let currentState = message.msg;
359
- scope.lastStates[type+targetRessource.id] = Object.assign({}, currentState);
365
+ scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
360
366
  currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
361
367
  currentState.lastState = lastState;
362
368
 
@@ -364,11 +370,11 @@ module.exports = function(RED)
364
370
  }
365
371
  else if(type == "light_level")
366
372
  {
367
- const message = new HueBrightnessMessage(targetRessource, options);
373
+ const message = new HueBrightnessMessage(targetResource, options);
368
374
 
369
375
  // GET & SAVE LAST STATE AND DIFFERENCES
370
376
  let currentState = message.msg;
371
- scope.lastStates[type+targetRessource.id] = Object.assign({}, currentState);
377
+ scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
372
378
  currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
373
379
  currentState.lastState = lastState;
374
380
 
@@ -376,11 +382,11 @@ module.exports = function(RED)
376
382
  }
377
383
  else if(type == "rule")
378
384
  {
379
- const message = new HueRulesMessage(targetRessource, options);
385
+ const message = new HueRulesMessage(targetResource, options);
380
386
 
381
387
  // GET & SAVE LAST STATE AND DIFFERENCES
382
388
  let currentState = message.msg;
383
- scope.lastStates[type+targetRessource.id] = Object.assign({}, currentState);
389
+ scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
384
390
  currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
385
391
  currentState.lastState = lastState;
386
392
 
@@ -398,46 +404,46 @@ module.exports = function(RED)
398
404
  }
399
405
  else
400
406
  {
401
- // FILTER RESSOURCES BY TYPE
402
- let allFilteredRessources = {};
407
+ // FILTER RESOURCES BY TYPE
408
+ let allFilteredResources = {};
403
409
 
404
- for (const [rootID, ressource] of Object.entries(scope.ressources))
410
+ for (const [rootID, resource] of Object.entries(scope.resources))
405
411
  {
406
- const isGroup = (ressource["type"] == "room" || ressource["type"] == "zone" || ressource["type"] == "bridge_home");
412
+ const isGroup = (resource["type"] == "room" || resource["type"] == "zone" || resource["type"] == "bridge_home");
407
413
 
408
414
  // NORMAL DEVICES
409
- if(!isGroup && ressource["services"] && ressource["services"][type])
415
+ if(!isGroup && resource["services"] && resource["services"][type])
410
416
  {
411
- for (const [serviceID, targetDevice] of Object.entries(ressource["services"][type]))
417
+ for (const [serviceID, targetDevice] of Object.entries(resource["services"][type]))
412
418
  {
413
- allFilteredRessources[rootID] = scope.get(type, rootID);
419
+ allFilteredResources[rootID] = scope.get(type, rootID);
414
420
  }
415
421
  }
416
- // GROUPED RESSOURCES
422
+ // GROUPED RESOURCES
417
423
  else if(isGroup && type === "group")
418
424
  {
419
- allFilteredRessources[rootID] = scope.get(type, rootID);
425
+ allFilteredResources[rootID] = scope.get(type, rootID);
420
426
  }
421
427
  }
422
428
 
423
- return Object.values(allFilteredRessources);
429
+ return Object.values(allFilteredResources);
424
430
  }
425
431
  }
426
432
 
427
- // PATCH RESSOURCE (FROM NODES)
433
+ // PATCH RESOURCE (FROM NODES)
428
434
  this.patch = function(type, id, patch, version = 2)
429
435
  {
430
436
  return new Promise(function(resolve, reject)
431
437
  {
432
438
  // GET SERVICE ID
433
- if(version !== 1 && scope.ressources[id] && scope.ressources[id]["services"] && scope.ressources[id]["services"][type])
439
+ if(version !== 1 && scope.resources[id] && scope.resources[id]["services"] && scope.resources[id]["services"][type])
434
440
  {
435
- const targetRessource = Object.values(scope.ressources[id]["services"][type])[0];
436
- id = targetRessource.id;
441
+ const targetResource = Object.values(scope.resources[id]["services"][type])[0];
442
+ id = targetResource.id;
437
443
  }
438
444
 
439
445
  // ACTION!
440
- API.request({ method: "PUT", ressource: (version === 2) ? (type+"/"+id) : id, data: patch, version: version })
446
+ API.request({ config: config, method: "PUT", resource: (version === 2) ? (type+"/"+id) : id, data: patch, version: version })
441
447
  .then(function(response) {
442
448
  resolve(response);
443
449
  })
@@ -452,7 +458,7 @@ module.exports = function(RED)
452
458
  {
453
459
  return new Promise(function(resolve, reject)
454
460
  {
455
- API.request({ ressource: "/rules/" + id, version: 1 })
461
+ API.request({ config: config, resource: "/rules/" + id, version: 1 })
456
462
  .then(function(rule)
457
463
  {
458
464
  // "RENAME" OWNER
@@ -469,8 +475,8 @@ module.exports = function(RED)
469
475
  // UPDATED TIME
470
476
  rule["updated"] = dayjs().format();
471
477
 
472
- // ADD BACK TO RESSOURCES
473
- scope.ressources[rule["id"]] = rule;
478
+ // ADD BACK TO RESOURCES
479
+ scope.resources[rule["id"]] = rule;
474
480
 
475
481
  // PUSH UPDATED STATE
476
482
  scope.pushUpdatedState(rule, "rule");
@@ -505,7 +511,7 @@ module.exports = function(RED)
505
511
  if(!id)
506
512
  {
507
513
  // UNIVERSAL MODE
508
- this.events.on("globalRessourceUpdates", function(info)
514
+ this.events.on(config.id + "_" + "globalResourceUpdates", function(info)
509
515
  {
510
516
  if(type === "bridge")
511
517
  {
@@ -523,8 +529,8 @@ module.exports = function(RED)
523
529
  }
524
530
  else
525
531
  {
526
- // SPECIFIC RESSOURCE MODE
527
- this.events.on(id, function(info)
532
+ // SPECIFIC RESOURCE MODE
533
+ this.events.on(config.id + "_" + id, function(info)
528
534
  {
529
535
  if(type === "bridge" || messageWhitelist[type].includes(info.updatedType))
530
536
  {
@@ -539,10 +545,13 @@ module.exports = function(RED)
539
545
  {
540
546
  if((config.autoupdates && config.autoupdates == true) || typeof config.autoupdates == 'undefined')
541
547
  {
548
+ if(scope.firmwareUpdateTimeout !== null) { clearTimeout(scope.firmwareUpdateTimeout); };
549
+
542
550
  scope.log("Checking for Hue Bridge firmware updates…");
543
551
  API.request({
552
+ config: config,
544
553
  method: "PUT",
545
- ressource: "/config",
554
+ resource: "/config",
546
555
  version: 1,
547
556
  data: {
548
557
  swupdate2: {
@@ -555,7 +564,7 @@ module.exports = function(RED)
555
564
  {
556
565
  if(scope.nodeActive == true)
557
566
  {
558
- setTimeout(function(){ scope.autoUpdateFirmware(); }, 60000 * 5);
567
+ scope.firmwareUpdateTimeout = setTimeout(function(){ scope.autoUpdateFirmware(); }, 60000 * 180);
559
568
  }
560
569
  })
561
570
  .catch(function(error)
@@ -563,7 +572,7 @@ module.exports = function(RED)
563
572
  // NO UPDATES AVAILABLE // TRY AGAIN IN 3H
564
573
  if(scope.nodeActive == true)
565
574
  {
566
- setTimeout(function(){ scope.autoUpdateFirmware(); }, 60000 * 180);
575
+ scope.firmwareUpdateTimeout = setTimeout(function(){ scope.autoUpdateFirmware(); }, 60000 * 180);
567
576
  }
568
577
  });
569
578
  }
@@ -581,10 +590,13 @@ module.exports = function(RED)
581
590
 
582
591
  // UNSUBSCRIBE FROM BRIDGE EVENTS
583
592
  scope.log("Unsubscribing from bridge events…");
584
- API.unsubscribe();
593
+ API.unsubscribe(config);
585
594
 
586
595
  // UNSUBSCRIBE FROM "READY" EVENTS
587
596
  scope.events.removeAllListeners();
597
+
598
+ // REMOVE FIRMWARE UPDATE TIMEOUT
599
+ if(scope.firmwareUpdateTimeout !== null) { clearTimeout(scope.firmwareUpdateTimeout); }
588
600
  });
589
601
  }
590
602
 
@@ -628,7 +640,7 @@ module.exports = function(RED)
628
640
  }
629
641
  else
630
642
  {
631
- API.init({ ip: req.query.ip })
643
+ API.init({ config: { bridge: req.query.ip, key: "huemagic" } })
632
644
  .then(function(bridge) {
633
645
  res.end(bridge.name);
634
646
  })
@@ -656,7 +668,7 @@ module.exports = function(RED)
656
668
  "Content-Type": "application/json; charset=utf-8"
657
669
  },
658
670
  "data": {
659
- "devicetype": "huemagic_" + Math.floor((Math.random() * 100) + 1)
671
+ "devicetype": "HueMagic for Node-RED (" + Math.floor((Math.random() * 100) + 1) + ")"
660
672
  }
661
673
  })
662
674
  .then(function(response)
@@ -678,18 +690,15 @@ module.exports = function(RED)
678
690
  });
679
691
 
680
692
  //
681
- // DISCOVER RESSOURCES
682
- RED.httpAdmin.get('/hue/ressources', function(req, res, next)
693
+ // DISCOVER RESOURCES
694
+ RED.httpAdmin.get('/hue/resources', function(req, res, next)
683
695
  {
684
696
  const targetType = req.query.type;
685
697
 
686
698
  // GET ALL RULES
687
699
  if(targetType == "rule")
688
700
  {
689
- API.init({ ip: req.query.bridge, key: req.query.key })
690
- .then(function(bridge) {
691
- return API.request({ ressource: "/rules", version: 1 });
692
- })
701
+ API.request({ config: { bridge: req.query.bridge, key: req.query.key }, resource: "/rules", version: 1 })
693
702
  .then(function(rules)
694
703
  {
695
704
  let targetRules = {};
@@ -714,58 +723,55 @@ module.exports = function(RED)
714
723
  res.status(500).send(JSON.stringify(error));
715
724
  });
716
725
  }
717
- // GET ALL OTHER RESSOURCES
726
+ // GET ALL OTHER RESOURCES
718
727
  else
719
728
  {
720
- API.init({ ip: req.query.bridge, key: req.query.key })
721
- .then(function(bridge) {
722
- return API.request({ ressource: "all" });
723
- })
724
- .then(function(allRessources)
729
+ API.request({ config: { bridge: req.query.bridge, key: req.query.key }, resource: "all" })
730
+ .then(function(allResources)
725
731
  {
726
- return API.processRessources(allRessources);
732
+ return API.processResources(allResources);
727
733
  })
728
- .then(function(processedRessources)
734
+ .then(function(processedResources)
729
735
  {
730
736
  let targetDevices = {};
731
737
 
732
- for (const [id, ressource] of Object.entries(processedRessources))
738
+ for (const [id, resource] of Object.entries(processedResources))
733
739
  {
734
- const isGroup = (ressource["type"] == "room" || ressource["type"] == "zone" || ressource["type"] == "bridge_home");
740
+ const isGroup = (resource["type"] == "room" || resource["type"] == "zone" || resource["type"] == "bridge_home");
735
741
 
736
742
  // NORMAL DEVICES
737
- if(!isGroup && ressource["services"] && ressource["services"][targetType])
743
+ if(!isGroup && resource["services"] && resource["services"][targetType])
738
744
  {
739
- for (const [deviceID, targetDevice] of Object.entries(ressource["services"][targetType]))
745
+ for (const [deviceID, targetDevice] of Object.entries(resource["services"][targetType]))
740
746
  {
741
747
  var oneDevice = {};
742
748
  oneDevice.id = id;
743
- oneDevice.name = ressource.metadata ? ressource.metadata.name : false;
744
- oneDevice.model = ressource.product_data ? ressource.product_data.product_name : false;
749
+ oneDevice.name = resource.metadata ? resource.metadata.name : false;
750
+ oneDevice.model = resource.product_data ? resource.product_data.product_name : false;
745
751
 
746
752
  targetDevices[id] = oneDevice;
747
753
  }
748
754
  }
749
- // GROUPED (LIGHT) RESSOURCES
755
+ // GROUPED (LIGHT) RESOURCES
750
756
  else if(isGroup && targetType === "group")
751
757
  {
752
- if(ressource["services"] && ressource["services"]["grouped_light"])
758
+ if(resource["services"] && resource["services"]["grouped_light"])
753
759
  {
754
760
  var oneDevice = {};
755
761
  oneDevice.id = id;
756
- oneDevice.name = ressource.metadata ? ressource.metadata.name : false;
757
- oneDevice.model = ressource["type"];
762
+ oneDevice.name = resource.metadata ? resource.metadata.name : false;
763
+ oneDevice.model = resource["type"];
758
764
 
759
765
  targetDevices[id] = oneDevice;
760
766
  }
761
767
  }
762
768
  // SCENES
763
- else if(targetType === "scene" && ressource["type"] == "scene")
769
+ else if(targetType === "scene" && resource["type"] == "scene")
764
770
  {
765
771
  var oneDevice = {};
766
772
  oneDevice.id = id;
767
- oneDevice.name = ressource.metadata ? ressource.metadata.name : false;
768
- oneDevice.group = processedRessources[ressource["group"]["rid"]].metadata.name;
773
+ oneDevice.name = resource.metadata ? resource.metadata.name : false;
774
+ oneDevice.group = processedResources[resource["group"]["rid"]].metadata.name;
769
775
 
770
776
  targetDevices[id] = oneDevice;
771
777
  }