Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infrared support for new LIFX+ #42

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/lifx/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'}
Expand Down
46 changes: 46 additions & 0 deletions lib/lifx/light.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 infrared 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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions lib/lifx/packet.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'},
Expand Down
7 changes: 7 additions & 0 deletions lib/lifx/packets/getInfrared.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

var Packet = {
size: 0
};

module.exports = Packet;
4 changes: 4 additions & 0 deletions lib/lifx/packets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
46 changes: 46 additions & 0 deletions lib/lifx/packets/setInfrared.js
Original file line number Diff line number Diff line change
@@ -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;
42 changes: 42 additions & 0 deletions lib/lifx/packets/stateInfrared.js
Original file line number Diff line number Diff line change
@@ -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;
47 changes: 47 additions & 0 deletions test/unit/light-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -335,4 +371,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;
});
});