rpi-rgb
Version:
Implements PWM control of RGB lighting via Raspberry Pi GPIO
237 lines (182 loc) • 6.94 kB
JavaScript
// rpi-rgb
// Supplies simple method of controlling PWM rgb
// lighting using raspberry pi GPIO
module.exports.Channel = Channel;
module.exports.Colour = Colour;
var gpio = require('wiring-pi');
var math = require('mathjs');
function Colour (red, green, blue) {
this.red = red;
this.green = green;
this.blue = blue;
this.clamp();
}
Colour.prototype.clamp = function() {
this.red = Math.max(0, Math.min(this.red, 100));
this.green = Math.max(0, Math.min(this.green, 100));
this.blue = Math.max(0, Math.min(this.blue, 100));
}
// GPIO is set up to use wiringpi pin numbers.
// See http://wiringpi.com/pins/ for detailed information.
// Alternatively you can run 'gpio readall' in bash to see
// pin information.
gpio.setup('wpi');
function Channel(redPin, greenPin, bluePin) {
this._pinRed = redPin;
this._pinGreen = greenPin;
this._pinBlue = bluePin;
// Current RGB value
this._valRed = 0;
this._valGreen = 0;
this._valBlue = 0;
// Variables needed to track fading
this._fade = {};
this._fade.active = false;
this._fade.pulse = false;
this._fade.strobe = false;
this._fade.steps = 0;
this._fade.stepcount = 0;
this._fade.dR = 0;
this._fade.dG = 0;
this._fade.dB = 0;
this._timer;
gpio.pinMode(this._pinRed, gpio.OUTPUT);
gpio.pinMode(this._pinGreen,gpio.OUTPUT);
gpio.pinMode(this._pinBlue, gpio.OUTPUT);
if (gpio.softPwmCreate(this._pinRed, 0, 100)) {
console.log('Failed to create Red PWM channel on pin ' + this._pinRed);
}
if (gpio.softPwmCreate(this._pinGreen, 0, 100)) {
console.log('Failed to create Green PWM channel on pin ' + this._pinGreen);
}
if (gpio.softPwmCreate(this._pinBlue, 0, 100)) {
console.log('Failed to create Blue PWM channel on pin ' + this._pinBlue);
}
};
Channel.prototype.setRgb = function (colour, callback) {
clearInterval(this._timer);
this._valRed = colour.red;
this._valGreen = colour.green;
this._valBlue = colour.blue;
gpio.softPwmWrite(this._pinRed, math.floor(this._valRed));
gpio.softPwmWrite(this._pinGreen, math.floor(this._valGreen));
gpio.softPwmWrite(this._pinBlue, math.floor(this._valBlue));
if (typeof callback === 'function') callback();
return 0;
};
Channel.prototype.fadeRgb = function (colour, time, callback) {
// Don't interrupt strobing, try again in ~20ms
if (this._fade.strobe === true) {
setTimeout( function(self, colour, time, callback){
self.fadeRgb(colour, time, callback);
}, 20, this, colour, time, callback);
return;
}
// Dividing time (ms) by 20 gives 50Hz update rate
this._fade.steps = math.round(time / 20);
this._fade.dR = (colour.red - this._valRed) / this._fade.steps;
this._fade.dG = (colour.green - this._valGreen) / this._fade.steps;
this._fade.dB = (colour.blue - this._valBlue) / this._fade.steps;
this._fade.stepcount = 0;
this._fade.active = true;
this._updateFade(callback);
};
Channel.prototype.pulseRgb = function (startColour, endColour, fadeTime, pulseTime) {
// Fades into start colour and then pulses between Start and End colors.
// fadeTime - governs how fast the LEDs fade to the start color.
// pulseTime - governs how fast the pulse occurs in one direction,
// meaning one full cycle lasts 2* pulseTime.
thisObj = this;
this.fadeRgb(startColour, fadeTime, function() {
thisObj._fade.pulse = true;
thisObj.fadeRgb(endColour, pulseTime);
});
}
Channel.prototype.endPulse = function(callback) {
this._fade.pulse = false;
clearTimeout(this.timer);
if (typeof callback === 'function') callback();
}
Channel.prototype.strobeRgb = function(colour, pulseLength, duration, callback) {
var halfPeriod = pulseLength; // time in ms between switching on/off
this._fade.steps = math.round(duration / halfPeriod);
this._fade.stepcount = 0;
// This line ensures ending in an 'off' state
if (this._fade.steps % 2 === 0) this._fade.steps++;
this._fade.dR = colour.red;
this._fade.dG = colour.green;
this._fade.dB = colour.blue;
this._fade.strobe = true;
this._updateStrobe(halfPeriod, callback);
}
Channel.prototype.close = function () {
gpio.softPwmStop(this._pinRed);
gpio.softPwmStop(this._pinGreen);
gpio.softPwmStop(this._pinBlue);
};
Channel.prototype._updateFade = function (callback) {
var fadeInfo = this._fade; // Because of readability
if (fadeInfo.active === false) return;
this._valRed = this._valRed + fadeInfo.dR;
this._valGreen = this._valGreen + fadeInfo.dG;
this._valBlue = this._valBlue + fadeInfo.dB;
gpio.softPwmWrite(this._pinRed, math.floor(this._valRed));
gpio.softPwmWrite(this._pinGreen, math.floor(this._valGreen));
gpio.softPwmWrite(this._pinBlue, math.floor(this._valBlue));
fadeInfo.stepcount++;
if (fadeInfo.stepcount < fadeInfo.steps) {
this.timer = setTimeout(function (thisObj) { thisObj._updateFade(callback); }, 20, this);
}
else {
// End of fade
if (fadeInfo.pulse)
{
//reverse signs on RGB and reset stepcount
fadeInfo.dR = -fadeInfo.dR;
fadeInfo.dG = -fadeInfo.dG;
fadeInfo.dB = -fadeInfo.dB;
fadeInfo.stepcount = 0;
this.timer = setTimeout(function (thisObj) { thisObj._updateFade(callback); }, 20, this);
}
else {
//Clean up
// math.abs is used to prevent channels from having a value of -0
this._valRed = math.abs(math.round(this._valRed));
this._valGreen = math.abs(math.round(this._valGreen));
this._valBlue = math.abs(math.round(this._valBlue));
this._fade.active = false;
this._fade.steps = 0;
this._fade.stepcount = 0;
this._fade.dR = 0;
this._fade.dG = 0;
this._fade.dB = 0;
// If callback present, call it
if (typeof callback === 'function') callback();
}
}
};
Channel.prototype._updateStrobe = function (halfPeriod, callback) {
if (this._fade.strobe === false) return;
switch (this._fade.stepcount % 2) {
case 0:
this.setRgb(new Colour(0,0,0));
break;
case 1:
this.setRgb(new Colour(this._fade.dR, this._fade.dG, this._fade.dB));
break;
}
this._fade.stepcount++;
if (this._fade.stepcount < this._fade.steps) {
setTimeout(function(self, time, callback) {self._updateStrobe(time, callback);}, halfPeriod, this, halfPeriod, callback);
}
else {
this._fade.strobe = false;
this._fade.steps = 0;
this._fade.stepcount = 0;
this._fade.dR = 0;
this._fade.dG = 0;
this._fade.dB = 0;
// If callback present, call it
if (typeof callback === 'function') callback();
}
}