hid-rgb-ctl
Linux command-line tool for controlling RGB lighting via standard HID protocols.
[!NOTE] This project was built with vibe coding. Contributions via vibe coding are welcome — don't worry too much about code style, just make it work.
Supported Protocols
-
HID LampArray (Usage Page 0x59) — Modern Dynamic Lighting standard from the USB HID Usage Tables v1.4 (Section 26). Supports device interrogation, per-lamp attributes, autonomous/manual mode, and color updates.
-
HID LED Page RGB (Usage Page 0x08, Usage 0x52) — Legacy RGB LED control per HID Usage Tables Section 11.7. Simpler protocol with direct R/B/G channel writes.
Features
- Auto-discovers devices by parsing HID report descriptors — no hardcoded vendor/product IDs
- Supports preset colors, decimal RGB, hex color codes, and intensity control
- Per-lamp color control via
set-lampon LampArray devices (LampMultiUpdateReport with automatic batching) - Query and toggle autonomous/manual mode on LampArray devices
- Automatic value scaling to device-declared LogicalMaximum (e.g. LED Intensity 0-100 per spec)
- Supports both Feature and Output HID report types (auto-detected from descriptor)
- Minimal dependencies — only
lexopt(CLI parsing) andlibc(ioctl)
Install
# or from git
# or from local clone
Usage
# List detected devices
# Show device attributes and lamp info
# Set color by preset name
# Set color by RGB values (0-255)
# Set color by hex code
# Set color with custom intensity
# Turn off
# Set per-lamp colors (LampArray only)
# Per-lamp with custom intensity
# Specify device path (when multiple devices present)
# Query autonomous mode (LampArray only)
# Set autonomous mode
Color presets: red, green, blue, white, cyan, yellow, orange,
purple, pink, off
Permissions
HID device access requires read/write permission on /dev/hidrawN.
Add a udev rule for your device, for example:
# /etc/udev/rules.d/99-hid-rgb.rules
# ASUS Vivobook keyboard (0B05:5570)
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0b05", ATTRS{idProduct}=="5570", TAG+="uaccess"
Then reload:
&&
Verified Devices
| Device | Bus | VID:PID | Protocol | Lamps | Status |
|---|---|---|---|---|---|
| ASUS Vivobook S 16 (M5606WA) keyboard | I2C | 0B05:5570 | LampArray | 1 (single-zone) | Verified |
Contributions welcome — please open an issue or PR with your device info.
Protocol Notes
LampArray (Usage Page 0x59)
The typical operation flow (Section 26.6):
- Read
LampArrayAttributesReport— get lamp count, device kind - Read
LampAttributesResponseReportfor each lamp — get position, RGB level counts, programmability - Disable
AutonomousMode— take control from device firmware - Send
LampRangeUpdateReportorLampMultiUpdateReportwith color data - Re-enable
AutonomousModewhen done (optional)
LampCount (Usage 0x03) tells you how many independently controllable zones
the device has. A single-zone keyboard has LampCount=1; a per-key RGB
keyboard may have 100+.
Two update reports are supported:
LampRangeUpdateReport(Usage 0x60) — applies a single color to a contiguous range of lamps. Used by thesetcommand to set all lamps at once.LampMultiUpdateReport(Usage 0x50) — updates individual lamps with independent colors. Used by theset-lampcommand. Colors are automatically batched based on the device's slot count (derived from report size), with intermediate batches settingLampUpdateComplete=0and the final batch settingLampUpdateComplete=1so the device applies all updates atomically.
LED Page RGB (Usage Page 0x08, Section 11.7)
Simpler protocol — the RGB LED collection (Usage 0x52) directly contains:
- Red LED Channel (Usage 0x53)
- Blue LED Channel (Usage 0x54) — note: Blue before Green in the spec
- Green LED Channel (Usage 0x55)
- LED Intensity (Usage 0x56, optional)
No autonomous mode or lamp enumeration. Both Feature and Output report types are supported (auto-detected from the descriptor). Color and intensity values are automatically scaled to the device's declared LogicalMaximum (the spec recommends logical max 100 for LED Intensity).
MinUpdateInterval
LampArray devices report a MinUpdateIntervalInMicroseconds (visible via
hid-rgb-ctl get). When performing rapid sequential updates (e.g. animation
loops), callers should wait at least this long between updates. The spec
requires the host to not send more than one LampUpdateComplete per interval.
Since each CLI invocation is a separate process, this cannot be enforced
automatically — scripts should add appropriate delays between calls.
Examples
See examples/ for scripts that use hid-rgb-ctl for lighting
effects, including rainbow.sh (smooth rainbow gradient loop). When writing
animation loops, respect the device's MinUpdateIntervalInMicroseconds
(see MinUpdateInterval above).
Library Usage
This crate can also be used as a Rust library:
use ;
let devices = discover_devices;
for dev in &devices
Add to your Cargo.toml:
[]
= { = "https://github.com/xz-dev/hid-rgb-ctl.git" }
References
- USB HID Usage Tables v1.4 — Section 26 (Lighting and Illumination), Section 11.7 (Multicolor RGB LED)
- Microsoft Dynamic Lighting — Windows implementation guide for the same HID LampArray standard
License
MIT