From fe545fc39da6a355dcc5def46bacb56fa39359c0 Mon Sep 17 00:00:00 2001 From: velvettear Date: Fri, 4 Mar 2022 00:02:07 +0100 Subject: [PATCH] added support for multiple blinksticks --- blinky.js | 2 +- config.json | 10 +++++ libs/cli.js | 2 +- libs/controller.js | 106 ++++++++++++++++++++++++++++++++------------- libs/parser.js | 9 ++++ libs/server.js | 13 +++--- 6 files changed, 105 insertions(+), 37 deletions(-) diff --git a/blinky.js b/blinky.js index fb9ae95..8df2513 100644 --- a/blinky.js +++ b/blinky.js @@ -26,7 +26,7 @@ async function main() { if (await cli.handleArguments()) { util.exit(); } - await controller.findBlinkstick(); + await controller.mapBlinkSticks(); logger.info(await server.start()); server.handleRequests(); } diff --git a/config.json b/config.json index 7b336b2..e551f84 100644 --- a/config.json +++ b/config.json @@ -5,6 +5,16 @@ }, "blinkstick": { "cache": true, + "map": [ + { + "id": "square", + "serial": "BS006537-3.0" + }, + { + "id": "strip", + "serial": "BS042165-3.0" + } + ], "serials": [ "BS006537-3.0" ] diff --git a/libs/cli.js b/libs/cli.js index 22de507..2dac6d3 100644 --- a/libs/cli.js +++ b/libs/cli.js @@ -11,7 +11,7 @@ async function handleArguments() { continue; case constants.ARG_LIST: case constants.ARG_LIST_SHORT: - logger.info('blinksticks: ' + JSON.stringify(await controller.findBlinkstick(constants.ALL, true))); + logger.info('blinksticks: ' + JSON.stringify(await controller.findBlinkstick('strip11', true))); handled++; break; } diff --git a/libs/controller.js b/libs/controller.js index 4086ff4..bdd693b 100644 --- a/libs/controller.js +++ b/libs/controller.js @@ -5,36 +5,81 @@ const blinkstick = require('blinkstick'); const LEDAnimations = new Map(); -let blinksticks; +let blinksticks = new Map(); -// find connected blinkstick(s) -async function findBlinkstick(index, ignoreFilter) { - if (!global.config.blinkstick?.cache || blinksticks === undefined) { - blinksticks = blinkstick.findAll(); - if (!ignoreFilter && global.config.blinkstick?.serials?.length > 0) { - blinksticks = blinksticks.filter((blinkstick) => { - return global.config.blinkstick.serials.includes(blinkstick.serial); - }); - if (blinksticks.length === 0) { - throw new Error('could not find any blinkstick matching the defined serial(s)'); +// get connected blinkstick by id (or return the first one found) +async function getBlinkstick(id, filter) { + if (!global.config.blinkstick?.cache || blinksticks.size === 0) { + mapBlinkSticks(filter); + } + if (id === undefined) { + return blinksticks.values().next().value; + } + if (id === constants.ALL) { + return Array.from(blinksticks.values()); + } + if (!blinksticks.has(id)) { + throw new Error('could not find any blinkstick matching the given id \'' + id + '\''); + } + return blinksticks.get(id); +} + +// map found blinksticks +function mapBlinkSticks(filter) { + const foundBlinksticks = blinkstick.findAll(); + if (filter === undefined) { + filter = global.config?.blinkstick?.map?.length > 0; + } + blinksticks = new Map(); + filter = filter && global.config.blinkstick?.map?.length > 0; + for (let blinkstickIndex = 0; blinkstickIndex < foundBlinksticks.length; blinkstickIndex++) { + const serial = foundBlinksticks[blinkstickIndex].serial; + if (!filter) { + blinksticks.set(serial, foundBlinksticks[blinkstickIndex]); + continue; + } + for (filterIndex = 0; filterIndex < global.config.blinkstick.map.length; filterIndex++) { + let tmp = global.config.blinkstick.map[filterIndex]; + if (tmp.serial !== serial) { + continue; } + blinksticks.set(tmp.id || serial, foundBlinksticks[blinkstickIndex]); + break; } } if (blinksticks.length === 0) { - throw new Error('could not find any blinkstick, make sure at least one blinkstick is connected'); + if (filter) { + throw new Error('could not find any blinkstick matching the given serial(s)'); + } else { + throw new Error('could not find any blinkstick, make sure at least one blinkstick is connected'); + } } - if (index === undefined) { - index = 0; - } else if (index !== constants.ALL) { - index = parseInt(index) || 0; +} + +// reset a blinkstick +async function resetBlinkstick(id) { + if (blinksticks === undefined || blinksticks.length === 0) { + return; } - if (index > blinksticks.length - 1) { - throw new Error('there is no blinkstick for index \'' + index + '\''); + let tmp; + if (id === constants.ALL) { + tmp = await getBlinkstick(id); + for (let index = 0; index < tmp.length; index++) { + if (tmp[index] === undefined) { + continue; + } + tmp[index].close(); + } + blinksticks.clear(); + } else { + tmp = await getBlinkstick(id); + if (tmp === undefined) { + return; + } + tmp.close(); + blinksticks.delete(id); } - if (index === constants.ALL) { - return blinksticks; - } - return blinksticks[index]; + mapBlinkSticks(); } // simple animation (set the color / morph to color) @@ -89,7 +134,7 @@ async function powerOff(config) { logger.info('led \'' + indexes[index] + '\' powered off'); } if (config.options.index === constants.ALL) { - const blinkstick = await findBlinkstick(); + const blinkstick = await getBlinkstick(); blinkstick.turnOff(); LEDAnimations.clear(); logger.info('blinkstick powered off'); @@ -100,7 +145,7 @@ async function powerOff(config) { // animations async function singleAnimation(config, index) { config.options.index = index; - const blinkstick = await findBlinkstick(); + const blinkstick = await getBlinkstick(config.blinkstick); return await new Promise((resolve, reject) => { logger.debug('changing color of led \'' + config.options.index + '\' to \'' + config.color + '\' (mode: ' + config.mode + ' | options: ' + JSON.stringify(config.options) + ')...'); setLEDAnimated(config.options.index); @@ -141,12 +186,13 @@ function getIndices(blinkstickConfig) { return [blinkstickConfig.options.index]; } -async function getColor(index) { - if (index === undefined) { - index = 0; +async function getColor(config) { + const index = 0; + if (!isNaN(config.options.index)) { + index = parseInt(config.options.index); } logger.debug('getting color for led with index \'' + index + '\''); - const blinkstick = await findBlinkstick(); + const blinkstick = await getBlinkstick(config.blinkstick); return await new Promise((resolve, reject) => { blinkstick.getColorString(index, (err, color) => { if (err) { @@ -162,7 +208,7 @@ async function setColorIfRandom(config) { if (config.options.index !== constants.ALL || config.color !== constants.RANDOM) { return; } - config.color = await getColor(0); + config.color = await getColor(config); } async function stopLEDsAccordingly(config) { @@ -278,7 +324,7 @@ function isInfiniteAnimation(config) { // exports module.exports = { - findBlinkstick, + mapBlinkSticks, simple, complex, powerOff, diff --git a/libs/parser.js b/libs/parser.js index 82f10f7..615c9ff 100644 --- a/libs/parser.js +++ b/libs/parser.js @@ -8,6 +8,7 @@ function parseRequest(requestBody, mode) { } let config = { 'id': Math.random(), + 'blinkstick': parseBlinkstick(requestBody.blinkstick), 'mode': mode, 'options': { 'index': parseIndex(requestBody.index), @@ -39,6 +40,14 @@ function parseRequest(requestBody, mode) { return config; } +// parse the blinkstick +function parseBlinkstick(blinkstick) { + if (blinkstick === undefined) { + return undefined; + } + return blinkstick; +} + // parse the index function parseIndex(index) { if (index === undefined) { diff --git a/libs/server.js b/libs/server.js index 99c8a17..2296356 100644 --- a/libs/server.js +++ b/libs/server.js @@ -12,7 +12,7 @@ const bodyparser = require('body-parser'); const app = express(); app.use(favicon(path.join(path.dirname(__dirname), 'public', 'favicon.ico'))); app.use(bodyparser.json()); -app.use(bodyparser.urlencoded({extended: true})); +app.use(bodyparser.urlencoded({ extended: true })); const html = require('./index.js').get(); @@ -67,15 +67,18 @@ async function handleSimpleAnimation(config, response) { try { response.end(JSON.stringify(await controller.simple(config))); } catch (err) { + if (err.message.includes('feature report')) { + await controller.resetBlinksticks(); + } logger.error(err); response.status(500); - response.end(JSON.stringify({status: 'error', error: err.message})); + response.end(JSON.stringify({ status: 'error', error: err.message })); } } async function handleComplexAnimation(config, response) { if (controller.isInfiniteAnimation(config)) { - response.end(JSON.stringify({status: 'ok', time: 'infinite'})); + response.end(JSON.stringify({ status: 'ok', time: 'infinite' })); response = undefined; } try { @@ -90,7 +93,7 @@ async function handleComplexAnimation(config, response) { } logger.error(err); response.status(500); - response.end(JSON.stringify({status: 'error', error: err.message})); + response.end(JSON.stringify({ status: 'error', error: err.message })); } } @@ -99,7 +102,7 @@ async function handlePowerOff(config, response) { response.end(JSON.stringify(await controller.powerOff(config))); } catch (err) { response.status(500); - response.end(JSON.stringify({status: 'error', error: err.message})); + response.end(JSON.stringify({ status: 'error', error: err.message })); } }