UNPKG

lpd8806-asyncfx

Version:

Non-blocking LPD8806 NodeJS general library with animation effects.

405 lines (375 loc) 14.5 kB
// Dependencies var Color = require('color'); var LPD8806 = require('lpd8806-async'); var async = require('async'); module.exports = function(_ledCount) { 'use strict'; var ledCount; if (typeof _ledCount !== 'number') { throw 'Invalid number of led\'s.'; } else { ledCount = parseInt(_ledCount, 32); } // Internal reference to lpd8806-async var leds = new LPD8806(ledCount, '/dev/spidev1.0'); leds.fillRGB(0, 0, 0); // Initialize off // Private utility functions & variables // ***************************************************************************** var animationRunning = false; var stopAnimationRequest = false; var defaultSpeed = 25; // Used in 'pulseColor', blinks led's function flashEffect(r, g, b, speed) { var step = speed; function performStep() { if (stopAnimationRequest) { stopAnimation(); return; } var level = 0.01, dir = step; async.whilst(function() { return (level >= 0.0 && !stopAnimationRequest); }, function(callback) { setTimeout(function() { leds.setMasterBrightness(level); leds.fill(new Color({ r: r, g: g, b: b })); if (level >= 0.99) { dir = -step; } level += dir; callback(); }, 4); }, function(err) { process.nextTick(performStep); }); } performStep(); } function switchAnimation(cb) { if (!animationRunning) { return startAnimation(cb); } stopAnimationRequest = true; if (animationRunning) { setTimeout(function() { switchAnimation(cb); }, 100); } else { startAnimation(cb); } } function startAnimation(cb) { console.log('Starting animation..'); stopAnimationRequest = false; animationRunning = true; return cb(); } function stopAnimation() { console.log('Animation stopped.'); animationRunning = false; return; } function randomNumber(min, max) { return Math.floor(Math.random() * (max - min) + min); } // Public methods // Base functions (mostly exposed fn's from 'lpd8806-async') // ***************************************************************************** return { setBrightness: function(brightness) { if (brightness) leds.setMasterBrightness(brightness); console.log('[info]', 'Setting brightness', brightness); }, // Returns an array of color values based on the passed in type. Defaults to RGB wheelColor: function(wheelPosition, type) { var color; if (wheelPosition) { switch (type) { case 'rgb': color = leds.wheel_color(wheelPosition).values[type]; break; case 'hsl': color = leds.wheel_color(wheelPosition).values[type]; break; case 'hsv': color = leds.wheel_color(wheelPosition).values[type]; break; case 'cmyk': color = leds.wheel_color(wheelPosition).values[type]; break; default: color = leds.wheel_color(wheelPosition).values.rgb; break; } } return color; }, // Stops current animation if one is running stopAnimation: function() { if (animationRunning) { stopAnimationRequest = true; } }, update: function() { leds.update(); }, fillRGB: function(r, g, b) { switchAnimation(function() { console.log('[info]', 'Filling leds with', r, g, b); leds.fillRGB(r, g, b); stopAnimation(); }); }, fillHSV: function(h, s, v) { switchAnimation(function() { console.log('[info]', 'Filling leds with', h, s, v); leds.fillHSV(h, s, v); stopAnimation(); }); }, off: function() { console.log('[info]', 'Setting Leds Off'); leds.allOFF(); stopAnimation(); }, setPixelRGB: function(pixel, r, g, b) { switchAnimation(function() { leds.setPixelRGB(pixel, r, g, b); leds.update(); }); }, setPixelHSV: function(pixel, h, s, v) { switchAnimation(function() { leds.setPixelHSV(pixel, h, s, v); leds.update(); }); }, setPixelOff: function(pixel) { switchAnimation(function() { leds.setPixelOff(pixel); }); }, // Animation effects // ***************************************************************************** // Lights a pixel on either end of the strip and joins them joinEffect: function(r, g, b, brightness) { switchAnimation(function() { console.log('[info]', 'Playing join animation', r, g, b, brightness); if (ledCount % 2 !== 0)--ledCount; brightness = brightness || 1.0; leds.setMasterBrightness(brightness); function performStep() { if (stopAnimationRequest) { stopAnimation(); return; } var j = 0; leds.allOFF(); async.whilst(function() { return (j < ledCount && !stopAnimationRequest); }, function(callback) { setTimeout(function() { if (j < ledCount / 2) { leds.setPixelRGB(j, r, g, b); if (j > 0) leds.setPixelRGB(j - 1, 0, 0, 0); leds.setPixelRGB(ledCount - j - 1, r, g, b); if (j > 0) leds.setPixelRGB(ledCount - j, 0, 0, 0); if (j == ledCount) { leds.setPixelRGB(ledCount, 0, 0, 0); leds.setPixelRGB(0, 0, 0, 0); } leds.update(); } j++; callback(); }, 40); }, function(err) { process.nextTick(performStep); }); } performStep(); }); }, // Knight Rider style animation flow: function(r, g, b, brightness) { switchAnimation(function() { console.log('[info]', 'Playing knight rider animation', r, g, b, brightness); brightness = brightness || 1.0; leds.setMasterBrightness(brightness); function performStep() { if (stopAnimationRequest) { stopAnimation(); return; } leds.allOFF(); var j = 0; async.whilst(function() { return (j < ledCount && !stopAnimationRequest); }, function(callback) { setTimeout(function() { leds.setPixelRGB(j, r, g, b); if (j > 0) leds.setPixelRGB(j - 1, 0, 0, 0); leds.update(); j++; callback(); }, 4); }, function(err) { if (stopAnimationRequest) { stopAnimation(); return; } process.nextTick(function() { var i = 0; async.whilst(function() { return (i < ledCount && !stopAnimationRequest); }, function(callback) { setTimeout(function() { leds.setPixelRGB(ledCount - i - 1, r, g, b); if (i > 0) leds.setPixelRGB(ledCount - i, 0, 0, 0); leds.update(); i++; callback(); }, 7); }, function(err) { process.nextTick(performStep); }); }); }); } performStep(); }); }, // Fade's the LED's in and out pulseColor: function(r, g, b, speed) { switchAnimation(function() { console.log('[info]', 'Flashing color', r, g, b); speed = speed || 0.09; flashEffect(r, g, b, speed); }); }, rainbow: function(brightness, speed) { switchAnimation(function() { console.log('[info]', 'Playing rainbow animation', brightness); var _step = 0; var start = 0; leds.allOFF(); brightness = brightness || 1.0; speed = speed || defaultSpeed; leds.setMasterBrightness(brightness); var i = 0; function performStep() { if (stopAnimationRequest) { stopAnimation(); return; } var amt = 1; for (var p = 0; p < ledCount; p++) { var color = (p + _step) % 384; leds.setPixel(start + p, leds.wheel_color(color)); } leds.update(); _step += amt; var overflow = _step - 384; if (overflow >= 0) { _step = overflow; } if (++i >= 384) { i = 0; } setTimeout(performStep, speed); } performStep(); }); }, // Single pixel running down the strip colorChase: function(r, g, b, speed) { speed = speed || defaultSpeed; switchAnimation(function() { function performStep() { if (stopAnimationRequest) { stopAnimation(); return; } leds.allOFF(); var i = 0; async.whilst(function() { return (i < ledCount && !stopAnimationRequest); }, function(callback) { setTimeout(function() { leds.setPixelRGB(i, r, g, b); leds.update(); leds.setPixelOff(i); i++; callback(); }, speed); }, function(err) { if (stopAnimationRequest) { stopAnimation(); return; } leds.update(); process.nextTick(performStep); }); } performStep(); }); }, // Randomly color each pixels on/off with random colors rave: function(speed, colorsArray) { speed = speed || defaultSpeed; console.log('[info]', 'rave!'); function randomColors(){ var color = { r: randomNumber(1, 255), g: randomNumber(1, 255), b: randomNumber(1, 255) }; for (var i = 0; i < Math.floor(ledCount/2); i++){ leds.setPixelRGB(randomNumber(1, ledCount), color.r, color.g, color.b); } } function userColors(){ var color = colorsArray[randomNumber(0, colorsArray.length)]; for (var i = 0; i < Math.floor(ledCount/2); i++){ leds.setPixelRGB(randomNumber(1, ledCount), color[0], color[1], color[2]); } } switchAnimation(function() { function performStep() { if (stopAnimationRequest) { stopAnimation(); return; } leds.allOFF(); async.whilst(function() { return (!stopAnimationRequest); }, function(callback) { setTimeout(function() { if(Array.isArray(colorsArray)){ userColors(); } else { randomColors(); } leds.update(); leds.setPixelOff(randomNumber(1, ledCount)); callback(); }, speed); }, function(err) { if (stopAnimationRequest) { stopAnimation(); return; } leds.update(); process.nextTick(performStep); }); } performStep(); }); } }; };