Skip to content

Instantly share code, notes, and snippets.

@jamesbulpin
Created December 18, 2016 21:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamesbulpin/ec819028f5f0a1a8686173da014fcbe3 to your computer and use it in GitHub Desktop.
Save jamesbulpin/ec819028f5f0a1a8686173da014fcbe3 to your computer and use it in GitHub Desktop.
Hacked up WS2811 LED connector for Octoblu
var ws281x = require('rpi-ws281x-native');
var meshblu = require('meshblu');
var meshbluJSON = require("./meshblu.json");
var tinycolor = require("tinycolor2");
var mic = require('microphone');
var VUMeter = require('vu-meter')
// Specifies how you want your message payload to be passed
// from Octoblu to your device
var MESSAGE_SCHEMA = {
type: 'object',
properties: {
mode: {
type: 'string',
required: true
},
color: {
type: 'integer',
required: false
}
}
};
var NUM_LEDS = 100,
pixelData = new Uint32Array(NUM_LEDS),
modulation = new Uint32Array(NUM_LEDS);
var mode = "";
var color = 0xffffff;
ws281x.init(NUM_LEDS);
var meter = new VUMeter();
var vu = 0;
last_vals = []
for (var i =0; i < 50; i++) {
last_vals.push(-33.0);
}
last_val_index = 0;
meter.on('data', function(data) {
last_vals[last_val_index] = data[0];
last_val_index++;
if (last_val_index >= last_vals.length) last_val_index = 0;
var min = last_vals.reduce(function(a, b) {return Math.min(a,b);}, 100);
var max = last_vals.reduce(function(a, b) {return Math.max(a,b);}, -100);
var x = Math.floor(50*(data[0] - min)/(max-min));
if (x < 0) x = 0;
if (x > 49) x = 49;
vu = x;
//console.log("Input=%s min/max %s/%s vu=%s", data[0], min, max, vu);
});
mic.audioStream.on('data', function(data) {
meter.write(data, function(err) {
if (err) {
console.log("mic.audioStream.on error: " + str(err));
}
});
});
mic.startCapture();
process.on('SIGINT', function () {
ws281x.reset();
process.nextTick(function () { process.exit(0); });
});
// Animation loop
var offset = 0;
setInterval(function () {
for (var i = 0; i < NUM_LEDS; i++) {
if ((offset % 40) == (i % 40)) {
modulation[i] = Math.round(Math.random());
}
switch (mode) {
case "colorwheel":
pixelData[i] = colorwheel((offset + i) % 256);
break;
case "bars":
case "yoyo":
case "yo-yo":
pixelData[i] = bars(i, offset % (NUM_LEDS*2));
break;
case "solid":
pixelData[i] = color;
break;
case "echo":
case "vu":
pixelData[i] = vubar(i);
break;
case "snowfall":
pixelData[i] = snowfall(i, (offset/2) % 100);
break;
case "twinkle":
case "twinklewhite":
pixelData[i] = twinklewhite(i);
break;
case "flashing":
case "twinklecolor":
pixelData[i] = twinklecolor(i);
break;
case "nothing":
pixelData[i] = 0;
break;
}
}
offset = (offset + 1);
ws281x.render(pixelData);
}, 1000 / 120);
console.log('Press <ctrl>+C to exit.');
function bars(pos, step) {
if (step > (NUM_LEDS-1)) {
step = (NUM_LEDS*2) - 1 - step;
}
if (step >= pos) {
return colorwheel((offset + pos) % 256);
}
return 0;
}
var snowfall_rg = {}
function snowfall(pos, step) {
pos = 99 - pos;
if (Math.abs(pos-step) < 5) {
var rg = 0;
if (snowfall_rg[pos]) {
rg = snowfall_rg[pos];
}
else {
rg = 127 + Math.random() * 128;
snowfall_rg[pos] = rg;
}
return rgb2Int(rg, rg, 255);
}
snowfall_rg[pos] = null;
return rgb2Int(0, 0, 0);
}
function twinklewhite(pos) {
return modulation[pos] * rgb2Int(255, 255, 255);
}
function twinklecolor(pos) {
return modulation[pos] * colorwheel((offset + pos)%256);
}
// rainbow-colors, taken from http://goo.gl/Cs3H0v
function colorwheel(pos) {
pos = 255 - pos;
if (pos < 85) { return rgb2Int(255 - pos * 3, 0, pos * 3); }
else if (pos < 170) { pos -= 85; return rgb2Int(0, pos * 3, 255 - pos * 3); }
else { pos -= 170; return rgb2Int(pos * 3, 255 - pos * 3, 0); }
}
function vubar(pos) {
var vpos = pos / (NUM_LEDS/50);
if (vpos <= vu) return colorwheel((offset + pos) % 256);
return 0;
}
function rgb2Int(r, g, b) {
return ((g & 0xff) << 16) + ((r & 0xff) << 8) + (b & 0xff);
}
connectionTimer = setTimeout(function() {
console.log("Timeout setting up connections, exiting.");
process.exit(1);
}, 120000);
// Not specifying a UUID/Token auto-registers a new device
var conn = meshblu.createConnection({
"uuid": meshbluJSON.uuid,
"token": meshbluJSON.token,
"server": "meshblu.octoblu.com",
"port": 80
});
conn.on('notReady', function(data){
console.log('Octoblu UUID FAILED AUTHENTICATION!');
console.log(data);
});
function handle_message(newmode, newcolor) {
if (newmode == "solid") {
if (newcolor) {
var c = parseInt(newcolor);
if (isNaN(c)) {
var rgb = tinycolor(newcolor).toRgb();
c = rgb2Int(rgb.r, rgb.g, rgb.b);
}
color = c;
console.log("Setting colour " + c);
}
}
mode = newmode;
}
conn.on('ready', function(rdata){
console.log('UUID AUTHENTICATED!');
console.log(rdata);
clearTimeout(connectionTimer);
connectionTimer = undefined;
conn.update({
"uuid": meshbluJSON.uuid,
"token": meshbluJSON.token,
"messageSchema": MESSAGE_SCHEMA,
});
conn.on('message', function(data){
console.log('Octoblu message received');
console.log(data);
mode = data.mode;
color = ("color" in data)?data.color:null;
handle_message(mode, color)
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment