This is a fork of Blinkstick library, but now in TypeScript with Promises.
BlinkStick Node provides an interface to control Blinkstick devices connected to your computer with Node.js.
What is BlinkStick? It's a smart USB-controlled LED device. More info about it here:
- TypeScript
- All methods taking callbacks now return Promises
- Most animation methods allow
AbortSignal
(this is only partially supported, your mileage may vary) - Many methods return results of setting a feature report on device instead of
undefined
] - Requires Node.js 20.0 or higher
- Added support for arbitrary animations
- Removed lots of low-level or unnecessary methods
- Added subclasses
BlinkStickSync
andBlinkStickAsync
for sync and async APIs and future specialization- Likely future specialization will be
BlinkStickProSync
andBlinkStickProAsync
, as the Pro device seems to have lots of unusual features
- Likely future specialization will be
BREAKING CHANGES:
- Restored original return types of several methods
- No
string
when dealing with low-level data - useBuffer
instead, we assume that you know what you are doing
If you want to gift or buy me a BlinkStick device for testing purposes, please email me.
Tested:
- BlinkStick Nano
Should work:
- BlinkStick
- BlinkStick Strip
- Blinkstick Strip Mini
*Variable LED count
BlinkStick Flex and BlinkStick Pro come with a variable number of LEDs.
This library probably can work with them, but you need to set the number of LEDs in the constructor before using any method.
blinkstick.ledCount = 42;
If you don't set the number of LEDs, the library will assume that you have one LED.
- Node.js, version 20.0 or higher
- Libusb for Mac OSX and Linux
Install libudev
and libusb
development packages:
sudo apt-get install libusb-1.0-0-dev libudev-dev -y
Install using npm:
npm install @ginden/blinkstick-v2
Using async APIs is the recommended way. While even sync APIs use Promises, they may block the event loop, which is not a good practice.
Read docs of node-hid
for more
information.
import { BlinkStick, findFirstAsync } from '@ginden/blinkstick-v2';
const blinkstick = await findFirstAsync();
If you are using Async API, you might accidentally let Blinkstick
instance to be garbage-collected. This will emit a
warning, because Blinkstick
instance holds reference to C API object. To avoid it, just call close
or
use explicit resource management.
Direct construction of BlinkStick
is not recommended.
import { BlinkStick, findFirst } from '@ginden/blinkstick-v2';
const blinkstick = findFirst();
// Color names are allowed
await blinkstick.pulse('red');
// "random" is also allowed
await blinkstick.pulse('random');
// RGB values are allowed
await blinkstick.pulse(100, 0, 0);
// RGB values as hex string are allowed
await blinkstick.pulse('#ff0000');
// RGB values as hex string are allowed
await blinkstick.pulse('ff0000');
// Well, even rgb(255, 0, 0) is allowed
await blinkstick.pulse('rgb(255, 0, 0)');
await blinkstick.setColor('red');
// Will work only if you have at least 2 LEDs
await blinkstick.led(0).setColor('green');
await blinkstick.led(1).setColor('blue');
// Set color of all LEDs
await blinkstick.leds().setColor('yellow');
Currently, both APIs are identical in functionality and API. The only difference is that async API uses internally HIDAsync
from node-hid
library, while sync API uses HID
.
Let's start with an example:
import { findFirst, Animation } from '@ginden/blinkstick-v2';
import { animationApi } from './animation-api';
const blinkstick = findFirst();
const animation = Animation.repeat(
Animation.morphMany(['blue', 'purple', 'red', 'yellow', 'green', 'cyan'], 5000),
12,
);
blinkstick.animation.runAndForget(animation);
Animation
class is a simple convenience wrapper for several common animations and generates AnimationDescription
objects.
What is AnimationDescription
? It's an iterable object that contains all the frames of the animation.
export type AnimationDescription =
| Iterable<SimpleFrame | ComplexFrame>
| AsyncIterable<SimpleFrame | ComplexFrame>;
SimpleFrame
is a class of {rgb: RgbTuple, duration: number}
. It's used by animation runner to change color of all LEDs at once.
ComplexFrame
is a class of {leds: RgbTuple[], duration: number}
. It's used by animation runner to change color of each LED separately. Number of LEDs must match the number of LEDs in the device.
- Dreaded
could not get feature report from device
- this error occurs somewhere in thenode-hid
library and its dependencies, and is most likely to occur when calling methods in tight loops. See node-hid/node-hid#561
If you get an error message on Linux:
Error: cannot open device with path /dev/hidraw0
Please run the following command:
echo "KERNEL==\"hidraw*\", SUBSYSTEM==\"hidraw\", ATTRS{idVendor}==\"20a0\", ATTRS{idProduct}==\"41e5\", MODE=\"0666\"" | sudo tee /etc/udev/rules.d/85-blinkstick-hid.rules
Then either restart the computer or run the following command to reload udev rules:
sudo udevadm control --reload-rules && sudo udevadm trigger
Open pull requests, you are welcome.
To run tests, you need to have Blinkstick device connected to your computer. This makes it impossible to run tests on CI, and even typical automated testing is rather challenging.
Run npm run test:manual
and follow the instructions. You should physically see the device changing colors, and you
will answer yes/no to the questions.
Just run npm test
and it will run the tests. You can also run npm test -- --watch
to run the tests in watch mode.
- Michał Wadas - https://github.com/Ginden
- Arvydas Juskevicius - http://twitter.com/arvydev
- Paul Cuthbertson - http://twitter.com/paulcuth
Copyright (c) 2014 Agile Innovative Ltd and contributors
Released under MIT license.