Created
March 19, 2019 18:49
-
-
Save AlexJuarez/70a67c18d359c545878e6b4f4df7d50b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const ws281x = require('rpi-ws281x-native'); | |
const EventEmitter = require('events'); | |
function parse(i, min, max) { | |
const num = Number(i); | |
if (isNaN((num))) { | |
return min; | |
} | |
return Math.min(max, Math.max(min, num)); | |
} | |
const DEFAULT_OPTIONS = { | |
frequency: 700000, | |
dmaNum: 10, | |
gpioPin: 18, | |
}; | |
const LED_MAX = 1000; | |
class FastPixel extends EventEmitter { | |
constructor() { | |
super(); | |
this.ledCount = 1; | |
this.pixelData = new Uint32Array(1); | |
this.brightness = 100; | |
this.timeout = null; | |
this.initalized = false; | |
} | |
setLedCount(str) { | |
const num = parse(str, 0, LED_MAX); | |
if (this.ledCount === num) { | |
return; | |
} | |
if (this.initalized) { | |
this.clearAnimation(); | |
this.pixelData = null; | |
ws281x.reset(); | |
} | |
try { | |
ws281x.init(num, DEFAULT_OPTIONS); | |
this.ledCount = num; | |
this.pixelData = new Uint32Array(num); | |
} catch (e) { | |
this.emit('error', e.message); | |
} | |
this.initalized = true; | |
} | |
setBrightness(percent) { | |
const num = parse(percent, 0, 100); | |
if (this.brightness === num) { | |
return; | |
} | |
const brightness = Math.floor(num * 255 / 100); | |
if (this.initalized) { | |
try { | |
ws281x.setBrightness(brightness); | |
this.brightness = num; | |
} catch (e) { | |
this.emit('error', e.message); | |
} | |
} | |
} | |
clearAnimation() { | |
if (this.timeout != null) { | |
clearTimeout(this.timeout); | |
this.timeout = null; | |
} | |
} | |
rgb2Int(r, g, b) { | |
return ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff); | |
} | |
setPixel(i, { r = 0, g = 0, b = 0 }) { | |
this.pixelData[i] = this.rgb2Int(r, g, b); | |
} | |
render() { | |
if (!this.initalized) { | |
return; | |
} | |
try { | |
ws281x.render(this.pixelData); | |
} catch (e) { | |
this.emit('error', e.message); | |
} | |
} | |
animate(fn, time = 1000/30) { | |
if (!this.initalized) { | |
this.emit('error', 'The driver has not been initialized.'); | |
return; | |
} | |
this.clearAnimation(); | |
const execute = () => { | |
const start = new Date(); | |
fn(this.pixelData, Math.floor(start / time)); | |
try { | |
ws281x.render(this.pixelData); | |
} catch (e) { | |
this.emit('error', e.message); | |
this.clearAnimation(); | |
} | |
const elapsed = new Date() - start; | |
if (elapsed < time) { | |
this.timeout = setTimeout(execute, time - elapsed); | |
} else { | |
this.emit('warn', `animation loop ran long ${elapsed}ms`); | |
execute(); | |
} | |
}; | |
execute(); | |
} | |
} | |
module.exports = new FastPixel(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment