thingzi-logic-twinkly
Version:
Twinkly lights control via node red
132 lines (110 loc) • 4.63 kB
JavaScript
module.exports = function(RED) {
'use strict';
const { Twinkly } = require("./lib/twinkly");
RED.nodes.registerType('thingzi-twinkly-set', function(config) {
RED.nodes.createNode(this, config);
const node = this;
if (!config.address) {
node.status({fill:'red', shape:'dot', text:'Address not set'});
return;
}
// Configuration
this.onMode = config.onMode || "movie";
this.debug = config.debug;
const twinkly = new Twinkly((msg, important) => {
if (node.debug) node.warn(msg);
if (important) node.status({fill:'red', shape:'dot', text: msg});
}, config.address);
// Render colors and intermediate colors
function renderColors(colors, steps, presets)
{
// Boundary checks
if (!colors || colors.length === 0)
return [[255,255,255,255]];
// Check / map / fix colors
for (var c = 0; c < colors.length; c++) {
let col = colors[c];
if (typeof col === 'string' && presets) {
col = presets[col];
}
if (col.length < 3 || col.length > 4) {
colors[c] = [0,0,0,0];
} else if (col.length === 3) {
colors[c] = [col[0],col[1],col[2],0];
}
}
// Render intermediate colors - linear for now
const stepFactor = 1 / steps;
let renderArray = [];
for (var c = 0; c < colors.length; c++) {
let c1 = colors[c];
let c2 = colors[(c+1) % colors.length];
for (var i = 0; i < steps; i++) {
let factor = stepFactor * i;
renderArray.push([
Math.round(c1[0] + factor * (c2[0] - c1[0])),
Math.round(c1[1] + factor * (c2[1] - c1[1])),
Math.round(c1[2] + factor * (c2[2] - c1[2])),
Math.round(c1[3] + factor * (c2[3] - c1[3]))
]);
}
}
return renderArray;
}
// handle incoming messages
this.on("input", function(msg, send, done) {
// Message properties (can be part of same message)
let power = msg.hasOwnProperty('payload') ? msg.payload.toString() : null;
let brightness = msg.hasOwnProperty('brightness') ? msg.brightness.toString() : null;
let mode = msg.hasOwnProperty('mode') ? msg.mode.toString() : null;
let color = msg.hasOwnProperty('color') ? msg.color : null;
var set = undefined;
// Set brightness
if (brightness) {
let bri = parseInt(brightness);
set = twinkly.setBrightness(bri);
}
// Set mode / power
if (mode) {
set = twinkly.ensureMode(mode);
} else if (power) {
let isOn = power.toLowerCase() === 'on';
set = twinkly.ensureMode(isOn ? node.onMode : 'off');
}
// Set color mode
if (color && color.colors && color.colors.length > 0) {
// Ensure delay is always valid
if (isNaN(color.delay)) {
color.delay = null;
}
// Check step count
if (isNaN(color.steps) || color.steps < 1) {
color.steps = 1;
}
// Render colours
let colors = renderColors(color.colors, color.steps, color.presets);
if (color.mode === 'blink') {
twinkly.setBlinkingColors(colors, color.delay);
} else if (color.mode === 'loop') {
twinkly.setLoopingColors(colors, color.delay);
} else { // solid
twinkly.setColors(colors);
}
}
// Update State
if (set) {
set
.then(() => twinkly.isOn())
.then(state => {
node.status({fill:'green', shape:'dot', text: `${state ? 'ON' : 'OFF'}`});
});
}
done && done();
});
// Get power state on init
twinkly.isOn()
.then(state => {
node.status({fill:'green', shape:'dot', text: `${state ? 'ON' : 'OFF'}`});
});
});
};