blinky/libs/blinkstick.js

230 lines
7.3 KiB
JavaScript
Raw Normal View History

2021-04-06 16:41:49 +02:00
// requirements
const logger = require('./logger');
const config = require('../config.json');
2021-04-06 16:41:49 +02:00
// third party requirements
const blinkstick = require('blinkstick');
const hexcolor = require('hex-color-regex');
// constants
2022-02-21 11:56:49 +01:00
const RANDOM = 'random';
2021-04-06 16:41:49 +02:00
const ANIMATION_STATE_INPROGRESS = 1;
const ANIMATION_STATE_FINISH = 0;
2022-02-21 11:56:49 +01:00
// letiables
2021-04-06 16:41:49 +02:00
let led;
let animation = {};
function findBlinkstick() {
2022-02-21 00:48:29 +01:00
return new Promise((resolve, reject) => {
2021-04-06 16:41:49 +02:00
led = blinkstick.findFirst();
if (led !== undefined && led !== null) {
return resolve(led);
}
2022-02-21 00:48:29 +01:00
return reject('could not find any blinkstick');
2021-04-06 16:41:49 +02:00
});
}
// turn the blinkstick off
function powerOff() {
2022-02-21 00:48:29 +01:00
return new Promise((resolve, reject) => {
findBlinkstick()
.then((led) => {
led.stop();
led.turnOff();
logger.info('blinkstick powered off');
resolve();
})
.catch(reject);
})
2021-04-06 16:41:49 +02:00
}
// parse a color object from given request arguments
function parseColor(value) {
2021-04-07 12:08:30 +02:00
if (!value || value == RANDOM) {
return RANDOM;
}
let parsedColor = parseRGBColor(value);
if (!parsedColor) {
parsedColor = parseHexColor(value);
}
return parsedColor || function () {
2022-02-21 00:48:29 +01:00
logger.warn('could not parse color value \'' + value + '\', defaulting to \'' + config.api.post.color.default + '\'');
return config.api.post.color.default;
}();
2021-04-06 16:41:49 +02:00
}
// parse rgb color values
function parseRGBColor(value) {
2022-02-21 11:56:49 +01:00
if (value.indexOf(',') === -1 && isRGBValue(value)) {
return convertRGBToHex(parseInt(value) || 0, 0, 0);
2021-04-06 16:41:49 +02:00
} else {
2022-02-21 00:48:29 +01:00
const splittedValues = value.split(',');
let color = {};
2021-04-06 16:41:49 +02:00
for (let index = 0; index < splittedValues.length; index++) {
const value = splittedValues[index];
2022-02-21 11:56:49 +01:00
if (index === 0) {
color.red = parseInt(value) || 0;
2021-04-06 16:41:49 +02:00
} else if (index === 1) {
color.green = parseInt(value) || 0;
2021-04-06 16:41:49 +02:00
} else if (index === 2) {
color.blue = parseInt(value) || 0;
2021-04-06 16:41:49 +02:00
}
}
if (isRGBValue(color.red) && isRGBValue(color.green) && isRGBValue(color.blue)) {
return convertRGBToHex(color.red, color.green, color.blue);
2021-04-06 16:41:49 +02:00
}
}
}
// check a single rgb value
function isRGBValue(value) {
2022-02-21 11:56:49 +01:00
return value !== undefined && !isNaN(value) && value >= 0 && value <= 255;
}
// convert rgb to hex color values
function convertRGBToHex(red, green, blue) {
2022-02-21 00:48:29 +01:00
return '#' + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1);
2021-04-06 16:41:49 +02:00
}
// parse hex color values
function parseHexColor(value) {
2022-02-21 11:56:49 +01:00
if (value[0] !== '#') {
value = '#' + value;
2021-04-06 16:41:49 +02:00
}
if (value.length === 4) {
value = (value[0] + value[1] + value[1] + value[2] + value[2] + value[3] + value[3]);
2021-04-06 16:41:49 +02:00
}
if (hexcolor({ strict: true }).test(value)) {
return value;
2021-04-06 16:41:49 +02:00
}
}
// pass the options to the blinkstick accordingly
function illuminate(blinkstickConfig) {
return new Promise(function (resolve, reject) {
findBlinkstick()
.then(function () {
switch (blinkstickConfig.mode) {
2022-02-21 00:48:29 +01:00
case 'morph':
morph(blinkstickConfig, resolve, reject);
break;
2022-02-21 00:48:29 +01:00
case 'pulse':
startPulsing(blinkstickConfig, resolve, reject);
break;
default:
setColor(blinkstickConfig, resolve, reject);
break;
}
})
2021-04-06 16:41:49 +02:00
.catch(reject);
});
}
// set a static color
function setColor(blinkstickConfig, resolve, reject) {
2021-04-06 16:41:49 +02:00
stopAnimation()
.then(function () {
setAnimationProperties(blinkstickConfig);
2022-02-21 00:48:29 +01:00
logger.debug('setting color to \'' + blinkstickConfig.color + '\'...');
led.setColor(blinkstickConfig.color, blinkstickConfig.options, function (err) {
2021-04-06 16:41:49 +02:00
clearAnimationProperties();
if (err) {
2022-02-21 00:48:29 +01:00
return reject('error setting color \'' + blinkstickConfig.color + '\' (' + err + ')');
2021-04-06 16:41:49 +02:00
}
2022-02-21 00:48:29 +01:00
return resolve('set color to \'' + blinkstickConfig.color + '\'');
2021-04-06 16:41:49 +02:00
});
});
}
// morph to a color
function morph(blinkstickConfig, resolve, reject) {
2021-04-06 16:41:49 +02:00
stopAnimation()
.then(function () {
setAnimationProperties(blinkstickConfig);
2022-02-21 00:48:29 +01:00
logger.debug('morphing color to \'' + blinkstickConfig.color + '\'...');
led.morph(blinkstickConfig.color, blinkstickConfig.options, function (err) {
2021-04-06 16:41:49 +02:00
clearAnimationProperties();
if (err) {
2022-02-21 00:48:29 +01:00
return reject('error morphing color to \'' + blinkstickConfig.color + '\' (' + err + ')');
2021-04-06 16:41:49 +02:00
}
2022-02-21 00:48:29 +01:00
return resolve('morphed color to \'' + blinkstickConfig.color + '\'');
2021-04-06 16:41:49 +02:00
});
});
}
// start pulsing
function startPulsing(blinkstickConfig, resolve, reject) {
2022-02-21 11:56:49 +01:00
if (animation.state === ANIMATION_STATE_FINISH || (blinkstickConfig.options.pulse.max > 0 && (blinkstickConfig.options.pulse.done && blinkstickConfig.options.pulse.done === blinkstickConfig.options.pulse.max))) {
2021-04-06 16:41:49 +02:00
clearAnimationProperties();
2022-02-21 00:48:29 +01:00
return resolve('finished pulsing color \'' + blinkstickConfig.color + '\'');
2021-04-06 16:41:49 +02:00
}
2022-02-21 11:56:49 +01:00
if (animation.id && animation.id !== blinkstickConfig.id) {
2021-04-06 16:41:49 +02:00
stopAnimation()
.then(logger.info)
.then(function () {
startPulsing(blinkstickConfig, resolve, reject)
2021-04-06 16:41:49 +02:00
})
.catch(logger.error);
return;
}
setAnimationProperties(blinkstickConfig);
led.pulse(blinkstickConfig.color, blinkstickConfig.options, function (err) {
2021-04-06 16:41:49 +02:00
if (err) {
clearAnimationProperties();
2022-02-21 00:48:29 +01:00
return reject('error pulsing color \'' + blinkstickConfig.color + '\' (' + err + ')');
2021-04-06 16:41:49 +02:00
}
blinkstickConfig.options.pulse.done++;
2022-02-21 00:48:29 +01:00
logger.debug('pulsed color \'' + blinkstickConfig.color + '\' ' + blinkstickConfig.options.pulse.done + '/' + blinkstickConfig.options.pulse.max + ' times');
startPulsing(blinkstickConfig, resolve, reject);
2021-04-06 16:41:49 +02:00
});
}
// set properties for the current animation
function setAnimationProperties(blinkstickConfig) {
2022-02-21 11:56:49 +01:00
if (animation.id === blinkstickConfig.id) {
2021-04-06 16:41:49 +02:00
return;
}
led.animationsEnabled = true;
animation.id = blinkstickConfig.id;
2022-02-21 00:48:29 +01:00
animation.state = ANIMATION_STATE_INPROGRESS;
2021-04-06 16:41:49 +02:00
}
// clear properties for the current animation
function clearAnimationProperties() {
led.stop();
animation = {};
}
// stop the current animation
function stopAnimation() {
return new Promise(function (resolve, reject) {
if (!isAnimationInProgress()) {
return resolve();
}
animation.state = ANIMATION_STATE_FINISH;
waitForAnimation(Date.now(), resolve, reject);
});
}
// wait for current animation
function waitForAnimation(timestamp, resolve, reject) {
if (!isAnimationInProgress()) {
return resolve();
}
setTimeout(function () {
waitForAnimation(timestamp, resolve, reject);
}, 100);
}
// is currently an animation in progress
function isAnimationInProgress() {
2022-02-21 11:56:49 +01:00
return animation !== undefined && animation.state !== undefined;
2021-04-06 16:41:49 +02:00
}
// exports
module.exports = {
parseColor,
illuminate,
powerOff
};