From 2c17326f96804dbcb5fdb9b3b8e5e763a1e5995c Mon Sep 17 00:00:00 2001 From: velvettear Date: Mon, 28 Feb 2022 01:53:13 +0100 Subject: [PATCH] fixed a lot of problems --- blinky.js | 24 +----- libs/blinkstick.js | 189 ++++++++++++++++++++++----------------------- libs/util.js | 27 ++++++- 3 files changed, 121 insertions(+), 119 deletions(-) diff --git a/blinky.js b/blinky.js index 7fe6d59..bbf4032 100644 --- a/blinky.js +++ b/blinky.js @@ -16,7 +16,7 @@ handleInterrupts(); // start the application main() - .catch(exit); + .catch(util.exit); async function main() { await setGlobalConfig(); @@ -44,25 +44,7 @@ async function setGlobalConfig() { function handleInterrupts() { for (let index = 0; index < INTERRUPTS.length; index++) { process.once(INTERRUPTS[index], (code) => { - exit(null, code); + util.exit(undefined, code); }); } -} - -function exit(err, code) { - if (code === undefined) { - code = 0; - if (err !== undefined) { - code = 1; - } - } - if (err) { - logger.error(err); - logger.error(global.appName + ' ' + global.appVersion + ' ended due to an error'); - } else { - logger.info(global.appName + ' ' + global.appVersion + ' shutting down gracefully') - } - process.exit(code); -} - - +} \ No newline at end of file diff --git a/libs/blinkstick.js b/libs/blinkstick.js index 9110243..127a9ef 100644 --- a/libs/blinkstick.js +++ b/libs/blinkstick.js @@ -1,4 +1,5 @@ -const logger = require('./logger'); +const logger = require('./logger.js'); +const util = require('./util.js'); const blinkstick = require('blinkstick'); const ALL = 'all'; @@ -9,8 +10,7 @@ const MODE_BLINK = 'blink'; const MODE_PULSE = 'pulse'; const MODE_POWEROFF = 'poweroff'; -const LEDS_ANIMATED = []; -const LEDS_STOP = []; +const LEDAnimations = new Map(); let blinksticks; @@ -49,13 +49,12 @@ async function findBlinkstick(index, ignoreFilter) { // simple animation (set the color / morph to color) async function simple(config) { - await stopLedsAccordingly(config); + await stopLEDsAccordingly(config); config.timestamp = new Date().getTime(); let indices = getIndices(config); for (let index = 0; index < indices.length; index++) { - setLedAnimated(indices[index]); - await singleAnimation(JSON.parse(JSON.stringify(config)), indices[index]); - clearLedState(indices[index]); + const tmpConfig = JSON.parse(JSON.stringify(config)); + await singleAnimation(tmpConfig, indices[index]); } return { status: 'ok', @@ -68,38 +67,38 @@ async function simple(config) { // complex animation (pulse / blink) async function complex(config) { if (config.timestamp === undefined) { - await stopLedsAccordingly(config); + await stopLEDsAccordingly(config); config.timestamp = new Date().getTime(); } let indices = getIndices(config); for (let index = 0; index < indices.length; index++) { - if (shouldLedFinish(config)) { - clearLedState(indices[index]); + if (shouldLEDFinish(config)) { + clearLedState(config.options.index); return { status: 'ok', time: (new Date().getTime() - config.timestamp) + 'ms' }; } - setLedAnimated(indices[index]); - await singleAnimation(JSON.parse(JSON.stringify(config)), indices[index]); - if (config.options.index === ALL) { - clearLedState(indices[index]); - } + const tmpConfig = JSON.parse(JSON.stringify(config)); + await singleAnimation(tmpConfig, indices[index]); config.repetitions.done++; } - return complex(config); + return await complex(config); } // power the blinkstick (or just a specific led) off async function powerOff(config) { config.timestamp = new Date().getTime(); let indices = getIndices(config); - await forceStop(config.options.index); + if (config.options.index === ALL) { + LEDAnimations.set(ALL, { stop: new Date().getTime() }); + } for (let index = 0; index < indices.length; index++) { + await stopLEDAnimation(indices[index]); await singleAnimation(JSON.parse(JSON.stringify(config)), indices[index]); logger.info('led \'' + indices[index] + '\' powered off'); } if (config.options.index === ALL) { const blinkstick = await findBlinkstick(); - blinkstick.stop(); blinkstick.turnOff(); + LEDAnimations.clear(); logger.info('blinkstick powered off'); } return { status: 'ok', indices: indices, time: (new Date().getTime() - config.timestamp) + 'ms' }; @@ -110,7 +109,9 @@ async function singleAnimation(config, index) { config.options.index = index; const blinkstick = await findBlinkstick(); return await new Promise((resolve, reject) => { - logger.debug('changing color of led \'' + config.options.index + '\' to \'' + config.color + '\' (mode: ' + config.mode + ')...'); + logger.debug('changing color of led \'' + config.options.index + '\' to \'' + config.color + '\' (mode: ' + config.mode + ' | options: ' + JSON.stringify(config.options) + ')...'); + setLEDAnimated(config.options.index); + blinkstick.animationsEnabled = true; switch (config.mode) { case MODE_MORPH: blinkstick.morph(config.color, config.options, callback); @@ -127,6 +128,9 @@ async function singleAnimation(config, index) { } function callback(err) { + if (config.mode !== MODE_BLINK && config.mode !== MODE_PULSE) { + clearLedState(config.options.index); + } if (err) { reject(new Error('changing color of led \'' + config.options.index + '\' to \'' + config.color + '\' encountered an error > ' + err)); } @@ -136,47 +140,6 @@ async function singleAnimation(config, index) { }); } -async function stopLedsAccordingly(config) { - if (config.options.index === ALL) { - logger.debug('stopping all leds...'); - return await powerOff({ - id: Math.random(), - mode: MODE_POWEROFF, - color: '#000000', - options: { index: ALL } - }); - } - return stopLedAnimation(config.options.index); -} - -async function forceStop(index) { - if (index === ALL) { - LEDS_STOP.push(ALL); - return await new Promise((resolve, reject) => { - waitForAllAnimationsEnd(() => { - resolve(); - }); - }); - } - setLedStopping(index); - return await new Promise((resolve, reject) => { - waitForAnimationEnd(index, () => { - resolve(); - }); - }); -} - -function shouldLedFinish(config) { - if (isLedStopping(config.options.index)) { - logger.debug('led \'' + config.options.index + '\' is set to \'stop\' and should finish now'); - return true; - } - if (config.mode === MODE_BLINK || config.mode === MODE_PULSE) { - return config.repetitions.max !== 0 && config.repetitions.done >= config.repetitions.max; - } - return false; -} - // led / index helper functions function getIndices(blinkstickConfig) { if (blinkstickConfig.options.index === ALL) { @@ -185,74 +148,108 @@ function getIndices(blinkstickConfig) { return [blinkstickConfig.options.index]; } -function setLedAnimated(index) { - if (isLedAnimated(index)) { +async function stopLEDsAccordingly(config) { + if (LEDAnimations.size === 0) { return; } - LEDS_ANIMATED.push(index); + if (config.options.index === ALL) { + logger.debug('stopping all leds...'); + return await powerOff({ + id: Math.random(), + mode: MODE_POWEROFF, + color: '#000000', + options: { index: ALL } + }); + } + return stopLEDAnimation(config.options.index); +} + +function shouldLEDFinish(config) { + if (LEDAnimations.has(ALL) || (isLEDAnimated(config.options.index) && isLEDStopping(config.options.index))) { + logger.debug('led \'' + config.options.index + '\' is set to \'stop\' and should finish now'); + return true; + } + if (config.mode === MODE_BLINK || config.mode === MODE_PULSE) { + return config.repetitions.max !== 0 && config.repetitions.done >= config.repetitions.max; + } + return false; +} + +function setLEDAnimated(index) { + if (isLEDAnimated(index)) { + return; + } + LEDAnimations.set(index, { start: new Date().getTime() }); logger.debug('led \'' + index + '\ set to \'animated\''); } -function setLedStopping(index) { - if (!isLedAnimated(index) || isLedStopping(index)) { +function setLEDStopping(index) { + if (!isLEDAnimated(index) || isLEDStopping(index)) { return; } - LEDS_STOP.push(index); + if (LEDAnimations.has(index)) { + LEDAnimations.get(index).stop = new Date().getTime(); + } logger.debug('led \'' + index + '\ set to \'stop\''); } function clearLedState(index) { if (index === ALL) { - LEDS_ANIMATED.length = 0; + LEDAnimations.clear(); logger.debug('cleared animation state of all leds'); return; } - LEDS_ANIMATED.splice(LEDS_ANIMATED.indexOf(index), 1); + LEDAnimations.delete(index); logger.debug('cleared animation state of led \'' + index + '\''); } -function isLedAnimated(index) { - return LEDS_ANIMATED.includes(index); +function isLEDAnimated(index) { + return LEDAnimations.has(index); } -function isLedStopping(index) { - if (LEDS_STOP.includes(ALL)) { +function isLEDStopping(index) { + if (LEDAnimations.has(ALL) && LEDAnimations.get(ALL).stop !== undefined) { return true; } - return LEDS_STOP.includes(index); + if (LEDAnimations.has(index) && LEDAnimations.get(index).stop !== undefined) { + return true; + } + return false; } -function stopLedAnimation(index) { - setLedStopping(index); - return new Promise((resolve, reject) => { - waitForAnimationEnd(index, () => { - resolve(); - }); - }); +async function stopLEDAnimation(index) { + if (index === ALL) { + for (const [key, value] of LEDAnimations) { + setLEDStopping(key); + } + await waitForAllAnimationsEnd(); + return; + } + setLEDStopping(index); + await waitForAnimationEnd(index); } -function waitForAnimationEnd(index, callback) { +async function waitForAnimationEnd(index, timestamp) { logger.debug('waiting for animated led \'' + index + '\' to end...'); - if (!isLedAnimated(index)) { + if (!isLEDAnimated(index)) { logger.debug('animation of led \'' + index + '\' should have ended now'); - LEDS_STOP.splice(LEDS_STOP.indexOf(index), 1); - return callback(); + return; } - setTimeout(() => { - waitForAnimationEnd(index, callback); - }, 100); + if (timestamp === undefined) { + timestamp = new Date().getTime(); + } + await util.sleep(100); + return await waitForAnimationEnd(index, timestamp); } -function waitForAllAnimationsEnd(callback) { - logger.debug('waiting for all animations to end...'); - if (LEDS_ANIMATED.length === 0) { - logger.debug('all animations should have ended now'); - LEDS_STOP.length = 0; - return callback(); +async function waitForAllAnimationsEnd(callback, timestamp) { + if (LEDAnimations.size === 0) { + return; + } + logger.debug('waiting for all animations to end...'); + for (const [key, value] of LEDAnimations) { + await waitForAnimationEnd(key); } - setTimeout(() => { - waitForAllAnimationsEnd(callback); - }, 100); } function isInfiniteAnimation(config) { diff --git a/libs/util.js b/libs/util.js index dd53fce..dd2817f 100644 --- a/libs/util.js +++ b/libs/util.js @@ -1,6 +1,23 @@ +const logger = require('./logger.js'); const realpath = require('fs').realpath; const stat = require('fs').stat; +function exit(err, code) { + if (code === undefined) { + code = 0; + if (err !== undefined) { + code = 1; + } + } + if (err) { + logger.error(err); + logger.error(global.appName + ' ' + global.appVersion + ' ended due to an error'); + } else { + logger.info(global.appName + ' ' + global.appVersion + ' shutting down gracefully') + } + process.exit(code); +} + async function fileExists(file) { if (file === undefined) { throw new Error('can not check the existence of an undefined file'); @@ -11,7 +28,7 @@ async function fileExists(file) { if (err) { reject(err); } - resolve({path, stats}); + resolve({ path, stats }); }) }); } @@ -30,7 +47,13 @@ async function resolvePath(file) { }); } +async function sleep(milliseconds) { + return new Promise(resolve => setTimeout(resolve, milliseconds)); +} + module.exports = { + exit, fileExists, - resolvePath + resolvePath, + sleep }; \ No newline at end of file