UNPKG

piixel

Version:

Control WS281X / NeoPixel LEDs from a Raspberry Pi using Node.js and TypeScript

143 lines (141 loc) 5.53 kB
import getBindings from "bindings"; import ansiEscapes from "ansi-escapes"; import chalk from "chalk"; function colorwheel(pos) { pos = pos - Math.floor(pos / 256) * 256; let shift1, shift2; pos < 85 ? (shift1 = 8, shift2 = 16) : pos < 170 ? (pos -= 85, shift1 = 0, shift2 = 8) : (pos -= 170, shift1 = 16, shift2 = 0); let p = Math.floor(pos * 3); return p = p < 256 ? p : 255, p << shift1 | 255 - p << shift2; } function rgb2hex(r, g, b) { return r << 16 | g << 8 | b; } function brighten(color, amount) { amount = amount === 0 ? 0 : amount; const [r, g, b] = color; return [ Math.max(0, Math.min(255, r - Math.round(255 * -amount))), Math.max(0, Math.min(255, g - Math.round(255 * -amount))), Math.max(0, Math.min(255, b - Math.round(255 * -amount))) ]; } class MockBindings { #options; #pixels = new Uint32Array(0); #brightness = 1; #layout; // todo: add support circular layout constructor(layout = { h: 1 }) { this.#layout = layout, layout.h !== -1 && process.stdout.write(ansiEscapes.cursorHide); } configure(options) { this.#options = options; } render() { const height = this.#layout.h; if (height === -1) return; const width = this.#layout.w ?? Math.ceil(this.#pixels.length / this.#layout.h), pixels = new Array(height).fill(0).map( (_, row) => new Array(width).fill(0).map((_2, col) => { const pixel = this.#pixels[row * width + col], r = pixel >> 16 & 255, g = pixel >> 8 & 255, b = pixel & 255; return chalk.bgRgb(...brighten([r, g, b], 1 - this.#brightness))( " " ); }).join("") ).join(` `); process.stdout.write( ansiEscapes.cursorLeft + ansiEscapes.eraseLines(height) + pixels ); } reset() { process.stdout.write(ansiEscapes.cursorShow); } setPixels(pixels) { this.#pixels = pixels; } setBrightness(brightness) { this.#brightness = brightness; } } function createMockBindings(layout) { return new MockBindings(layout); } function parseMockEnv(env) { const [h, w] = env.split("x").map(Number); return isNaN(h) ? { h: 1 } : { h, w }; } function tryGetBindings() { try { return getBindings("addon"); } catch (error) { if (error instanceof Error) { if ("code" in error && error.code === "ERR_DLOPEN_FAILED") { if (process.env.MOCK_PIIXEL) return createMockBindings(parseMockEnv(process.env.MOCK_PIIXEL)); error.message = `WS281x native bindings could not be loaded. Set MOCK_PIIXEL=true to render pixels to terminal. Original error: ${error.message}`; } "tries" in error && Array.isArray(error.tries) && (error.message = `!!This package is only works on a Raspberry PI!! ${error.message}`); } throw error; } } const bindings = tryGetBindings(); var StripType = /* @__PURE__ */ ((StripType2) => (StripType2[StripType2.SK6812_STRIP_RGBW = 403703808] = "SK6812_STRIP_RGBW", StripType2[StripType2.SK6812_STRIP_RBGW = 403701768] = "SK6812_STRIP_RBGW", StripType2[StripType2.SK6812_STRIP_GRBW = 403181568] = "SK6812_STRIP_GRBW", StripType2[StripType2.SK6812_STRIP_GBRW = 403177488] = "SK6812_STRIP_GBRW", StripType2[StripType2.SK6812_STRIP_BRGW = 402657288] = "SK6812_STRIP_BRGW", StripType2[StripType2.SK6812_STRIP_BGRW = 402655248] = "SK6812_STRIP_BGRW", StripType2[StripType2.WS2811_STRIP_RGB = 1050624] = "WS2811_STRIP_RGB", StripType2[StripType2.WS2811_STRIP_RBG = 1048584] = "WS2811_STRIP_RBG", StripType2[StripType2.WS2811_STRIP_GRB = 528384] = "WS2811_STRIP_GRB", StripType2[StripType2.WS2811_STRIP_GBR = 524304] = "WS2811_STRIP_GBR", StripType2[StripType2.WS2811_STRIP_BRG = 4104] = "WS2811_STRIP_BRG", StripType2[StripType2.WS2811_STRIP_BGR = 2064] = "WS2811_STRIP_BGR", StripType2[ StripType2.WS2812_STRIP = 528384 /* WS2811_STRIP_GRB */ ] = "WS2812_STRIP", StripType2[ StripType2.SK6812_STRIP = 528384 /* WS2811_STRIP_GRB */ ] = "SK6812_STRIP", StripType2[ StripType2.SK6812W_STRIP = 403181568 /* SK6812_STRIP_GRBW */ ] = "SK6812W_STRIP", StripType2))(StripType || {}); class Ws281xImpl { #leds = void 0; #resetOnExit = !1; constructor() { process.once("exit", () => { this.#resetOnExit && this.clear(); }); } configure({ resetOnExit, ...options }) { if (this.#leds !== void 0) throw new Error( "ws281x is already configured. Call ws281x.reset() first!" ); this.#resetOnExit = resetOnExit ?? !1, this.#leds = options.leds, bindings.configure(options); } reset() { this.#leds !== void 0 && (this.clear(), bindings.reset()), this.#leds = void 0; } clear() { this.#leds !== void 0 && this.render(new Uint32Array(this.#leds)); } render(pixelsOrOpts) { pixelsOrOpts instanceof Uint32Array ? this.#render({ pixels: pixelsOrOpts }) : this.#render(pixelsOrOpts); } #render(options) { if (this.#leds === void 0) throw new Error("Must call configure() before render()"); const { pixels, brightness } = options, ops = []; if (typeof pixels < "u") { if (pixels.length !== this.#leds) throw new Error( `Size of pixels array must match number of LEDs (expected: ${this.#leds}, got: ${pixels.length})` ); ops.push(() => bindings.setPixels(pixels)); } brightness !== void 0 && ops.push(() => bindings.setBrightness(brightness)), ops.length !== 0 && (ops.forEach((op) => op()), bindings.render()); } } const ws281x = new Ws281xImpl(); export { StripType, colorwheel, rgb2hex, ws281x }; //# sourceMappingURL=index.js.map