| Crates.io | openrgb2 |
| lib.rs | openrgb2 |
| version | 0.3.0 |
| created_at | 2025-07-11 20:22:28.176633+00 |
| updated_at | 2025-08-31 08:18:46.836804+00 |
| description | OpenRGB SDK client, successor to openrgb |
| homepage | https://github.com/Achtuur/openrgb-rs2 |
| repository | https://github.com/Achtuur/openrgb-rs2 |
| max_upload_size | |
| id | 1748413 |
| size | 229,164 |
Rust client library for the OpenRGB SDK.
OpenRGB is an RGB Lighting control app that doesn't depend on manufacturer software.
See documentation and examples.
use openrgb2::{OpenRgbClient, OpenRgbResult};
#[tokio::main]
async fn main() -> OpenRgbResult<()> {
// connect to local server
let client = OpenRgbClient::connect().await?;
let controllers = client.get_all_controllers().await?;
for c in controllers {
println!("controller {}: {:#?}", c.id(), c.name());
// the LEDs should now be a rainbow
c.init().await?;
}
Ok(())
}
The OpenRGB SDK provides a few ways to write colors to devices: per led, per zone, or all leds (set_leds). From my testing it seemed that when updating large number of LEDs, set_leds is the fastest one. It's inconvenient to update in this way, as some controllers have multiple unrelated zones, such as motherboards, meaninig you have to keep track of the zone offset.
To ease this, the crate has a Command API, which translates arbitrary LED updates to a single all_leds update, ensuring both user friendliness and maximum performance. The entire API is sync, with only one asynchronous api call at the end.
use openrgb2::{OpenRgbClient, OpenRgbResult, Color};
#[tokio::main]
async fn main() -> OpenRgbResult<()> {
// connect to local server
let client = OpenRgbClient::connect().await?;
// get a controller
let controllers = client.get_all_controllers().await?;
let controller = controllers
.iter()
.next()
.expect("Must have at least one controller");
controller.init().await?;
let mut cmd = controller.cmd();
// Set all LEDs to red
cmd.set_leds(vec![Color::new(255, 0, 0); controller.num_leds()])?;
// First half of first zone to green
cmd.set_zone_leds(
0,
vec![Color::new(0, 255, 0); controller.get_zone(0)?.num_leds() / 2],
)?;
// First led to blue
cmd.set_led(0, Color::new(0, 0, 255))?;
// This is now equivalent to a single `controller.set_leds(...)` command
cmd.execute().await?;
Ok(())
}
My case contains a few controllers that I would like to control in sync, like my RAM sticks and case fans. To make it easier to update those, the Command API also supports ControllerGroups.
use openrgb2::{Color, OpenRgbClient, OpenRgbResult};
const RAINBOW_COLORS: [Color; 7] = [
Color::new(255, 0, 0), // Red
Color::new(255, 127, 0), // Orange
Color::new(255, 255, 0), // Yellow
Color::new(0, 255, 0), // Green
Color::new(0, 0, 255), // Blue
Color::new(85, 0, 180), // Indigo
Color::new(148, 0, 211), // Violet
];
#[tokio::main]
async fn main() -> OpenRgbResult<()> {
// connect to local server
let client = OpenRgbClient::connect().await?;
let group = client.get_all_controllers().await?;
group.init().await?;
// sets each separate device to a color of the rainbow
let mut cmd_group = group.cmd();
for (idx, c) in group.iter().enumerate() {
let color = RAINBOW_COLORS[idx % RAINBOW_COLORS.len()];
cmd_group.set_controller_leds(c, vec![color; c.num_leds()])?;
}
// executes a `set_leds` for every controller
cmd_group.execute().await?;
Ok(())
}
Syncing controller data with the data in OpenRGB requires an additional API call, which could be unnecessary in a lot of cases. Most of the (important) data will not change over a Controllers lifetime and usually you just want to write colors as fast as possible. Therefore, I chose to make syncing the controller data a separate method (Controller::sync_controller_data) instead of being automatically called after any request.
openrgb-rsThis repository is a clone of the repo previously maintaed by nicoulaj. I have attempted to reach out to them, but received no response. As a result I decided to republish the OpenRGB SDK under a new name (openrgb-rs2).
Support for OpenRGB protocol versions 4 and 5 is added. There's also now a friendlier to use API than before.
Internally there's some changes in how serializing/deserializing the protocol is done. I decided it was easier to read/write to a buffer, rather than directly to a stream as was previously done. For the end user there should not be much visible change though. I have not done any benchmarking, so I'm not sure about the performance. I can update my entire rig at about 300 FPS at release mode, so I'm not too worried about performance anyway.