How OpenLogi Implements RGB Lighting Control for Logitech Keyboards

OpenLogi implements RGB lighting control for Logitech keyboards through the HID++ 2.0 protocol, utilizing the Per-Key Lighting feature (ID 0x8081) and RGB Effects feature (ID 0x8080) to provide an async, open-source alternative to Logitech Options+.

OpenLogi is a Rust-based open-source implementation that reverse-engineers Logitech's proprietary communication protocols to unlock hardware capabilities on Linux and other platforms. By leveraging HID++ 2.0 feature indices, the project enables precise per-key RGB customization without relying on vendor-specific drivers or closed-source software stacks.

HID++ 2.0 Protocol Foundation

OpenLogi communicates with Logitech keyboards using the HID++ 2.0 protocol, a proprietary extension of standard HID used across modern Logitech peripherals. The RGB lighting implementation relies on two distinct feature IDs:

  • Per-Key Lighting (0x8081) – Controls individual key illumination and zone-based coloring
  • RGB Effects (0x8080) – Manages device-wide power states and global lighting effect clusters

These feature IDs are discovered during device enumeration through the HID++ registry, allowing OpenLogi to determine whether connected hardware supports advanced RGB capabilities before attempting configuration.

Architecture Overview

The implementation spans three layered crates that separate protocol specifics from user-facing APIs.

openlogi-hidpp: Low-Level Protocol Implementation

The core HID++ definitions reside in crates/openlogi-hidpp/src/feature/per_key_lighting.rs. The PerKeyLightingFeature struct implements the complete per-key API, exposing methods such as:

  • set_individual_rgb_zones() – Sets unique colors for specific keys
  • set_consecutive_rgb_zones() – Optimizes batch updates for adjacent keys
  • set_rgb_zones_single_value() – Applies a uniform color to multiple zones
  • frame_end() – Commits changes to the device controller

For device-wide management, crates/openlogi-hidpp/src/feature/rgb_effects.rs provides power-mode handling via get_rgb_power_mode() and set_rgb_power_mode(), along with cluster-effect configuration for global lighting presets.

openlogi-device: High-Level Abstraction

The Device struct in crates/openlogi-device/src/write/lighting.rs translates ergonomic Rust calls into HID++ feature invocations. Methods like Device::set_rgb_zones_single_value() wrap the low-level protocol details, handling endpoint management and error propagation while presenting a clean async interface to upper layers.

openlogi-cli: Command-Line Interface

Quick diagnostics and testing are available through crates/openlogi-cli/src/cmd/diag/lighting.rs. The diag lighting subcommand parses hexadecimal color strings (e.g., RRGGBB) and forwards them through the device layer, enabling rapid hardware validation without writing code.

Implementation Workflow

OpenLogi executes RGB updates through a five-stage async pipeline:

  1. Feature Discovery – The agent queries the HID++ registry to locate keyboards advertising support for feature ID 0x8081.

  2. Endpoint Binding – PerKeyLightingFeature::new(endpoint) instantiates a feature-specific endpoint tied to the discovered device.

  3. Payload Construction – Helper functions like individual_zones_args() and single_value_args() serialize RGB data into the 16-byte HID++ payload format required by the protocol specification.

  4. Async Transmission – The feature calls endpoint.call_long() (or call() for short commands) to transmit the HID++ packet over the underlying HID transport managed by openlogi-hid.

  5. Frame Commit – frame_end() finalizes the update buffer, with optional EEPROM persistence controlled via the FramePersistence enum (volatile for temporary effects, non-volatile for permanent configuration changes).

Code Examples

Setting Per-Key Colors Programmatically

The following Rust example demonstrates setting a solid cyan color on the first 13 keys using the direct HID++ feature API:

use openlogi_hidpp::feature::per_key_lighting::{PerKeyLightingFeature, Rgb, FramePersistence};
use openlogi_hidpp::protocol::v20::Hidpp20Error;

// `endpoint` is a `FeatureEndpoint` obtained from the device registry.
let per_key = PerKeyLightingFeature { endpoint };

// Define the target color (bright cyan).
let colour = Rgb { red: 0x00, green: 0xFF, blue: 0xFF };

// Specify zone IDs (key indices). Only the first 13 zones are processed per call.
let zones = &[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];

// Apply the color to the specified zones.
per_key
    .set_rgb_zones_single_value(colour, zones)
    .await
    .expect("Failed to set per-key RGB");

// Commit the frame (volatile update, not persisted across reboots).
per_key
    .frame_end(FramePersistence::Volatile, 0, 0)
    .await
    .expect("Failed to commit RGB frame");

CLI Diagnostics

For quick hardware testing without compiling Rust code, use the CLI to set the entire keyboard to red:


# Set keyboard to pure red (FF0000)

openlogi diag lighting ff0000

The CLI parses the hexadecimal string, constructs an Rgb struct, and invokes the same set_rgb_zones_single_value() path used by the desktop application.

Summary

  • OpenLogi uses HID++ 2.0 feature ID 0x8081 (Per-Key Lighting) for granular RGB control and 0x8080 (RGB Effects) for global power modes
  • The codebase follows a three-layer architecture: openlogi-hidpp for protocol implementation, openlogi-device for high-level device management, and openlogi-cli for command-line operations
  • Key source files include crates/openlogi-hidpp/src/feature/per_key_lighting.rs for low-level features and crates/openlogi-device/src/write/lighting.rs for the public API
  • Updates are transmitted asynchronously via endpoint.call_long() and committed using frame_end() with optional EEPROM persistence
  • Both programmatic Rust APIs and CLI tools support setting individual keys or uniform colors across zones

Frequently Asked Questions

What protocol does OpenLogi use for RGB control?

OpenLogi uses the HID++ 2.0 protocol, specifically targeting feature ID 0x8081 for per-key lighting and 0x8080 for RGB effects. This is the same underlying protocol used by Logitech's official software, reverse-engineered to work across platforms without proprietary drivers.

How many keys can be updated simultaneously in a single call?

The set_rgb_zones_single_value() method supports up to 13 zones per invocation. For updates exceeding this limit, OpenLogi batches commands or uses set_consecutive_rgb_zones() for optimized adjacent-key updates, automatically handling the protocol's payload size constraints.

Is the RGB lighting persistent across reboots?

Persistence depends on the FramePersistence parameter passed to frame_end(). Use FramePersistence::Volatile for temporary effects that reset on power cycle, or specify non-volatile persistence flags to write the configuration to the keyboard's EEPROM for permanent storage.

Which Logitech devices support per-key RGB through OpenLogi?

Device support depends on whether the keyboard advertises the Per-Key Lighting feature (0x8081) in its HID++ registry. Modern Logitech gaming keyboards such as the G Pro series, G915, and G715 typically expose this feature, while office-focused keyboards may only support basic RGB Effects (0x8080) for power modes rather than per-key customization.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →