node-red-contrib-huemagic 4.0.4 → 4.2.0
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/README.md +27 -4
- package/huemagic/hue-bridge-config.html +7 -0
- package/huemagic/hue-bridge-config.js +168 -88
- package/huemagic/hue-brightness.html +15 -1
- package/huemagic/hue-brightness.js +30 -3
- package/huemagic/hue-buttons.html +14 -0
- package/huemagic/hue-buttons.js +5 -0
- package/huemagic/hue-group.html +15 -1
- package/huemagic/hue-group.js +153 -55
- package/huemagic/hue-light.html +15 -1
- package/huemagic/hue-light.js +196 -71
- package/huemagic/hue-motion.html +15 -1
- package/huemagic/hue-motion.js +30 -3
- package/huemagic/hue-rules.html +15 -1
- package/huemagic/hue-rules.js +30 -6
- package/huemagic/hue-scene.html +15 -1
- package/huemagic/hue-scene.js +62 -16
- package/huemagic/hue-temperature.html +15 -1
- package/huemagic/hue-temperature.js +30 -3
- package/huemagic/locales/de/hue-bridge-config.html +8 -0
- package/huemagic/locales/de/hue-group.html +1 -0
- package/huemagic/locales/en-US/hue-bridge-config.html +8 -0
- package/huemagic/locales/en-US/hue-bridge.html +1 -1
- package/huemagic/locales/en-US/hue-group.html +1 -0
- package/huemagic/locales/en-US/hue-light.html +1 -1
- package/huemagic/locales/en-US/hue-magic.html +1 -1
- package/huemagic/utils/api.js +3 -10
- package/huemagic/utils/messages.js +61 -51
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -142,7 +142,7 @@ If the "fetch" command has been used on the node, the bridge outputs the corresp
|
|
|
142
142
|
|
|
143
143
|
#### Global status messages under `msg.updated` (optional)
|
|
144
144
|
|
|
145
|
-
Unless deactivated, the node outputs an updated status message for each resource on the bridge. The status message under
|
|
145
|
+
Unless deactivated, the node outputs an updated status message for each resource on the bridge. The status message under `msg.updated` follows the pattern of the respective resource and varies depending on the type of device that was last updated.
|
|
146
146
|
|
|
147
147
|
#### Last command under `msg.command` (optional)
|
|
148
148
|
|
|
@@ -172,7 +172,7 @@ To play or stop an animation, pass an object with the following content to the n
|
|
|
172
172
|
|--|--|
|
|
173
173
|
| payload (boolean) | `true`, starts the animation, `false`, stops the animation |
|
|
174
174
|
|
|
175
|
-
###
|
|
175
|
+
### Custom animations
|
|
176
176
|
|
|
177
177
|
If you pass your own animation to the node, the preselected, pre-defined animation (if set) will be temporarily replaced by yours. Own HueMagic animations are a sequence of commands that have been combined in an array. Each array element forms a step - whereby a step can also consist of several frames (transition effects).
|
|
178
178
|
|
|
@@ -273,7 +273,7 @@ In addition to simply switching it on and off, there are also many other options
|
|
|
273
273
|
| gradient (object {hex […]}) | An object with a supported color object (e.g. `hex`,` rgb`, ...) and several colors to set a gradient to supported lights |
|
|
274
274
|
| mixColor (object) | A color to be mixed with the current light color. Can accept `color`, `hex`, `rgb` or `xyColor` objects and optionally `amount` (int) to indicate the mixing ratio in percent |
|
|
275
275
|
| image (string) | Path of an image (local or on the web) to set the current color of the light to the average color of the image |
|
|
276
|
-
| saturation (int) |
|
|
276
|
+
| saturation (int) | Percentage of the saturation of the current color (beta) |
|
|
277
277
|
| colorTemp (int / string) | Value between 153 and 500 to set the color temperature of the light or the values `cold`, `normal`, `warm`, `hot` and `auto` - where `auto` is the color temperature based on the current time |
|
|
278
278
|
| incrementColorTemp (int / boolean) | Value by how much the color temperature should be warmer or `true` to make the color temperature warmer in steps of 50 |
|
|
279
279
|
| decrementColorTemp (int / boolean) | Value by how much the color temperature should be colder or `true` to make the color temperature colder in steps of 50 |
|
|
@@ -395,6 +395,7 @@ In contrast to the "Hue Light" node, you have much less status information avail
|
|
|
395
395
|
| id (string) | Indicates the new ID of the group |
|
|
396
396
|
| idV1 (string / boolean) | Indicates the old ID of the group |
|
|
397
397
|
| name (string) | The currently set name of the group |
|
|
398
|
+
| resources (object) | Contains all devices/resources behind the group
|
|
398
399
|
| type (string) | The type of the group (always `group`) |
|
|
399
400
|
|
|
400
401
|
#### Status changes under `msg.updated`
|
|
@@ -795,7 +796,29 @@ If the status of the node has changed via a certain command, the entire command
|
|
|
795
796
|
|
|
796
797
|
# Changelog
|
|
797
798
|
|
|
798
|
-
### v4.0
|
|
799
|
+
### v4.2.0 (latest)
|
|
800
|
+
|
|
801
|
+
* Commands are now re-executed up to three times if they fail due to a bridge timeout
|
|
802
|
+
* The "image" option on the "Hue Light" node will now set the corresponding gradient colors on supported resources
|
|
803
|
+
* Better handling of broken connections to the bridge ([#309](https://github.com/Foddy/node-red-contrib-huemagic/pull/309)) (thx)
|
|
804
|
+
* Fixed an error with the "Hue Scenes" node on newer bridge firmwares ([#335](https://github.com/Foddy/node-red-contrib-huemagic/issues/335)) ([#339](https://github.com/Foddy/node-red-contrib-huemagic/pull/339)) (thx)
|
|
805
|
+
* Fixed an uncaught exception on newer bridge firmwares ([#302](https://github.com/Foddy/node-red-contrib-huemagic/issues/302)) ([#309](https://github.com/Foddy/node-red-contrib-huemagic/pull/309)) (thx)
|
|
806
|
+
* Updated dependencies to the latest versions
|
|
807
|
+
* Fixed some typos here and there
|
|
808
|
+
|
|
809
|
+
### v4.1.0
|
|
810
|
+
|
|
811
|
+
* New queue worker throttles the number of parallel requests to the bridge to avoid 503 API limit errors (can be configured in the Bridge configuration)
|
|
812
|
+
* Resources are now alphabetically sorted in the node´s configuration interface ([#282](https://github.com/Foddy/node-red-contrib-huemagic/pull/282)) (thx)
|
|
813
|
+
* "Hue Brightness" node was optimized to output more accurate "dark" and "dayLight" values
|
|
814
|
+
* Several optimizations in the documentation of some nodes
|
|
815
|
+
|
|
816
|
+
### v4.0.5
|
|
817
|
+
|
|
818
|
+
* The "Hue Group" node now contains the "resources" information with all linked resources behind the group/zone
|
|
819
|
+
* Fixed an issue that caused Node-RED to restart if a command was sent before a node was initialized
|
|
820
|
+
|
|
821
|
+
### v4.0.4
|
|
799
822
|
|
|
800
823
|
* Fixed an issue with the bridge config node checking for updates too frequently ([#246](https://github.com/Foddy/node-red-contrib-huemagic/issues/246#issuecomment-1009376442))
|
|
801
824
|
* Fixed an issue with multiple bridges configured
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
</button>
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
|
28
|
+
<div class="form-row">
|
|
29
|
+
<label for="node-config-input-worker"><i class="fa fa-cogs"></i> <span>Worker</span></label>
|
|
30
|
+
<input type="text" id="node-config-input-worker" placeholder="10" style="width: calc(100% - 105px)">
|
|
31
|
+
</div>
|
|
28
32
|
<div class="form-row" style="margin-top: 30px">
|
|
29
33
|
<div style="display: inline-flex; width: calc(100% - 105px)">
|
|
30
34
|
<input type="checkbox" id="node-input-autoupdates" style="flex: 15px;">
|
|
@@ -47,6 +51,9 @@
|
|
|
47
51
|
name: { value:"Hue Bridge", required: true },
|
|
48
52
|
bridge: { value:"", required: true },
|
|
49
53
|
key: { value:"", required: true },
|
|
54
|
+
worker: { value: 10, required: true, validate: function(v) {
|
|
55
|
+
return (!isNaN(v) && v > 0);
|
|
56
|
+
}},
|
|
50
57
|
autoupdates: { value: true },
|
|
51
58
|
disableupdates: { value: false }
|
|
52
59
|
},
|
|
@@ -9,6 +9,7 @@ module.exports = function(RED)
|
|
|
9
9
|
const diff = require("deep-object-diff").diff;
|
|
10
10
|
const axios = require('axios');
|
|
11
11
|
const https = require('https');
|
|
12
|
+
const fastq = require('fastq');
|
|
12
13
|
|
|
13
14
|
// READABLE RESOURCE MESSAGES
|
|
14
15
|
const { HueBridgeMessage,
|
|
@@ -32,6 +33,8 @@ module.exports = function(RED)
|
|
|
32
33
|
this.resourcesInGroups = {};
|
|
33
34
|
this.lastStates = {};
|
|
34
35
|
this.events = new events.EventEmitter();
|
|
36
|
+
this.patchQueue = null;
|
|
37
|
+
this.timerWatchDog = null; // 31/01/2022 Supergiovane: watchdog for the connection with the bridge
|
|
35
38
|
|
|
36
39
|
// RESOURCE ID PATTERN
|
|
37
40
|
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;
|
|
@@ -42,9 +45,35 @@ module.exports = function(RED)
|
|
|
42
45
|
// CREATE NODE
|
|
43
46
|
RED.nodes.createNode(scope, config);
|
|
44
47
|
|
|
48
|
+
this.startWatchdog = function() {
|
|
49
|
+
// 31/01/2022 Supergiovane: Check wether the bridge is connected.
|
|
50
|
+
if (this.timerWatchDog !== null) clearTimeout(this.timerWatchDog);
|
|
51
|
+
this.timerWatchDog = setTimeout(() => {
|
|
52
|
+
try {
|
|
53
|
+
API.request({ config: config, resource: "/config", version: 1 })
|
|
54
|
+
.then(function(bridgeInformation)
|
|
55
|
+
{
|
|
56
|
+
// The bridge is still connected
|
|
57
|
+
scope.startWatchdog();
|
|
58
|
+
})
|
|
59
|
+
.catch(function(error)
|
|
60
|
+
{
|
|
61
|
+
// Error connecting to the bridge
|
|
62
|
+
scope.log("Error requesting info from the bridge. Reconnect in some secs. " + error.message);
|
|
63
|
+
scope.start();
|
|
64
|
+
});
|
|
65
|
+
} catch (error) {
|
|
66
|
+
scope.log("Lost connection with the bridge. Reconnect in some secs. " + error.message);
|
|
67
|
+
scope.start();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}, 10000);
|
|
71
|
+
}
|
|
45
72
|
// INITIALIZE
|
|
46
73
|
this.start = function()
|
|
47
74
|
{
|
|
75
|
+
this.startWatchdog(); // 31/01/2022 Supergiovane: starts the watchdog.
|
|
76
|
+
|
|
48
77
|
scope.log("Initializing the bridge ("+config.bridge+")…");
|
|
49
78
|
API.init({ config: config })
|
|
50
79
|
.then(function(bridge) {
|
|
@@ -301,96 +330,129 @@ module.exports = function(RED)
|
|
|
301
330
|
|
|
302
331
|
if(type == "bridge")
|
|
303
332
|
{
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
333
|
+
try {
|
|
334
|
+
const message = new HueBridgeMessage(targetResource, options);
|
|
335
|
+
|
|
336
|
+
// GET CURRENT STATE MESSAGE
|
|
337
|
+
let currentState = message.msg;
|
|
338
|
+
return currentState;
|
|
339
|
+
} catch (error) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
|
|
309
343
|
}
|
|
310
344
|
else if(type == "light")
|
|
311
345
|
{
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
346
|
+
try {
|
|
347
|
+
const message = new HueLightMessage(targetResource, options);
|
|
348
|
+
|
|
349
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
350
|
+
let currentState = message.msg;
|
|
351
|
+
scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
|
|
352
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
353
|
+
currentState.lastState = lastState;
|
|
354
|
+
|
|
355
|
+
return currentState;
|
|
356
|
+
} catch (error) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
321
359
|
}
|
|
322
360
|
else if(type == "group")
|
|
323
361
|
{
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
362
|
+
try {
|
|
363
|
+
// GET MESSAGE
|
|
364
|
+
const message = new HueGroupMessage(targetResource, { resources: scope.resources, ...options});
|
|
365
|
+
|
|
366
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
367
|
+
let currentState = message.msg;
|
|
368
|
+
scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
|
|
369
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
370
|
+
currentState.lastState = lastState;
|
|
371
|
+
|
|
372
|
+
return currentState;
|
|
373
|
+
} catch (error) {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
334
376
|
}
|
|
335
377
|
else if(type == "button")
|
|
336
378
|
{
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
379
|
+
try {
|
|
380
|
+
const message = new HueButtonsMessage(targetResource, options);
|
|
381
|
+
|
|
382
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
383
|
+
let currentState = message.msg;
|
|
384
|
+
scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
|
|
385
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
386
|
+
currentState.lastState = lastState;
|
|
387
|
+
|
|
388
|
+
return currentState;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
346
392
|
}
|
|
347
393
|
else if(type == "motion")
|
|
348
394
|
{
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
395
|
+
try {
|
|
396
|
+
const message = new HueMotionMessage(targetResource, options);
|
|
397
|
+
|
|
398
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
399
|
+
let currentState = message.msg;
|
|
400
|
+
scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
|
|
401
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
402
|
+
currentState.lastState = lastState;
|
|
403
|
+
|
|
404
|
+
return currentState;
|
|
405
|
+
} catch (error) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
358
408
|
}
|
|
359
409
|
else if(type == "temperature")
|
|
360
410
|
{
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
411
|
+
try {
|
|
412
|
+
const message = new HueTemperatureMessage(targetResource, options);
|
|
413
|
+
|
|
414
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
415
|
+
let currentState = message.msg;
|
|
416
|
+
scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
|
|
417
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
418
|
+
currentState.lastState = lastState;
|
|
419
|
+
|
|
420
|
+
return currentState;
|
|
421
|
+
} catch (error) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
370
424
|
}
|
|
371
425
|
else if(type == "light_level")
|
|
372
426
|
{
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
427
|
+
try {
|
|
428
|
+
const message = new HueBrightnessMessage(targetResource, options);
|
|
429
|
+
|
|
430
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
431
|
+
let currentState = message.msg;
|
|
432
|
+
scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
|
|
433
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
434
|
+
currentState.lastState = lastState;
|
|
435
|
+
|
|
436
|
+
return currentState;
|
|
437
|
+
} catch (error) {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
382
440
|
}
|
|
383
441
|
else if(type == "rule")
|
|
384
442
|
{
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
443
|
+
try {
|
|
444
|
+
const message = new HueRulesMessage(targetResource, options);
|
|
445
|
+
|
|
446
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
447
|
+
let currentState = message.msg;
|
|
448
|
+
scope.lastStates[type+targetResource.id] = Object.assign({}, currentState);
|
|
449
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
450
|
+
currentState.lastState = lastState;
|
|
451
|
+
|
|
452
|
+
return currentState;
|
|
453
|
+
} catch (error) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
394
456
|
}
|
|
395
457
|
else
|
|
396
458
|
{
|
|
@@ -435,24 +497,41 @@ module.exports = function(RED)
|
|
|
435
497
|
{
|
|
436
498
|
return new Promise(function(resolve, reject)
|
|
437
499
|
{
|
|
438
|
-
|
|
439
|
-
|
|
500
|
+
if(!scope.patchQueue) { return false; }
|
|
501
|
+
scope.patchQueue.push({ type: type, id: id, patch: patch, version: version }, function (error, response)
|
|
440
502
|
{
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
})
|
|
450
|
-
.catch(function(error) {
|
|
451
|
-
reject(error);
|
|
503
|
+
if(error)
|
|
504
|
+
{
|
|
505
|
+
reject(error);
|
|
506
|
+
}
|
|
507
|
+
else
|
|
508
|
+
{
|
|
509
|
+
resolve(response);
|
|
510
|
+
}
|
|
452
511
|
});
|
|
453
512
|
});
|
|
454
513
|
}
|
|
455
514
|
|
|
515
|
+
// PATCH RESOURCE (WORKER) / 7 PROCESSES IN PARALLEL
|
|
516
|
+
this.patchQueue = fastq(function({ type, id, patch, version }, callback)
|
|
517
|
+
{
|
|
518
|
+
// GET SERVICE ID
|
|
519
|
+
if(version !== 1 && scope.resources[id] && scope.resources[id]["services"] && scope.resources[id]["services"][type])
|
|
520
|
+
{
|
|
521
|
+
const targetResource = Object.values(scope.resources[id]["services"][type])[0];
|
|
522
|
+
id = targetResource.id;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// ACTION!
|
|
526
|
+
API.request({ config: config, method: "PUT", resource: (version === 2) ? (type+"/"+id) : id, data: patch, version: version })
|
|
527
|
+
.then(function(response) {
|
|
528
|
+
callback(null, response);
|
|
529
|
+
})
|
|
530
|
+
.catch(function(error) {
|
|
531
|
+
callback(error, null);
|
|
532
|
+
});
|
|
533
|
+
}, config.worker ? parseInt(config.worker) : 10);
|
|
534
|
+
|
|
456
535
|
// RE-FETCH RULE (RECEIVES NO UPDATES VIA SSE)
|
|
457
536
|
this.refetchRule = function(id)
|
|
458
537
|
{
|
|
@@ -546,8 +625,6 @@ module.exports = function(RED)
|
|
|
546
625
|
if((config.autoupdates && config.autoupdates == true) || typeof config.autoupdates == 'undefined')
|
|
547
626
|
{
|
|
548
627
|
if(scope.firmwareUpdateTimeout !== null) { clearTimeout(scope.firmwareUpdateTimeout); };
|
|
549
|
-
|
|
550
|
-
scope.log("Checking for Hue Bridge firmware updates…");
|
|
551
628
|
API.request({
|
|
552
629
|
config: config,
|
|
553
630
|
method: "PUT",
|
|
@@ -564,15 +641,15 @@ module.exports = function(RED)
|
|
|
564
641
|
{
|
|
565
642
|
if(scope.nodeActive == true)
|
|
566
643
|
{
|
|
567
|
-
scope.firmwareUpdateTimeout = setTimeout(function(){ scope.autoUpdateFirmware(); }, 60000 *
|
|
644
|
+
scope.firmwareUpdateTimeout = setTimeout(function(){ scope.autoUpdateFirmware(); }, 60000 * 720);
|
|
568
645
|
}
|
|
569
646
|
})
|
|
570
647
|
.catch(function(error)
|
|
571
648
|
{
|
|
572
|
-
// NO UPDATES AVAILABLE // TRY AGAIN IN
|
|
649
|
+
// NO UPDATES AVAILABLE // TRY AGAIN IN 12H
|
|
573
650
|
if(scope.nodeActive == true)
|
|
574
651
|
{
|
|
575
|
-
scope.firmwareUpdateTimeout = setTimeout(function(){ scope.autoUpdateFirmware(); }, 60000 *
|
|
652
|
+
scope.firmwareUpdateTimeout = setTimeout(function(){ scope.autoUpdateFirmware(); }, 60000 * 720);
|
|
576
653
|
}
|
|
577
654
|
});
|
|
578
655
|
}
|
|
@@ -581,7 +658,7 @@ module.exports = function(RED)
|
|
|
581
658
|
//
|
|
582
659
|
// START THE MAGIC
|
|
583
660
|
this.start();
|
|
584
|
-
|
|
661
|
+
|
|
585
662
|
//
|
|
586
663
|
// CLOSE NODE / REMOVE EVENT LISTENER
|
|
587
664
|
this.on('close', function()
|
|
@@ -597,6 +674,9 @@ module.exports = function(RED)
|
|
|
597
674
|
|
|
598
675
|
// REMOVE FIRMWARE UPDATE TIMEOUT
|
|
599
676
|
if(scope.firmwareUpdateTimeout !== null) { clearTimeout(scope.firmwareUpdateTimeout); }
|
|
677
|
+
|
|
678
|
+
// KILL QUEUE
|
|
679
|
+
scope.patchQueue.kill();
|
|
600
680
|
});
|
|
601
681
|
}
|
|
602
682
|
|
|
@@ -81,6 +81,19 @@
|
|
|
81
81
|
buttonIcon.removeClass("fa-pencil");
|
|
82
82
|
buttonIcon.addClass("fa-search");
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
function sortResourcesBy(prop, resources)
|
|
86
|
+
{
|
|
87
|
+
return resources.sort((a, b) => {
|
|
88
|
+
if ( a[prop] < b[prop] ){
|
|
89
|
+
return -1;
|
|
90
|
+
}
|
|
91
|
+
if ( a[prop] > b[prop] ){
|
|
92
|
+
return 1;
|
|
93
|
+
}
|
|
94
|
+
return 0;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
84
97
|
|
|
85
98
|
function searchAndSelect()
|
|
86
99
|
{
|
|
@@ -98,6 +111,7 @@
|
|
|
98
111
|
$.get('hue/resources', { bridge: bridgeConfig.bridge, key: bridgeConfig.key, type: "motion" })
|
|
99
112
|
.done( function(data) {
|
|
100
113
|
var allResources = JSON.parse(data);
|
|
114
|
+
allResources = sortResourcesBy('name', allResources);
|
|
101
115
|
if(allResources.length <= 0)
|
|
102
116
|
{
|
|
103
117
|
notification.close();
|
|
@@ -194,4 +208,4 @@
|
|
|
194
208
|
}
|
|
195
209
|
}
|
|
196
210
|
});
|
|
197
|
-
</script>
|
|
211
|
+
</script>
|
|
@@ -8,6 +8,7 @@ module.exports = function(RED)
|
|
|
8
8
|
|
|
9
9
|
const scope = this;
|
|
10
10
|
const bridge = RED.nodes.getNode(config.bridge);
|
|
11
|
+
const async = require('async');
|
|
11
12
|
|
|
12
13
|
// SAVE LAST COMMAND
|
|
13
14
|
this.lastCommand = null;
|
|
@@ -114,6 +115,11 @@ module.exports = function(RED)
|
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
let currentState = bridge.get("light_level", tempSensorID);
|
|
118
|
+
if(!currentState)
|
|
119
|
+
{
|
|
120
|
+
scope.error("The sensor in not yet available. Please wait until HueMagic has established a connection with the bridge or check whether the resource ID in the configuration is valid.");
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
117
123
|
|
|
118
124
|
// GET CURRENT STATE
|
|
119
125
|
if( (typeof msg.payload != 'undefined' && typeof msg.payload.status != 'undefined') || (typeof msg.__user_inject_props__ != 'undefined' && msg.__user_inject_props__ == "status") )
|
|
@@ -152,9 +158,30 @@ module.exports = function(RED)
|
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
// PATCH!
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
161
|
+
async.retry({
|
|
162
|
+
times: 3,
|
|
163
|
+
errorFilter: function(err) {
|
|
164
|
+
return (err.status == 503);
|
|
165
|
+
},
|
|
166
|
+
interval: function(retryCount) { return retryCount*2000; }
|
|
167
|
+
},
|
|
168
|
+
function(callback, results)
|
|
169
|
+
{
|
|
170
|
+
bridge.patch("light_level", tempSensorID, patchObject)
|
|
171
|
+
.then(function() { callback(null, true); })
|
|
172
|
+
.catch(function(errors) { callback(errors, null); });
|
|
173
|
+
},
|
|
174
|
+
function(errors, success)
|
|
175
|
+
{
|
|
176
|
+
if(errors)
|
|
177
|
+
{
|
|
178
|
+
scope.error(errors);
|
|
179
|
+
}
|
|
180
|
+
else if(done)
|
|
181
|
+
{
|
|
182
|
+
done();
|
|
183
|
+
}
|
|
184
|
+
});
|
|
158
185
|
}
|
|
159
186
|
else
|
|
160
187
|
{
|
|
@@ -81,6 +81,19 @@
|
|
|
81
81
|
buttonIcon.removeClass("fa-pencil");
|
|
82
82
|
buttonIcon.addClass("fa-search");
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
function sortResourcesBy(prop, resources)
|
|
86
|
+
{
|
|
87
|
+
return resources.sort((a, b) => {
|
|
88
|
+
if ( a[prop] < b[prop] ){
|
|
89
|
+
return -1;
|
|
90
|
+
}
|
|
91
|
+
if ( a[prop] > b[prop] ){
|
|
92
|
+
return 1;
|
|
93
|
+
}
|
|
94
|
+
return 0;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
84
97
|
|
|
85
98
|
function searchAndSelect()
|
|
86
99
|
{
|
|
@@ -98,6 +111,7 @@
|
|
|
98
111
|
$.get('hue/resources', { bridge: bridgeConfig.bridge, key: bridgeConfig.key, type: "button" })
|
|
99
112
|
.done( function(data) {
|
|
100
113
|
var allResources = JSON.parse(data);
|
|
114
|
+
allResources = sortResourcesBy('name', allResources);
|
|
101
115
|
if(allResources.length <= 0)
|
|
102
116
|
{
|
|
103
117
|
notification.close();
|
package/huemagic/hue-buttons.js
CHANGED
|
@@ -132,6 +132,11 @@ module.exports = function(RED)
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
let currentState = bridge.get("button", tempSensorID);
|
|
135
|
+
if(!currentState)
|
|
136
|
+
{
|
|
137
|
+
scope.error("The button/switch in not yet available. Please wait until HueMagic has established a connection with the bridge or check whether the resource ID in the configuration is valid.");
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
135
140
|
|
|
136
141
|
// GET CURRENT STATE
|
|
137
142
|
if( (typeof msg.payload != 'undefined' && typeof msg.payload.status != 'undefined') || (typeof msg.__user_inject_props__ != 'undefined' && msg.__user_inject_props__ == "status") )
|
package/huemagic/hue-group.html
CHANGED
|
@@ -81,6 +81,19 @@
|
|
|
81
81
|
buttonIcon.removeClass("fa-pencil");
|
|
82
82
|
buttonIcon.addClass("fa-search");
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
function sortResourcesBy(prop, resources)
|
|
86
|
+
{
|
|
87
|
+
return resources.sort((a, b) => {
|
|
88
|
+
if ( a[prop] < b[prop] ){
|
|
89
|
+
return -1;
|
|
90
|
+
}
|
|
91
|
+
if ( a[prop] > b[prop] ){
|
|
92
|
+
return 1;
|
|
93
|
+
}
|
|
94
|
+
return 0;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
84
97
|
|
|
85
98
|
function searchAndSelect()
|
|
86
99
|
{
|
|
@@ -98,6 +111,7 @@
|
|
|
98
111
|
$.get('hue/resources', { bridge: bridgeConfig.bridge, key: bridgeConfig.key, type: "group" })
|
|
99
112
|
.done( function(data) {
|
|
100
113
|
var allResources = JSON.parse(data);
|
|
114
|
+
allResources = sortResourcesBy('name', allResources);
|
|
101
115
|
if(allResources.length <= 0)
|
|
102
116
|
{
|
|
103
117
|
notification.close();
|
|
@@ -205,4 +219,4 @@
|
|
|
205
219
|
}
|
|
206
220
|
}
|
|
207
221
|
});
|
|
208
|
-
</script>
|
|
222
|
+
</script>
|