Last active
March 14, 2024 23:52
-
-
Save T-vK/31b966837a5741e84742a740e75a4908 to your computer and use it in GitHub Desktop.
Example showing how to use the WLED realtime UDP interface with Node.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dgram from 'dgram'; | |
class WledRealtimeClient { | |
constructor(wledControllerIp, numPixels, udpPort = 21324, maxPixelsPerPacket = 126) { | |
this.wledControllerIp = wledControllerIp; | |
this.numPixels = numPixels; | |
this.udpPort = udpPort; | |
this.maxPixelsPerPacket = maxPixelsPerPacket; | |
this.sock = dgram.createSocket('udp4'); | |
this.prevPixels = Buffer.alloc(3 * this.numPixels, 253); | |
this.pixels = Buffer.alloc(3 * this.numPixels, 1); | |
} | |
update() { | |
// Truncate values and cast to integer | |
for (let i = 0; i < this.pixels.length; i++) { | |
this.pixels[i] = Math.max(0, Math.min(255, this.pixels[i])); | |
} | |
const p = Buffer.from(this.pixels); | |
const idx = []; | |
for (let i = 0; i < p.length; i += 3) { | |
if (!this.areArraysEqual(p.slice(i, i + 3), this.prevPixels.slice(i, i + 3))) { | |
idx.push(i / 3); | |
} | |
} | |
const numPixels = idx.length; | |
const nPackets = Math.ceil(numPixels / this.maxPixelsPerPacket); | |
const idxSplit = []; | |
for (let i = 0; i < nPackets; i++) { | |
idxSplit.push(idx.slice(i * this.maxPixelsPerPacket, (i + 1) * this.maxPixelsPerPacket)); | |
} | |
const header = Buffer.from([1, 2]); // WARLS protocol header | |
for (const packetIndices of idxSplit) { | |
const data = Buffer.alloc(header.length + packetIndices.length * 4); | |
header.copy(data, 0); | |
let dataIndex = header.length; | |
for (const i of packetIndices) { | |
data.writeUInt8(i, dataIndex++); | |
p.copy(data, dataIndex, i * 3, i * 3 + 3); | |
dataIndex += 3; | |
} | |
this.sock.send(data, 0, data.length, this.udpPort, this.wledControllerIp); | |
} | |
this.prevPixels = Buffer.from(p); | |
} | |
areArraysEqual(arr1, arr2) { | |
if (arr1.length !== arr2.length) { | |
return false; | |
} | |
for (let i = 0; i < arr1.length; i++) { | |
if (arr1[i] !== arr2[i]) { | |
return false; | |
} | |
} | |
return true; | |
} | |
setLeds(pixels) { | |
for (let i = 0; i < pixels.length; i++) { | |
const pixel = pixels[i] | |
this.pixels[i * 3] = pixel[0]; // Red | |
this.pixels[i * 3 + 1] = pixel[1]; // Green | |
this.pixels[i * 3 + 2] = pixel[2]; // Blue | |
} | |
} | |
} | |
////////////////////////////////// LED blink test ////////////////////////////////// | |
const WLED_CONTROLLER_IP = '192.168.X.X'; | |
const NUM_PIXELS = 1; // Amount of LEDs on your strip | |
import { performance } from 'perf_hooks'; | |
const RED = [255,0,0]; | |
const OFF = [0,0,255]; | |
const wled = new WledRealtimeClient(WLED_CONTROLLER_IP, NUM_PIXELS); | |
console.log('Starting LED blink test'); | |
const leds = []; | |
while (true) { | |
leds[0] = RED; | |
wled.setLeds(leds); | |
wled.update(); | |
await new Promise(resolve => setTimeout(resolve, 100)); | |
leds[0] = OFF; | |
wled.setLeds(leds); | |
wled.update(); | |
await new Promise(resolve => setTimeout(resolve, 100)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment