Skip to content

Commit d8eea85

Browse files
committed
Better error handling for getMaxIR
1 parent 60b23e7 commit d8eea85

File tree

5 files changed

+157
-22
lines changed

5 files changed

+157
-22
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ jspm_packages
3535

3636
# Optional REPL history
3737
.node_repl_history
38+
package-lock.json

example/dump_lights.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
var Lifx = require('node-lifx').Client;
4+
var client = new Lifx();
5+
6+
client.on('error', function(err) {
7+
console.log('LIFX error:\n' + err.stack);
8+
client.destroy();
9+
});
10+
11+
client.on('light-new', function(light) {
12+
light.getHardwareVersion((err, data) => {
13+
console.log('getHardwareVersion', light.id, err ? err.message : data);
14+
});
15+
16+
light.getMaxIR((err, data) => {
17+
console.log('getMaxIR', light.id, err ? err.message : data);
18+
});
19+
20+
light.getState((err, data) => {
21+
console.log('getState', light.id, err ? err.message : data);
22+
})
23+
});
24+
25+
26+
client.on('listening', function() {
27+
var address = client.address();
28+
console.log(
29+
'Started LIFX listening on ' +
30+
address.address + ':' + address.port + '\n'
31+
);
32+
});
33+
34+
client.init({
35+
//broadcast: "192.168.1.255",
36+
messageHandlerTimeout: 1000,
37+
//debug: true,
38+
});

lib/lifx-light.js

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ function LightItem(lightID, lifxLight, config) {
9595
address: lifxLight.address,
9696
label: lifxLight.label,
9797
reachable: true,
98+
messageHandlerTimeout: 5000,
9899
maxIRLevel: 0, // Only valid for IR capable lights
100+
getMaxIR_Error: false, // do we get an error when querying for maxIRLevel
99101
}
100102

101103
// Default state
@@ -151,7 +153,14 @@ LightItem.prototype.initialize = function initialize(callback) {
151153
(done) => {
152154
if (!(capability & LightCapability.INFRARED))
153155
return done(null, null);
154-
self.lifx.getMaxIR(done);
156+
self.lifx.getMaxIR((err, data) => {
157+
// getMaxIR generates an error, stop using it and use static value
158+
if (err) {
159+
self.info.getMaxIR_Error = true;
160+
data = { brightness: self.info.maxIRLevel };
161+
}
162+
done(null, data);
163+
});
155164
},
156165

157166
], (err, data) => {
@@ -171,8 +180,11 @@ LightItem.prototype.initialize = function initialize(callback) {
171180
self.state = convertLifxState(lifxInfo);
172181

173182
// Infrared
174-
if (self.info.capability | LightCapability.INFRARED)
175-
self.info.maxIRLevel = lifxMaxIR;
183+
if (self.info.capability | LightCapability.INFRARED &&
184+
_.isPlainObject(lifxMaxIR) &&
185+
_.isFinite(lifxMaxIR.brightness)) {
186+
self.info.maxIRLevel = limitValue(Math.round(lifxMaxIR.brightness), 0, 100);
187+
}
176188

177189
// Update label
178190
self.info.label = lifxInfo.label;
@@ -201,10 +213,15 @@ LightItem.prototype.stop = function stop() {
201213

202214
/**
203215
* Poll light for changes
216+
* @param {?function} callback Optional function to call when done
204217
*/
205-
LightItem.prototype.pollChanges = function pollChanges() {
218+
LightItem.prototype.pollChanges = function pollChanges(callback) {
206219
var self = this;
207220

221+
// Ensure callback is an function
222+
if (typeof callback !== 'function')
223+
callback = function() {}
224+
208225
async.series([
209226
// Get state info
210227
(done) => {
@@ -213,21 +230,37 @@ LightItem.prototype.pollChanges = function pollChanges() {
213230

214231
// Get IR info (if we have the capability)
215232
(done) => {
233+
// Check capability
216234
if (!(self.info.capability & LightCapability.INFRARED))
217235
return done(null, null);
218-
self.lifx.getMaxIR(done);
236+
237+
// Check if getMaxIR returns error
238+
if (!self.info.getMaxIR_Error)
239+
return done(null, { brightness: self.info.maxIRLevel } );
240+
241+
// Get IR level
242+
self.lifx.getMaxIR((err, data) => {
243+
// Ignore errors
244+
if (err) {
245+
data = { brightness: self.info.maxIRLevel };
246+
}
247+
done(null, data);
248+
});
219249
}
220250
], (err, data) => {
221251
if (err) {
252+
callback(err);
222253
return;
223254
}
224255

225256
var lifxState = data[0];
226257
var lifxMaxIR = data[1];
227258

228259
// We need to ignore the changes for this light until modified value has expired
229-
if (self.modified >= process.uptime())
260+
if (self.modified >= process.uptime()) {
261+
callback();
230262
return;
263+
}
231264

232265
var newState = convertLifxState(lifxState);
233266
var isUpdated = false;
@@ -237,9 +270,11 @@ LightItem.prototype.pollChanges = function pollChanges() {
237270
if (isUpdated)
238271
self.state = newState;
239272

240-
if (self.info.capability & LightCapability.INFRARED && _.isFinite(lifxMaxIR)) {
241-
isUpdated = (self.info.maxIRLevel !== lifxMaxIR) || isUpdated;
242-
self.info.maxIRLevel = limitValue(Math.round(lifxMaxIR), 0, 100);
273+
if (self.info.capability & LightCapability.INFRARED &&
274+
_.isPlainObject(lifxMaxIR) &&
275+
_.isFinite(lifxMaxIR.brightness)) {
276+
isUpdated = (self.info.maxIRLevel !== lifxMaxIR.lifxMaxIR) || isUpdated;
277+
self.info.maxIRLevel = limitValue(Math.round(lifxMaxIR.brightness), 0, 100);
243278
}
244279

245280
// Copy label
@@ -248,6 +283,8 @@ LightItem.prototype.pollChanges = function pollChanges() {
248283
// Values/state has been updated
249284
if (isUpdated)
250285
self.emit('update');
286+
287+
callback();
251288
});
252289
}
253290

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-red-contrib-node-lifx",
3-
"version": "0.9.1",
3+
"version": "0.9.2",
44
"description": "Control Lifx lights using Node-RED.",
55
"author": "jdomeij",
66
"homepage": "https://github.com/jdomeij/node-red-contrib-node-lifx",
@@ -27,16 +27,16 @@
2727
"main": "lib/lifx-server.js",
2828
"license": "Apache-2.0",
2929
"devDependencies": {
30-
"chai": "^3.5.0",
31-
"chai-spies": "^0.7.1",
32-
"mocha": "^3.2.0"
30+
"chai": "^4.1.2",
31+
"chai-spies": "^1.0.0",
32+
"mocha": "^3.5.3"
3333
},
3434
"dependencies": {
35-
"async": "^2.1.4",
36-
"color-convert": "^1.9.0",
37-
"color-space": "^1.14.7",
35+
"async": "^2.6.0",
36+
"color-convert": "^1.9.1",
37+
"color-space": "^1.15.0",
3838
"color-temp": "0.0.2",
39-
"enum": "^2.3.0",
39+
"enum": "^2.5.0",
4040
"lodash": "^4.17.3",
4141
"node-lifx": "^0.8.0"
4242
},

test/lifx-light.test.js

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,9 @@ describe('Lifx-Light', () => {
496496
});
497497

498498
it('Basic test', (done) => {
499-
lightItem.pollChanges();
500-
done();
499+
lightItem.pollChanges((err) => {
500+
done(err);
501+
});
501502
});
502503
});
503504

@@ -537,14 +538,70 @@ describe('Lifx-Light', () => {
537538

538539
});
539540

541+
describe('IR Support: Error Handling', () => {
542+
it('getMaxIR init error', (done) => {
543+
var lightItem, lifxItem;
544+
lifxItem = new LifxEmulator();
545+
lifxItem._getHWVerData.productFeatures.infrared = true;
546+
547+
// Emulate error message from getMaxIR
548+
lifxItem.getMaxIR = function(callback) {
549+
callback(new Error('test'));
550+
};
551+
552+
lightItem = new LifxLight(lifxItem.id, lifxItem, {});
553+
lightItem.initialize((err) => {
554+
if (err)
555+
return done(err);
556+
557+
expect(lightItem.info.getMaxIR_Error).to.be.true;
558+
lightItem.stop();
559+
560+
done();
561+
});
562+
});
563+
564+
565+
it('getMaxIR poll error', (done) => {
566+
var lightItem, lifxItem;
567+
lifxItem = new LifxEmulator();
568+
lifxItem._getHWVerData.productFeatures.infrared = true;
569+
570+
// Initialize can call getMaxIR
571+
lifxItem.getMaxIR = function(callback) {
572+
callback(null, {brightness: 33});
573+
};
574+
575+
lightItem = new LifxLight(lifxItem.id, lifxItem, {});
576+
lightItem.initialize((err) => {
577+
if (err)
578+
return done(err);
579+
580+
expect(lightItem.info.maxIRLevel).to.equal(33);
581+
expect(lightItem.info.getMaxIR_Error).to.be.false;
582+
583+
// Poll will generate error
584+
lightItem.getMaxIR = function(callback) {
585+
callback(new Error('test'));
586+
};
587+
588+
lightItem.stop();
589+
lightItem.pollChanges((err) => {
590+
done(err);
591+
})
592+
});
593+
});
594+
});
595+
596+
540597
describe('IR Support', () => {
541598
var lightItem, lifxItem;
542599
beforeEach((done) => {
543600
lifxItem = new LifxEmulator();
544601
lifxItem._getHWVerData.productFeatures.infrared = true;
545602

546603
lifxItem.getMaxIR = function(callback) {
547-
callback(null, 33);
604+
callback(null, { brightness: 33 });
548605
};
549606

550607
lightItem = new LifxLight(lifxItem.id, lifxItem, {});
@@ -583,9 +640,11 @@ describe('Lifx-Light', () => {
583640
});
584641

585642
it('pollChanges', (done) => {
586-
lightItem.pollChanges();
643+
lightItem.pollChanges((err) => {
644+
done(err);
645+
646+
});
587647

588-
done();
589648
});
590649
});
591650
});

0 commit comments

Comments
 (0)