Created
December 10, 2018 16:24
-
-
Save jamesbulpin/c050bde1d8841a705536818fb27936c5 to your computer and use it in GitHub Desktop.
#IoTree MQTT version
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
var ws281x = require('rpi-ws281x-native'); | |
var tinycolor = require("tinycolor2"); | |
var mqtt = require('mqtt'); | |
var font5x7 = require('./font.js'); | |
var fs = require('fs'); | |
try { | |
var xy = require('./xy.json'); | |
} | |
catch (ex) { | |
var xy = null; | |
} | |
var config_mqtt = require("../config/config_mqtt.js"); | |
restartTimer = setTimeout(function() { | |
console.log("[" + new Date() + "] " + "Exiting after pre-set delay."); | |
var state = {}; | |
state.mode = mode; | |
state.color = color; | |
state.dmmessage = dmmessage; | |
fs.writeFile("/tmp/ws2811.json", JSON.stringify(state), function(err) { | |
process.exit(0); | |
}); | |
}, 3600000); | |
var NUM_LEDS = 100, | |
pixelData = new Uint32Array(NUM_LEDS), | |
modulation = new Uint32Array(NUM_LEDS); | |
var mode = ""; | |
var color = 0xffffff; | |
var dmmessage = " XMAS"; | |
try { | |
var state = require('/tmp/ws2811.json'); | |
mode = state.mode; | |
color = state.color; | |
dmmessage = state.dmmessage; | |
} | |
catch (ex) { | |
} | |
var dmarray = new Uint32Array(dmmessage.length * 7 + 5); | |
var dmcolor = new Uint32Array(dmmessage.length * 7 + 5); | |
var colorcycle = 255; | |
function renderMessage() { | |
dmarray = new Uint32Array(dmmessage.length * 7 + 5); | |
dmcolor = new Uint32Array(dmmessage.length * 7 + 5); | |
for (var i = 0; i < dmmessage.length; i++) { | |
var fonttablebase = (dmmessage.charCodeAt(i) - 0x20) * 5; | |
for (var j = 0; j < 5; j++) { | |
dmarray[i*7+j] = font5x7[fonttablebase + j]; | |
dmcolor[i*7+j] = colorcycle; | |
} | |
if (colorcycle == 0xff0000) { | |
colorcycle = 255; | |
} else { | |
colorcycle = colorcycle << 8; | |
} | |
} | |
} | |
renderMessage(); | |
// Rainbow colours | |
rbcolor = []; | |
["red", "orange", "yellow", "green", "blue", "indigo", "violet"].forEach(function (c) { | |
var rgb = tinycolor(c).toRgb(); | |
rbcolor.push(rgb2Int(rgb.r, rgb.g, rgb.b)); | |
}); | |
ws281x.init(NUM_LEDS); | |
last_vals = [] | |
for (var i =0; i < 50; i++) { | |
last_vals.push(-33.0); | |
} | |
last_val_index = 0; | |
// ---- trap the SIGINT and reset before exit | |
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 "octoblu": | |
pixelData[i] = octoblu(i); | |
break; | |
case "concentric": | |
pixelData[i] = concentric(i, Math.floor(offset/10)%10); | |
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; | |
case "dotmatrix": | |
pixelData[i] = dotmatrix(i); | |
break; | |
case "xytest": | |
pixelData[i] = xytest(i); | |
break; | |
case "rainbow": | |
pixelData[i] = rainbow(i); | |
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) { | |
if (xy) { | |
pos = xy.xy[pos][1]; | |
} | |
else { | |
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 octoblu(pos) { | |
var segment = (pos % 50)/6.25; | |
if (segment < 7) { | |
return rgb2Int(0, 0, 255); | |
} | |
return rgb2Int(0, 255, 0); | |
} | |
function concentric(pos, step) { | |
if (step >= 5) step = 9 - step; | |
var ppos = Math.floor(pos/50); | |
if (ppos == step) return colorwheel((offset + pos) % 256); | |
return 0; | |
} | |
function xytest(pos) { | |
var phase = Math.floor(offset/200)%4; | |
switch (phase) { | |
case 0: | |
if (Math.abs((offset%200)/2 - xy.xy[pos][0]) < 5.0) { | |
return color; | |
} else { | |
return 0; | |
} | |
break; | |
case 1: | |
if (Math.abs((offset%200)/2 - xy.xy[pos][1]) < 5.0) { | |
return color; | |
} else { | |
return 0; | |
} | |
break; | |
case 2: | |
if (Math.abs(xy.xy[pos][0] + xy.xy[pos][1] - (offset%200)) < 10.0) { | |
return color; | |
} else { | |
return 0; | |
} | |
break; | |
case 3: | |
if (Math.abs(100 + xy.xy[pos][0] - xy.xy[pos][1] - (offset%200)) < 10.0) { | |
return color; | |
} else { | |
return 0; | |
} | |
break; | |
} | |
} | |
function rainbow(pos) { | |
var z = xy.xy[pos][0] + xy.xy[pos][1] - ((offset/3)%200); | |
if (z < 0) z += 200; | |
if (z < 28) { | |
return rbcolor[0]; | |
} | |
if (z < 57) { | |
return rbcolor[1]; | |
} | |
if (z < 86) { | |
return rbcolor[2]; | |
} | |
if (z < 114) { | |
return rbcolor[3]; | |
} | |
if (z < 143) { | |
return rbcolor[4]; | |
} | |
if (z < 171) { | |
return rbcolor[5]; | |
} | |
return rbcolor[6]; | |
} | |
function dotmatrix_x(x) { | |
if (x < 30.0) return 0; | |
if (x < 43.0) return 1; | |
if (x < 57.0) return 2; | |
if (x < 70.0) return 3; | |
return 4; | |
} | |
function dotmatrix_y(y) { | |
if (y < 25.0) return 8; | |
if (y < 40.0) return 0; | |
if (y < 50.0) return 1; | |
if (y < 60.0) return 2; | |
if (y < 70.0) return 3; | |
if (y < 80.0) return 4; | |
if (y < 90.0) return 5; | |
return 6; | |
} | |
function dotmatrix(pos) { | |
//var xdot = dotmatrix_x(xy.xy[pos][0]); | |
var x = xy.xy[pos][0]; | |
var ydot = dotmatrix_y(xy.xy[pos][1]); | |
//var column = dmarray[(offset/20 + xdot)%dmarray.length]; | |
var idx = Math.floor(((offset + x)/10)%dmarray.length); | |
var column = dmarray[idx]; | |
if ((1<<ydot)&column) { | |
return dmcolor[idx]; | |
} | |
return 0; | |
} | |
function rgb2Int(r, g, b) { | |
return ((g & 0xff) << 16) + ((r & 0xff) << 8) + (b & 0xff); | |
} | |
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; | |
} | |
var client = mqtt.connect(config_mqtt.URL, config_mqtt.PROTOCOL); | |
client.on('connect', function () { | |
console.log("Connected to MQTT"); | |
client.subscribe('IoTree/#'); | |
}); | |
client.on('message', function (topic, message) { | |
console.log("MQTT RX t=" + topic + " m=" + message.toString()); | |
switch (topic) { | |
case "IoTree/mode": | |
handle_message(message.toString(), null); | |
break; | |
case "IoTree/color": | |
handle_message("solid", message.toString()); | |
break; | |
case "IoTree/message": | |
dmmessage = message.toString(); | |
renderMessage(); | |
handle_message("dotmatrix", null); | |
break; | |
} | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment