An open replacement for DX Light, the Windows app for Robobloq / "QuikLight" USB LED strip controllers (the kind sold as monitor or desk backlights). It runs in Edge or Chrome, talks to the controller directly over USB serial, and does everything DX Light does: static colors, effects, music and screen sync. It adds more effects, PC-audio music and a proper LED layout editor.
DX Light works, but it's a heavy Electron app with cloud and telemetry bits, a clunky UI, and its music mode only listens to the controller's own microphone. The goal was to get rid of it:
- Find out how DX Light talks to the controller.
- Build a cleaner app that controls the strip the same way. This repo.
- Next: write a SignalRGB plugin so the strip syncs with the rest of the RGB setup.
- Install Node.js (only used for a tiny local web server).
- Double-click
app/Start OpenDX.bat. It closes DX Light (which locks the COM port), starts the server onhttp://localhost:8642and opens the app in an Edge window. - Click Connect and pick the controller. It reconnects automatically after that.
- Use ⏻ to turn the strip on or off, then pick a mode.
To stop it, close the app window and the minimized "OpenDX server" window. To keep DX Light from coming back, disable it in Task Manager > Startup apps.
Full details, with byte layouts, are in DX-Light-protocol.md.
- How it was found: DX Light is an Electron app. Its
resources/app.asarwas unpacked (npx @electron/asar extract), and.webpack/main/index.jswas beautified and read. The protocol lives there in plain JavaScript. The extracted code isn't part of this repo (.gitignoreblocks it). - Device: USB
1A86:FE0C(WCH chip), a plain USB CDC serial port, 115200 baud 8N1. No driver needed, no HID, no encryption. - Frames:
RBcommand frames ('R' 'B' len seq action payload checksum), plus anSCframe for fast per-LED updates on firmware > 1.0.2. The checksum is the sum of all bytes & 0xFF. - Colors: 5-byte groups
[startLed, R, G, B, endLed], 1-based and inclusive, where254means "to the end". A run of same-colored LEDs can be one group. - Test device: firmware 1.1.2, 63 LEDs, reported by the controller itself (
readDeviceInfo). - Hardware limits: USB only, no Wi-Fi or Bluetooth. Its 3 buttons don't send anything to the PC. The controller's built-in music uses its onboard mic. On a wall charger it just runs its built-in effects.
- Open questions: the maximum frame rate (fast streaming once froze an animation), the full
list of built-in effect indexes, and whether the "PC audio levels → controller" command (
0x98) works on this model.
Everything is in one file, app/index.html, with no build step
and no dependencies. serve.js only serves it on 127.0.0.1, because
Web Serial needs a secure origin.
| Part | Where (search for) | Notes |
|---|---|---|
| Settings | DEFAULTS, save() |
Saved in the browser's localStorage (key ledctl), not on the controller |
| Protocol | rbFrame, scFrame, toGroups, ACT |
Byte-for-byte checked against frames the device accepted |
| Device I/O | connect, FILTER |
Reads device info on connect, sets the LED count, picks SC or RB transport by firmware |
| Effects | EFFECTS |
17 effects, rendered in JS and streamed to the strip |
| Music | startMusicSource, MUSIC |
Sources: PC audio (screen share + system audio), mic, controller mic, PC audio → controller (experimental) |
| Screen sync | startScreen, layoutLeds, renderScreen, autoLayout |
Captures at 128×72 and averages an edge region per LED. Layout = LEDs per side + start corner + direction |
| Output | tick, finalize |
A Worker timer drives the loop, so it keeps running when minimized. Applies brightness, color order and reverse, then skips unchanged frames (1 s keep-alive) |
| Hardware tab | setMode("hardware"), ACT.setLedEffect |
Raw access to the controller's built-in effects |
- Done: protocol decoded and verified, app with all DX Light modes plus extras, launcher.
- Needs testing on the strip: effect smoothness and max FPS, color order, screen-sync layout, Hardware tab effects, and the experimental PC audio → controller music.
- Next: the SignalRGB plugin. It's a serial device
1A86:FE0C: on connect, readreadDeviceInfofor the LED count, then send oneSCframe per frame usingtoGroupsrange compression. Use the same frame rate that works in the app. - Idea: for Wi-Fi, standalone use and native SignalRGB/WLED support, the strip itself (probably WS2812B) could be wired to a WLED board instead of this controller.
DX-Light-protocol.md full protocol reference
app/
index.html the whole app
serve.js local static server (127.0.0.1:8642)
Start OpenDX.bat launcher
Not affiliated with Robobloq. The protocol was worked out for interoperability with hardware I own.