Compare commits

..

No commits in common. "3d06477a0c494e8537f324c4fffdc42ed7c79291" and "20efca9234f8696be83e4941d398a3c6e8173c89" have entirely different histories.

12 changed files with 53 additions and 2239 deletions

5
.gitignore vendored
View file

@ -1,3 +1,6 @@
config.json
.vscode/
.idea/
node_modules/
package-lock.json
yarn.lock
npm-debug.log

28
.vscode/launch.json vendored
View file

@ -1,28 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"runtimeVersion": "8",
"request": "launch",
"name": "blinky",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/blinky.js"
},
{
"type": "node",
"runtimeVersion": "8",
"request": "launch",
"name": "blinky cli",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/blinky.js",
"args": [
"--get-blinksticks"
]
}
]
}

View file

@ -1,5 +1,4 @@
# MIT License
**Copyright (c) 2022 Daniel Sommer \<daniel.sommer@velvettear.de\>**
MIT License Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -12,9 +11,9 @@ The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -40,6 +40,8 @@ run:
`echo "KERNEL==\"hidraw*\", SUBSYSTEM==\"hidraw\", ATTRS{idVendor}==\"20a0\", ATTRS{idProduct}==\"41e5\", MODE=\"0666\"" | sudo tee /etc/udev/rules.d/85-blinkstick-hid.rules`
and reboot your system
## systemd
**for security reasons it is highly recommended to not run blinky with root permissions!**

View file

@ -26,7 +26,7 @@ async function main() {
if (await cli.handleArguments()) {
util.exit();
}
controller.mapBlinkSticks();
await controller.findBlinkstick();
logger.info(await server.start());
server.handleRequests();
}

View file

@ -5,16 +5,6 @@
},
"blinkstick": {
"cache": true,
"map": [
{
"id": "square",
"serial": "BS006537-3.0"
},
{
"id": "strip",
"serial": "BS042165-3.0"
}
],
"serials": [
"BS006537-3.0"
]
@ -25,10 +15,7 @@
},
"api": {
"get": {
"description": "show this page",
"endpoints": [
"/color"
]
"description": "show this page"
},
"post": {
"endpoints": [
@ -38,11 +25,6 @@
"/pulse",
"/poweroff"
],
"blinkstick": {
"available": "string values",
"default": "undefined",
"description": "specifies the blinkstick by the id given in the config.json file or by serial"
},
"color": {
"available": "random, hex color codes (#ffffff), rgb color codes (255, 255, 255)",
"default": "random",

View file

@ -11,7 +11,7 @@ async function handleArguments() {
continue;
case constants.ARG_LIST:
case constants.ARG_LIST_SHORT:
logger.info('blinksticks: ' + JSON.stringify(await controller.getBlinkstick(constants.ALL, false)));
logger.info('blinksticks: ' + JSON.stringify(await controller.findBlinkstick(constants.ALL, true)));
handled++;
break;
}

View file

@ -5,81 +5,36 @@ const blinkstick = require('blinkstick');
const LEDAnimations = new Map();
let blinksticks = new Map();
let blinksticks;
// 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;
// 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)');
}
}
if (blinksticks.size === 0) {
if (filter) {
throw new Error('could not find any blinkstick matching the given serial(s)');
} else {
}
if (blinksticks.length === 0) {
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;
if (index === constants.ALL) {
return blinksticks;
}
tmp[index].close();
}
blinksticks.clear();
} else {
tmp = await getBlinkstick(id);
if (tmp === undefined) {
return;
}
tmp.close();
blinksticks.delete(id);
}
mapBlinkSticks();
return blinksticks[index];
}
// simple animation (set the color / morph to color)
@ -124,16 +79,6 @@ async function complex(config) {
// power the blinkstick (or just a specific led) off
async function powerOff(config) {
config.timestamp = new Date().getTime();
if (config.blinkstick === constants.ALL) {
const promises = [];
const blinkstickNames = Array.from(blinksticks.keys());
for (let index = 0; index < blinkstickNames.length; index++) {
const tmp = JSON.parse(JSON.stringify(config));
tmp.blinkstick = blinkstickNames[index];
promises.push(powerOff(tmp));
}
return await Promise.allSettled(promises);
}
let indexes = getIndices(config);
if (config.options.index === constants.ALL) {
LEDAnimations.set(constants.ALL, { stop: new Date().getTime() });
@ -144,7 +89,7 @@ async function powerOff(config) {
logger.info('led \'' + indexes[index] + '\' powered off');
}
if (config.options.index === constants.ALL) {
const blinkstick = await getBlinkstick();
const blinkstick = await findBlinkstick();
blinkstick.turnOff();
LEDAnimations.clear();
logger.info('blinkstick powered off');
@ -155,7 +100,7 @@ async function powerOff(config) {
// animations
async function singleAnimation(config, index) {
config.options.index = index;
const blinkstick = await getBlinkstick(config.blinkstick);
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 + ' | options: ' + JSON.stringify(config.options) + ')...');
setLEDAnimated(config.options.index);
@ -196,47 +141,12 @@ function getIndices(blinkstickConfig) {
return [blinkstickConfig.options.index];
}
async function getColors(blinkstick, index) {
let blinksticksToCheck = [];
if (blinkstick === undefined) {
blinksticksToCheck = Array.from(blinksticks.keys());
} else {
blinksticksToCheck.push(blinkstick);
}
let indices = [0, 1, 2, 3, 4, 5, 6, 7];
if (index !== undefined && index !== constants.AL && !isNaN(index)) {
index = [index];
}
let results = [];
for (let blinkstickIndex = 0; blinkstickIndex < blinksticksToCheck.length; blinkstickIndex++) {
const tmpBlinkstick = blinksticksToCheck[blinkstickIndex];
let result = {
blinkstick: tmpBlinkstick,
leds: []
};
for (let ledIndex = 0; ledIndex < indices.length; ledIndex++) {
result.leds.push({
index: ledIndex,
color: await getColor({
blinkstick: tmpBlinkstick,
options: {
index: ledIndex
}
})
});
}
results.push(result);
}
return results;
}
async function getColor(config) {
let index = 0;
if (!isNaN(config.options.index)) {
index = parseInt(config.options.index);
async function getColor(index) {
if (index === undefined) {
index = 0;
}
logger.debug('getting color for led with index \'' + index + '\'');
const blinkstick = await getBlinkstick(config.blinkstick);
const blinkstick = await findBlinkstick();
return await new Promise((resolve, reject) => {
blinkstick.getColorString(index, (err, color) => {
if (err) {
@ -252,7 +162,7 @@ async function setColorIfRandom(config) {
if (config.options.index !== constants.ALL || config.color !== constants.RANDOM) {
return;
}
config.color = await getColor(config);
config.color = await getColor(0);
}
async function stopLEDsAccordingly(config) {
@ -368,11 +278,9 @@ function isInfiniteAnimation(config) {
// exports
module.exports = {
getBlinkstick,
mapBlinkSticks,
findBlinkstick,
simple,
complex,
powerOff,
isInfiniteAnimation,
getColors
isInfiniteAnimation
}

View file

@ -20,15 +20,9 @@ function get() {
'<div>' +
'<h2>get:</h2>' +
'<p>' + config.api.get.description + '</p>' +
'<h3>endpoints: </>';
for (let index = 0; index < config.api.get.endpoints.length; index++) {
if (index > 0) {
html += ', ';
}
html += config.api.get.endpoints[index];
}
'</div>';
html +=
'</div>' +
'<div>' +
'<h2>post:</h2>' +
'<h3>endpoints: </>';

View file

@ -8,7 +8,6 @@ function parseRequest(requestBody, mode) {
}
let config = {
'id': Math.random(),
'blinkstick': parseBlinkstick(requestBody.blinkstick),
'mode': mode,
'options': {
'index': parseIndex(requestBody.index),
@ -40,14 +39,6 @@ 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) {
@ -164,7 +155,5 @@ function parseHexColor(value) {
// exports
module.exports = {
parseRequest,
parseBlinkstick,
parseIndex
parseRequest
};

View file

@ -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();
@ -30,11 +30,6 @@ async function start() {
}
function handleRequests() {
// GET '/color'
app.get('/color', (request, response) => {
logger.http(request);
handleGETColor(request.body.blinkstick, request.body.index, response);
});
// GET html page
app.get('*', (request, response) => {
logger.http(request);
@ -68,36 +63,19 @@ function handleRequests() {
});
}
async function handleGETColor(blinkstick, index, response) {
try {
let result = await controller.getColors(blinkstick, index);
response.end(JSON.stringify(result));
} catch (err) {
if (response === undefined) {
return;
}
logger.error(err);
response.status(500);
response.end(JSON.stringify({ status: 'error', error: err.message }));
}
}
async function handleSimpleAnimation(config, response) {
try {
response.end(JSON.stringify(await controller.simple(config)));
} catch (err) {
if (response === undefined) {
return;
}
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 {
@ -112,19 +90,16 @@ 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}));
}
}
async function handlePowerOff(config, response) {
try {
if (config.blinkstick === undefined) {
config.blinkstick = constants.ALL;
}
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}));
}
}

2010
package-lock.json generated

File diff suppressed because it is too large Load diff