Skip to content

Instantly share code, notes, and snippets.

@AlexJuarez
Last active March 14, 2019 21:13
Show Gist options
  • Save AlexJuarez/683fceeb995b1e779493fb871dc63c44 to your computer and use it in GitHub Desktop.
Save AlexJuarez/683fceeb995b1e779493fb871dc63c44 to your computer and use it in GitHub Desktop.
Mative ws2812b bindings wrapper.
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);
this.initalized = true;
} catch (e) {
this.emit('error', e.message);
}
}
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