(raspberry-pi *only*) native bindings to control a strip of WS281x-LEDs with node.js
npm install @simontaga/rpi-ws281x-nativeNOTE: This will only ever work on the Raspberry Pi.
This module provides native bindings to the
rpi_ws281x library by Jeremy Garff
that is used to control strips of individually addressable LEDs directly
from a raspberry-pi. Supported are all LEDs of the NEOPIXEL/WS281x-family
(specifically WS2811, WS2812, WS2812b, SK6812, SK6812W in all variations).
this module is available via npm:
npm install @simontaga/rpi-ws281x-native
if you prefer installing from source:
npm install -g node-gyp
git clone --recursive https://github.com/Simontaga/node-rpi-ws281x-native.git
cd rpi-ws281x-native
npm install
You will need an up-to-date version of nodejs that supports at least some es6-features (>= 6.5).
If you are running on a RaspberryPi 1 or zero (running an ARMv61 processor),
you might need to download and install the nodejs-binaries manually.
Head over to https://nodejs.org/dist, find the version to install and download the -armv61-version.
See here for more information: https://raspberrypi.stackexchange.com/questions/48303/install-nodejs-for-all-raspberry-pi
This is the simplest example that will actually do something.
It will initialize the driver for 100 LEDs and set all LEDs to the
same, pinkish color:
``javascript
const ws281x = require('rpi-ws281x-native');
const channel = ws281x(100, { stripType: 'ws2812' });
const colorArray = channel.array;
for (let i = 0; i < channel.count; i++) {
colorsArray[i] = 0xffcc22;
}
ws281x.render();
`
For simple setups (i.e. those using just one channel), there is an easy
way for initialization using the top-level export function.
#### Example:
`javascript
const ws2821x = require('rpi-ws281x-native');
const options = {
dma: 10,
freq: 800000,
gpio: 18,
invert: false,
brightness: 255,
stripType: ws281x.stripType.WS2812
};
const channel = ws281x(20, options);
const colors = channel.array;
// update color-values
colors[42] = 0xffcc22;
ws281x.render();
`
This function takes two parameters, the number of LEDs (numLeds) and an options-object
which is entirely optional. These options combine the channel-options and
the global option from the init-function as described below.
The returned object is a channel object (also described below) that gives
access to the color-data.
Configures and initializes the drivers and returns an array of channel-interfaces.
#### Example:
`javascript
const ws2821x = require('rpi-ws281x-native');
const channels = ws281x.init({
dma: 10,
freq: 800000,
channels: [
{count: 20, gpio: 18, invert: false, brightness: 255, stripType: 'ws2812'},
{count: 20, gpio: 13, invert: false, brightness: 128, stripType: 'sk6812-rgbw'}
]
});
`
The only parameter options is an object with the following properties (unspecified properties will use the default-value):
- dma: number: the dma-number to use for the driver's data-transport to the LEDs (default: 10)
- freq: number: the frequency in Hz of the control-signal. This is 800kHz for ws2812/sk6812 LEDs and 400kHz for older ws2811 LEDs (default 800000).
- channels: Object[]: an array of one or two objects with channel-specific
configuration for the two possible outputs:
- count: number: the number of LEDs on this channel.gpio: number
- : the GPIO port-number the strip is connected to. (default: 18 for the first channel and 12 for the second channel)invert: boolean
- : whether the output-signal should be inverted (needed when a inverting level-shifter is used) (default: false)brightness: number
- : the brightness, applied to all LEDs on this channel. Value between 0 and 255 (default: 255).stripType: string|number
- : the LED-type connected on this channel. See ./lib/constants.js. Can be a string-constant or one of the values from ws281x.stripType (default ws281x.stripType.WS2812)
Send the current state of the channel color-buffers to the LEDs.
#### Example:
`javascript
const ws2821x = require('rpi-ws281x-native');
// initialize
const [channel] = ws281x.init(options);
// set some color-values
channel.array[12] = 0xff0000;
// render
ws281x.render();
`
Clear all color-values and render.
Shut down the drivers and free all resources.
Each of the channels is represented by a channel-object.
Channels do not contain any public methods – all interaction happens through the following properties:
- [readonly] count: number: number of LEDs on this channel[readonly] stripType: number
- : the numeric LED-type (see ws281x.stripType)[readonly] invert: boolean
- : if the signal for the LEDs is inverted[readonly] gpio: number
- : the GPIO port-number usedbrightness: number
- : the current brightness. Setting this property willrender()
have an effect with the very next -call.array: Uint32Array
- : the color-data, represented as a Uint32Array.0xwwrrggbb
Each index in this array represents the color-value of an LED in 32
bits (8 bit each for white, red, green, blue, counting from MSB to LSB).
So the numbers can be specified in hex using -format.buffer: Buffer
For RGB-LEDs (those without a seperate white-channel) the MSB is ignored.
- : A node-buffer, providing an alternative way to manipulate
the color-data. This is a view on the same array-buffer that is used by the
Uint32Array. When using the buffer, make sure to check for endianness to
prevent problems (I believe it is little endian on the raspebrry-pi).
connect the WS2812-strip to the raspberry-pi as described
here and run
the command sudo node examples/rainbow.js .
You should now see some rainbow-colors animation on the LED-strip.
As the native part of this module needs to directly interface with the physical
memory of the raspberry-pi (which is required in order to configure the PWM and
DMA-modules), it always has to run with root-privileges (there are probably ways
around this requirement, but that doesn't change the fact that the node-process
running the LEDs needs access to the raw physical memory – a thing you should
never allow to any user other than root).
If you are using this module as part of a program that should not be run with
elevated privileges, it would be a good idea to have the LED-driver running in
a seperate process. In such a case you could use the openpixel-control protocol
to send the pixel-data to the driver-process.
A stream-based node-implementation and some more information
can be found here.
There is a guide over at adafruit.com
on how to get the hardware up and running. I followed these instructions by
the word and had a working LED-strip.
Essentially, you need the Raspberry Pi, a logic-level converter and of
course a LED-Strip or other types of WS281x/SK6812-LEDs.
The logic-level shifter is required to shift the output-voltage of the
GPIO from 3.3V up to 5V. The adafruit-guide mentions
the 74AHCT125, but in fact most of the 74HCT-series chips or even a simple
transistor can be used for this.
To connect all that together, I'd recommend buying a small breadboard and some
jumper-wires. Also, consider buying a 5V power-supply that can deliver up to
60mA per LED (so you'll need up to 6A (30W) to fully power 100 LEDs).
For smaller applications, a good USB-charger should do the job just fine.
A short checklist of what you will need:
* Raspberry-PI and SD-Card
* 5V power-supply (Meanwell for instance builds really good ones)
* LED-Strip with WS2811/WS2812 Controllers (there are several other
controller-variations that are not supported)
* a breadboard and some jumper-wires (m/m as well as at least two f/m to
connect the GPIO-Pins)
* a 3.3V to 5V logic-level converter (74AHCT125 or 74HCT125N, others will
probably also work)
* more wire to connect the LED-strips
You can buy everything at adafruit.com,
sparkfun, on ebay or your favourite electronics
retailer (germany: check conrad electronic,
watterott or reichelt where
I bought most of my stuff). If you got more time than money to spend, I
recommend buying directly from chinese manufacturers (via aliexpress
for example). Shipping takes ages, but you end up paying only half as
much for the LEDs for example.
There is a conflict where the internal soundcard uses the same
GPIO / DMA / PWM functions that are needed to run the LED-drivers.
As far as I know you can not use both at the same time.
To disable audio, comment out the following line in config.txt contained on the boot partion.
#dtparam=audio=on
As @AdyiPool pointed out, that file seems to not exist in newer
raspbian-versions, Alternatively, you can create a file /etc/modprobe.d/blacklist-ws281x.conf with the following contents (effectively preventing sound-related modules to be loaded into the kernel):
``
blacklist snd_bcm2835
blacklist snd_pcm
blacklist snd_timer
blacklist snd_pcsp
blacklist snd
(after updating the file you need to run sudo update-initramfs -u` to
get the changes into the boot-partition or something like that)
If anyone finds a better solution please get in touch!