Skip to content

Commit

Permalink
Add RGB.pulse method
Browse files Browse the repository at this point in the history
  • Loading branch information
islemaster committed Jan 10, 2018
1 parent 863e922 commit d2005bf
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 28 deletions.
86 changes: 67 additions & 19 deletions lib/led/rgb.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ function RGB(opts) {
blue: 255,
intensity: 100,
isAnode: opts.isAnode || false,
interval: null
interval: null,
isRunning: false
};

// red, green, and blue store the raw color set via .color()
Expand All @@ -193,6 +194,14 @@ function RGB(opts) {
blue: state.blue
};

// state.prev records the last color set using color(),
// and is used to determine the new color when calling on() or pulse().
state.prev = {
red: 255,
green: 255,
blue: 255
};

priv.set(this, state);

Board.Controller.call(this, controller, opts);
Expand All @@ -207,7 +216,7 @@ function RGB(opts) {
},
isRunning: {
get: function() {
return !!state.interval;
return !!(state.interval || state.isRunning);
}
},
isAnode: {
Expand Down Expand Up @@ -399,25 +408,18 @@ RGB.prototype.color = function(red, green, blue) {

this.update(update);

// Store colors to state.prev for future use by on() or pulse()
state.prev = update;

return this;
};

RGB.prototype.on = function() {
var state = priv.get(this);
var colors;

// If it's not already on, we set them to the previous color
if (!this.isOn) {
/* istanbul ignore next */
colors = state.prev || {
red: 255,
green: 255,
blue: 255
};

state.prev = null;

this.update(colors);
this.update(state.prev);
}

return this;
Expand All @@ -426,13 +428,9 @@ RGB.prototype.on = function() {
RGB.prototype.off = function() {
var state = priv.get(this);

// If it's already off, do nothing so the pervious state stays intact
// If it's already off, do nothing so the previous state stays intact
/* istanbul ignore else */
if (this.isOn) {
state.prev = RGB.colors.reduce(function(current, color) {
return (current[color] = state[color], current);
}.bind(this), {});

this.update({
red: 0,
green: 0,
Expand Down Expand Up @@ -475,6 +473,55 @@ RGB.prototype.toggle = function() {
return this[this.isOn ? "off" : "on"]();
};

/**
* pulse Fade the Led in and out in a loop with specified time
* @param {number} duration Time in ms that a fade in/out will elapse
* @return {Led}
*
* - or -
*
* @param {Object} val An Animation() segment config object
*/

RGB.prototype.pulse = function(duration, callback) {
var state = priv.get(this);

var currentColor = state.prev;

this.stop();

var options = {
duration: typeof duration === "number" ? duration : 1000,
keyFrames: [
{intensity: 0, color: currentColor},
{intensity: 100, color: currentColor}
],
metronomic: true,
loop: true,
easing: "inOutSine",
onloop: function() {
/* istanbul ignore else */
if (typeof callback === "function") {
callback();
}
}
};

if (typeof duration === "object") {
Object.assign(options, duration);
}

if (typeof duration === "function") {
callback = duration;
}

state.isRunning = true;

state.animation = state.animation || new Animation(this);
state.animation.enqueue(options);
return this;
};

RGB.prototype.stop = function() {
var state = priv.get(this);

Expand All @@ -488,6 +535,7 @@ RGB.prototype.stop = function() {
}

state.interval = null;
state.isRunning = false;

return this;
};
Expand Down Expand Up @@ -573,7 +621,7 @@ RGB.prototype[Animation.normalize] = function(keyFrames) {
*/

RGB.prototype[Animation.render] = function(frames) {
return this.color(frames[0]);
return this.update(frames[0]);
};

/**
Expand Down
21 changes: 18 additions & 3 deletions test/rgb.collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,21 +291,36 @@ exports["RGB.Collection"] = {


"Animation.render": function(test) {
test.expect(1);
test.expect(4);

var rgbs = new RGB.Collection([
[1, 2, 3],
[4, 5, 6],
]);

this.color = this.sandbox.stub(RGB.prototype, "color");
rgbs.each(function(rgb) {
this.sandbox.stub(rgb, "write");
}.bind(this));

rgbs[Animation.render]([
{ red: 0xff, green: 0x00, blue: 0x00 },
{ red: 0x00, green: 0xff, blue: 0x00 },
]);

test.equal(this.color.callCount, 2);
test.equal(rgbs[0].write.callCount, 1);
test.deepEqual(rgbs[0].write.firstCall.args[0], {
red: 0xff,
green: 0x00,
blue: 0x00
});

test.equal(rgbs[1].write.callCount, 1);
test.deepEqual(rgbs[1].write.firstCall.args[0], {
red: 0x00,
green: 0xff,
blue: 0x00
});

test.done();
},
};
Expand Down
89 changes: 83 additions & 6 deletions test/rgb.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ var rgbProtoProperties = [{
name: "strobe"
}, {
name: "blink"
}, {
name: "pulse"
}, {
name: "stop"
}];
Expand Down Expand Up @@ -39,6 +41,7 @@ exports["RGB"] = {
this.board = newBoard();
this.sandbox = sinon.sandbox.create();
this.analogWrite = this.sandbox.spy(MockFirmata.prototype, "analogWrite");
this.enqueue = this.sandbox.stub(Animation.prototype, "enqueue");

this.rgb = new RGB({
pins: {
Expand Down Expand Up @@ -550,6 +553,76 @@ exports["RGB"] = {
test.done();
},



pulse: function(test) {
test.expect(1);

this.rgb.pulse();

test.equal(this.enqueue.callCount, 1);
test.done();
},

pulseDuration: function(test) {
test.expect(2);

this.rgb.pulse(1010);

test.equal(this.enqueue.callCount, 1);

var duration = this.enqueue.lastCall.args[0].duration;

test.equal(duration, 1010);
test.done();
},


pulseCallback: function(test) {
test.expect(2);

var spy = this.sandbox.spy();

this.rgb.pulse(spy);

test.equal(this.enqueue.callCount, 1);

var onloop = this.enqueue.lastCall.args[0].onloop;

onloop();

test.equal(spy.callCount, 1);
test.done();
},

pulseDurationCallback: function(test) {
test.expect(3);

var spy = this.sandbox.spy();

this.rgb.pulse(1010, spy);

test.equal(this.enqueue.callCount, 1);

var duration = this.enqueue.lastCall.args[0].duration;
var onloop = this.enqueue.lastCall.args[0].onloop;

onloop();


test.equal(duration, 1010);
test.equal(spy.callCount, 1);
test.done();
},

pulseObject: function(test) {
test.expect(1);

this.rgb.pulse({});
test.equal(this.enqueue.callCount, 1);
test.done();
},

intensity: function(test) {
test.expect(24);

Expand Down Expand Up @@ -754,10 +827,11 @@ exports["RGB"] = {
},

"Animation.render": function(test) {
test.expect(1);
this.color = this.sandbox.stub(this.rgb, "color");
this.rgb[Animation.render]([0]);
test.equal(this.color.callCount, 1);
test.expect(2);
// rgb.write() is already wrapped
this.rgb[Animation.render]([{red: 0, green: 0, blue: 0}]);
test.equal(this.rgb.write.callCount, 1);
test.deepEqual(this.rgb.write.firstCall.args[0], {red: 0, green: 0, blue: 0});
test.done();
},

Expand Down Expand Up @@ -786,11 +860,14 @@ exports["RGB - Cycling Operations"] = {
},

rgbCallsStopBeforeNextCyclingOperation: function(test) {
test.expect(1);
test.expect(2);

this.rgb.blink();
this.rgb.pulse();

test.equal(this.stop.callCount, 1);
test.equal(this.stop.callCount, 2);
// pulse is an animation
test.equal(this.enqueue.callCount, 1);

// Ensure that the interval is cleared.
this.rgb.stop();
Expand Down

0 comments on commit d2005bf

Please sign in to comment.