How OpenLogi Controls RGB Keyboard Static Effects Using the HID++ Protocol

OpenLogi controls static RGB keyboard lighting by leveraging the Logitech HID++ Backlight feature (ID 0x1982), writing the BacklightEffect::Static discriminant value 0 to the device's non-volatile memory via the set_backlight_config method.

The OpenLogi open-source project provides a Rust-based implementation for managing Logitech HID++ devices, enabling precise control over keyboard illumination. By interfacing directly with the HID++ protocol's backlight feature, the codebase allows developers to set persistent static color effects or apply temporary lighting changes in RAM. This article examines the specific mechanisms OpenLogi uses to configure static RGB effects, referencing the actual implementation in the AprilNEA/OpenLogi repository.

Understanding the HID++ Backlight Feature

OpenLogi implements the Logitech HID++ Backlight feature (ID 0x1982, version 3) to drive keyboard lighting operations. The BacklightFeature struct, defined in crates/openlogi-hidpp/src/feature/backlight.rs, implements the FeatureEndpoint trait to handle HID++ communication. This feature registration occurs in the feature registry at crates/openlogi-hidpp/src/feature/registry.rs, where the backlight capability is mapped to its protocol identifier.

Enumerating Available Effects

Before setting a static effect, OpenLogi checks device capabilities through the BacklightEffectList bitfield. The "static" effect corresponds to the STATIC flag, defined as 1 << 0 within the supported effects list.

According to the source code in crates/openlogi-hidpp/src/feature/backlight.rs (lines 63-66), the effect enumeration allows the host to determine whether the target device supports static illumination before attempting to configure it.

Persisting Static Effects with set_backlight_config

To permanently store a static RGB configuration in the keyboard's non-volatile memory, OpenLogi uses the BacklightFeature::set_backlight_config method. This function accepts a SetBacklightConfig struct, which contains an Option<BacklightEffect> field named effect.

When configuring static lighting, the code passes Some(BacklightEffect::Static), which writes the literal value 0 (the discriminant of BacklightEffect::Static) into the request payload. As defined in lines 78-80 of backlight.rs, the SetBacklightConfig struct encodes this value into a 16-byte argument array, placing the effect byte at index 2.

If the caller passes None for the effect field, OpenLogi uses the sentinel value 0xff (EFFECT_UNCHANGED) to instruct the device to retain its current effect setting. The payload construction logic appears in lines 101-104 of crates/openlogi-hidpp/src/feature/backlight.rs.

Applying Transient Effects with set_backlight_effect

For temporary, RAM-only changes that do not persist after power cycling, OpenLogi provides BacklightFeature::set_backlight_effect. This method sends the desired BacklightEffect value directly via HID++ sub-command 3, allowing for rapid effect previews without altering stored configuration.

The transient setter implementation resides in lines 132-135 of crates/openlogi-hidpp/src/feature/backlight.rs, offering a lightweight alternative to the persistent configuration pathway.

High-Level Device Integration

The HID++ protocol details are abstracted by the higher-level device layer in crates/openlogi-device/src/write/backlight.rs. This module opens the backlight feature, retrieves the current configuration, updates the effect field to Static, and invokes set_backlight_config to apply changes. This architecture separates UI concerns from low-level HID++ communication, ensuring that application code interacts with a clean, type-safe API while the library handles byte-level protocol compliance.

Practical Implementation Examples

The following examples demonstrate how to configure static RGB effects using the OpenLogi API.

To persistently set the static color effect on a keyboard:

// Acquire device instance and open backlight feature
let device = /* acquire openlogi-device instance */ ;
let backlight = openlogi_hidpp::feature::BacklightFeature::open(&mut device).await?;

// Read current config and modify effect to Static
let mut cfg = backlight.get_backlight_config().await?;
cfg.effect = Some(openlogi_hidpp::feature::BacklightEffect::Static);

// Write to non-volatile memory
backlight.set_backlight_config(cfg).await?;

To apply a temporary static effect (RAM only):

// Open backlight feature
let backlight = openlogi_hidpp::feature::BacklightFeature::open(&mut device).await?;

// Send transient command without persisting
backlight.set_backlight_effect(openlogi_hidpp::feature::BacklightEffect::Static).await?;

Summary

  • OpenLogi uses HID++ feature ID 0x1982 (Backlight feature, version 3) to control RGB lighting according to the Logitech protocol specification.
  • The static effect is represented by the STATIC flag (1 << 0) in the BacklightEffectList bitfield and discriminant value 0 in the BacklightEffect enum.
  • Persistent configuration uses set_backlight_config, writing the effect value to byte index 2 of a 16-byte payload sent via call_long(1, …).
  • The SetBacklightConfig struct uses 0xff (EFFECT_UNCHANGED) as a sentinel value when preserving the current effect is desired.
  • Transient effects use set_backlight_effect via HID++ sub-command 3 for RAM-only changes that disappear after device reset.
  • Core implementation resides in crates/openlogi-hidpp/src/feature/backlight.rs, with high-level abstractions in crates/openlogi-device/src/write/backlight.rs.

Frequently Asked Questions

What HID++ feature ID controls keyboard backlighting in OpenLogi?

OpenLogi implements feature ID 0x1982, version 3, which corresponds to the Logitech HID++ Backlight feature. This ID is registered in crates/openlogi-hidpp/src/feature/registry.rs and enables the BacklightFeature struct to communicate lighting commands to compatible keyboards.

What value represents the static effect in the HID++ protocol?

The static effect is represented by the discriminant value 0 within the BacklightEffect enumeration. When OpenLogi constructs a SetBacklightConfig payload, it places this value at byte index 2 of the 16-byte argument array to instruct the device to display a static solid color.

How does OpenLogi distinguish between persistent and temporary RGB effects?

OpenLogi provides two distinct methods: set_backlight_config writes to non-volatile memory for permanent changes, while set_backlight_effect uses HID++ sub-command 3 for temporary, RAM-only modifications. The persistent method requires constructing a full SetBacklightConfig struct, whereas the transient method accepts only the effect enum directly.

Where is the backlight feature registered in the OpenLogi codebase?

The backlight feature is registered in crates/openlogi-hidpp/src/feature/registry.rs, where BacklightFeature is associated with HID++ feature ID 0x1982. The actual protocol implementation, including effect definitions and configuration structs, resides in crates/openlogi-hidpp/src/feature/backlight.rs.

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 →