From c597e73dee512801a5b55c467c9b8fbabea970e8 Mon Sep 17 00:00:00 2001 From: Brandon Vandegrift Date: Sun, 6 Nov 2016 19:44:05 -0500 Subject: [PATCH 1/3] Infrared support. getInfrared, setInfrared, stateInfrared packets. maxIR() and getMaxIR() functions for light objects. tests for maxIR() and getMaxIR(). --- lib/lifx/constants.js | 4 +++ lib/lifx/light.js | 46 +++++++++++++++++++++++++++++++ lib/lifx/packet.js | 3 ++ lib/lifx/packets/getInfrared.js | 7 +++++ lib/lifx/packets/index.js | 4 +++ lib/lifx/packets/setInfrared.js | 46 +++++++++++++++++++++++++++++++ lib/lifx/packets/stateInfrared.js | 42 ++++++++++++++++++++++++++++ test/unit/light-test.js | 11 ++++++++ 8 files changed, 163 insertions(+) create mode 100644 lib/lifx/packets/getInfrared.js create mode 100644 lib/lifx/packets/setInfrared.js create mode 100644 lib/lifx/packets/stateInfrared.js diff --git a/lib/lifx/constants.js b/lib/lifx/constants.js index 3d0c277..a374123 100644 --- a/lib/lifx/constants.js +++ b/lib/lifx/constants.js @@ -37,6 +37,10 @@ module.exports = { HSBK_MINIMUM_HUE: 0, HSBK_MAXIMUM_HUE: 360, + // Infrared constants + IR_MINIMUM_BRIGHTNESS: 0, + IR_MAXIMUM_BRIGHTNESS: 100, + // Vendor ID values LIFX_VENDOR_IDS: [ {id: 1, name: 'LIFX'} diff --git a/lib/lifx/light.js b/lib/lifx/light.js index 5961344..4b1a3a5 100644 --- a/lib/lifx/light.js +++ b/lib/lifx/light.js @@ -111,6 +111,30 @@ Light.prototype.color = function(hue, saturation, brightness, kelvin, duration, this.client.send(packetObj, callback); }; +/** + * Sets the Maximum Infrared brightness + * @param {Number} brightness color brightness from 0 - 100 (in %) + * @param {Function} [callback] called when light did receive message + */ +Light.prototype.maxIR = function(brightness, callback) { + if (typeof brightness !== 'number' || brightness < constants.IR_MINIMUM_BRIGHTNESS || brightness > constants.IR_MAXIMUM_BRIGHTNESS) { + throw new RangeError('LIFX light setMaxIR method expects brightness to be a number between ' + + constants.IR_MINIMUM_BRIGHTNESS + ' and ' + constants.IR_MAXIMUM_BRIGHTNESS + ); + } + brightness = Math.round(brightness / constants.IR_MAXIMUM_BRIGHTNESS * 65535); + + if (callback !== undefined && typeof callback !== 'function') { + throw new TypeError('LIFX light setMaxIR method expects callback to be a function'); + } + + var packetObj = packet.create('setInfrared', { + brightness: brightness + }, this.client.source); + packetObj.target = this.id; + this.client.send(packetObj, callback); +}; + /** * Requests the current state of the light * @param {Function} callback a function to accept the data @@ -142,6 +166,28 @@ Light.prototype.getState = function(callback) { }, sqnNumber); }; +/** + * Requests the current maximum setting for the infrared channel + * @param {Function} callback a function to accept the data + */ +Light.prototype.getMaxIR = function(callback) { + if (typeof callback !== 'function') { + throw new TypeError('LIFX light getMaxIR method expects callback to be a function'); + } + var packetObj = packet.create('getInfrared', {}, this.client.source); + packetObj.target = this.id; + var sqnNumber = this.client.send(packetObj); + this.client.addMessageHandler('stateInfrared', function(err, msg) { + if (err) { + return callback(err, null); + } + + msg.brightness = Math.round(msg.brightness * (constants.HSBK_MAXIMUM_BRIGHTNESS / 65535)); + + callback(null, msg.brightness); + }, sqnNumber); +}; + /** * Requests hardware info from the light * @param {Function} callback a function to accept the data with error and diff --git a/lib/lifx/packet.js b/lib/lifx/packet.js index b46101c..070d405 100644 --- a/lib/lifx/packet.js +++ b/lib/lifx/packet.js @@ -69,6 +69,9 @@ Packet.typeList = [ {id: 117, name: 'setPower'}, {id: 118, name: 'statePower'}, // {id: 119, name: 'setWaveformOptional'}, + {id: 120, name: 'getInfrared'}, + {id: 121, name: 'stateInfrared'}, + {id: 122, name: 'setInfrared'}, {id: 401, name: 'getAmbientLight'}, {id: 402, name: 'stateAmbientLight'} // {id: 403, name: 'getDimmerVoltage'}, diff --git a/lib/lifx/packets/getInfrared.js b/lib/lifx/packets/getInfrared.js new file mode 100644 index 0000000..574e163 --- /dev/null +++ b/lib/lifx/packets/getInfrared.js @@ -0,0 +1,7 @@ +'use strict'; + +var Packet = { + size: 0 +}; + +module.exports = Packet; diff --git a/lib/lifx/packets/index.js b/lib/lifx/packets/index.js index de4cd5c..eb48f42 100644 --- a/lib/lifx/packets/index.js +++ b/lib/lifx/packets/index.js @@ -55,6 +55,10 @@ packets.setWaveform = require('./setWaveform'); packets.getTemperature = require('./getTemperature'); packets.stateTemperature = require('./stateTemperature'); +packets.getInfrared = require('./getInfrared'); +packets.setInfrared = require('./setInfrared'); +packets.stateInfrared = require('./stateInfrared'); + /* * Sensor related packages */ diff --git a/lib/lifx/packets/setInfrared.js b/lib/lifx/packets/setInfrared.js new file mode 100644 index 0000000..90fe5ed --- /dev/null +++ b/lib/lifx/packets/setInfrared.js @@ -0,0 +1,46 @@ +'use strict'; + +var Packet = { + size: 2 +}; + +/** + * Converts packet specific data from a buffer to an object + * @param {Buffer} buf Buffer containing only packet specific data no header + * @return {Object} Information contained in packet + */ +Packet.toObject = function(buf) { + var obj = {}; + var offset = 0; + + if (buf.length !== this.size) { + throw new Error('Invalid length given for setInfrared LIFX packet'); + } + + obj.brightness = buf.readUInt16LE(offset); + offset += 2; + + return obj; +}; + +/** + * Converts the given packet specific object into a packet + * @param {Object} obj object with configuration data + * @param {Number} obj.brightness between 0 and 65535 + * @return {Buffer} packet + */ +Packet.toBuffer = function(obj) { + var buf = new Buffer(this.size); + buf.fill(0); + var offset = 0; + + if (typeof obj.brightness !== 'number' && obj.brightness < 0 && obj.brightness > 65535) { + throw new RangeError('Invalid brightness given for setInfrared LIFX packet, must be a number between 0 and 65535'); + } + buf.writeUInt16LE(obj.brightness, offset); + offset += 2; + + return buf; +}; + +module.exports = Packet; diff --git a/lib/lifx/packets/stateInfrared.js b/lib/lifx/packets/stateInfrared.js new file mode 100644 index 0000000..489a805 --- /dev/null +++ b/lib/lifx/packets/stateInfrared.js @@ -0,0 +1,42 @@ +'use strict'; + +var Packet = { + size: 2 +}; + +/** + * Converts packet specific data from a buffer to an object + * @param {Buffer} buf Buffer containing only packet specific data no header + * @return {Object} Information contained in packet + */ +Packet.toObject = function(buf) { + var obj = {}; + var offset = 0; + + if (buf.length !== this.size) { + throw new Error('Invalid length given for stateInfrared LIFX packet'); + } + + obj.brightness = buf.readUInt16LE(offset); + offset += 2; + + return obj; +}; + +/** + * Converts the given packet specific object into a packet + * @param {Object} obj object with configuration data + * @return {Buffer} packet + */ +Packet.toBuffer = function(obj) { + var buf = new Buffer(this.size); + buf.fill(0); + var offset = 0; + + buf.writeUInt16LE(obj.brightness, offset); + offset += 2; + + return buf; +}; + +module.exports = Packet; diff --git a/test/unit/light-test.js b/test/unit/light-test.js index d798ba8..2c57954 100644 --- a/test/unit/light-test.js +++ b/test/unit/light-test.js @@ -335,4 +335,15 @@ suite('Light', () => { assert.equal(getMsgHandlerLength(), currHandlerCnt + 1, 'adds a handler'); currHandlerCnt += 1; }); + + test('getting infrared', () => { + assert.throw(() => { + bulb.getMaxIR('someValue'); + }, TypeError); + + let currHandlerCnt = getMsgHandlerLength(); + bulb.getMaxIR(() => {}); + assert.equal(getMsgHandlerLength(), currHandlerCnt + 1, 'adds a handler'); + currHandlerCnt += 1; + }); }); From f4f97b1c4fece5bb9740982560eddc7dc87c2b7f Mon Sep 17 00:00:00 2001 From: Brandon Vandegrift Date: Sun, 6 Nov 2016 19:50:18 -0500 Subject: [PATCH 2/3] forgot to commit unit test for maxIR() --- test/unit/light-test.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/unit/light-test.js b/test/unit/light-test.js index 2c57954..9899d10 100644 --- a/test/unit/light-test.js +++ b/test/unit/light-test.js @@ -179,6 +179,42 @@ suite('Light', () => { currHandlerCnt += 1; }); + test('changing infrared maximum brightness', () => { + let currMsgQueCnt = getMsgQueueLength(); + let currHandlerCnt = getMsgHandlerLength(); + + // Error cases + assert.throw(() => { + // No arguments + bulb.maxIR(); + }, RangeError); + + assert.throw(() => { + // Brightness too low + bulb.maxIR(constant.IR_MINIMUM_BRIGHTNESS - 1); + }, RangeError); + + assert.throw(() => { + // Brightness too high + bulb.maxIR(constant.IR_MAXIMUM_BRIGHTNESS + 1); + }, RangeError); + + assert.throw(() => { + // Invalid callback + bulb.maxIR(constant.IR_MAXIMUM_BRIGHTNESS, 'someValue'); + }, TypeError); + + bulb.maxIR(50); + assert.equal(getMsgQueueLength(), currMsgQueCnt + 1, 'sends a packet to the queue'); + currMsgQueCnt += 1; + + bulb.maxIR(50, () => {}); + assert.equal(getMsgQueueLength(), currMsgQueCnt + 1, 'sends a packet to the queue'); + currMsgQueCnt += 1; + assert.equal(getMsgHandlerLength(), currHandlerCnt + 1, 'adds a handler'); + currHandlerCnt += 1; + }); + test('getting light summary', () => { assert.throw(() => { bulb.getState('test'); From aeb4cada55d4bd47eb5bd74d5a52fac449a9a068 Mon Sep 17 00:00:00 2001 From: Brandon Vandegrift Date: Sun, 6 Nov 2016 19:50:46 -0500 Subject: [PATCH 3/3] typo --- lib/lifx/light.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lifx/light.js b/lib/lifx/light.js index 4b1a3a5..aa59f3b 100644 --- a/lib/lifx/light.js +++ b/lib/lifx/light.js @@ -113,7 +113,7 @@ Light.prototype.color = function(hue, saturation, brightness, kelvin, duration, /** * Sets the Maximum Infrared brightness - * @param {Number} brightness color brightness from 0 - 100 (in %) + * @param {Number} brightness infrared brightness from 0 - 100 (in %) * @param {Function} [callback] called when light did receive message */ Light.prototype.maxIR = function(brightness, callback) {