Which OpenLogi Crate Handles HID++ Enumeration and Probing?
The openlogi-device crate is the core component that performs HID++ device enumeration and probing in the OpenLogi project.
If you're building software that needs to discover Logitech HID++ devices, read their feature tables, or monitor for hot-plug events, you'll need to understand how this crate fits into the OpenLogi architecture. This article breaks down the crate's responsibilities, its API surface, and how it abstracts host-specific HID implementations across platforms.
Architecture Overview: A Clean Backend Abstraction
The openlogi-device crate sits at a strategic layer in OpenLogi's crate hierarchy. It depends on openlogi-hid for low-level platform HID operations, but exposes a host-agnostic API that works identically on macOS, Linux, Windows, and WebHID targets.
The HidBackend Seam
In crates/openlogi-device/src/lib.rs (lines 4-7), the crate defines [backend::HidBackend]—the seam that abstracts platform-specific HID implementations:
// From crates/openlogi-device/src/lib.rs
// The backend module provides the HidBackend trait and implementations
pub mod backend;
All enumeration logic operates through this backend. When you call enumerate(), openlogi-device creates a HidBackend, runs the enumeration pass, caches the resulting NodeInfo structs, and hands them back to your code. This design makes the same enumeration code reusable across every supported platform.
The Public Enumeration API
The crate re-exports three primary entry points from crate::inventory in crates/openlogi-device/src/lib.rs (lines 42-45):
enumerate— Standard inventory discovery used by the agent and GUIenumerate_standalone— Low-overhead enumeration for CLI usage when no agent is runningwatch_hotplug— Async stream that notifies callers of device insertion and removal events
Basic Enumeration with enumerate
Here's how the OpenLogi agent discovers devices:
use openlogi_device::{enumerate, Enumerator};
fn list_devices() -> Result<(), openlogi_device::InventoryError> {
// `enumerate` returns an iterator over discovered devices.
let devices = enumerate()?;
for device in devices {
println!("{} – {}", device.node_info.route, device.node_info.product_name);
}
Ok(())
}
Source: enumerate export
This is the standard path when an OpenLogi agent is active and managing device state.
Standalone Enumeration for CLI Tools
When you need device discovery without the agent infrastructure, enumerate_standalone provides lower overhead:
use openlogi_device::enumerate_standalone;
fn cli_list() {
match enumerate_standalone() {
Ok(devices) => {
for d in devices {
println!("{} ({})", d.product_name, d.serial_number);
}
}
Err(e) => eprintln!("Enumeration failed: {e:?}"),
}
}
Source: enumerate_standalone export
The CLI tool uses this path to quickly list available devices without spawning the full agent runtime.
Hot-Plug Monitoring with watch_hotplug
For reactive applications, the crate provides an async stream for device events:
use openlogi_device::watch_hotplug;
use futures::StreamExt;
#[tokio::main]
async fn hotplug_demo() {
let mut stream = watch_hotplug().await.unwrap();
while let Some(event) = stream.next().await {
println!("Hot‑plug event: {:?}", event);
}
}
Source: watch_hotplug export
This powers the GUI's live device list and the agent's automatic device attachment logic.
Device-Level Probing and Feature Access
After enumeration, openlogi-device provides helpers for probing a device's HID++ capabilities. The write module in crates/openlogi-device/src/write.rs contains functions that read feature tables, battery status, DPI settings, and other HID++ register values.
These probing operations work with the NodeInfo structures discovered during enumeration. They abstract the HID++ protocol details—your code doesn't need to construct raw HID reports or parse binary feature indices.
Key Source Files for HID++ Enumeration
| File | Role |
|---|---|
crates/openlogi-device/src/lib.rs |
Public façade that re-exports enumeration, backend, and write APIs |
crates/openlogi-device/src/inventory/mod.rs |
Core enumeration implementation (enumerate, enumerate_standalone) |
crates/openlogi-device/src/backend.rs |
HidBackend definition and hot-plug streaming infrastructure |
crates/openlogi-device/src/write.rs |
Probing helpers that read HID++ feature tables after enumeration |
crates/openlogi-hid/src/lib.rs |
Host-specific HID implementation consumed by openlogi-device |
These files form the complete HID++ enumeration and probing pipeline used across OpenLogi's GUI, agent, and CLI components.
Integration with Higher-Level Components
The openlogi-device crate serves as the single entry point for all device interaction:
- The GUI calls
enumerate()on startup and subscribes towatch_hotplug()for live updates - The agent uses
enumerate()for its device registry and delegateswritemodule functions for configuration changes - The CLI falls back to
enumerate_standalone()when the agent isn't available
No other crate in OpenLogi performs direct HID++ enumeration. Rather than duplicating platform detection logic, all components depend on openlogi-device and let its backend abstraction handle OS-specific details.
Summary
openlogi-deviceis the authoritative crate for HID++ enumeration and probing in OpenLogi- It provides three entry points:
enumerate(agent/GUI),enumerate_standalone(CLI), andwatch_hotplug(async events) - The
HidBackendabstraction inbackend.rsenables portable code across macOS, Linux, Windows, and WebHID - Device probing happens through the
writemodule after successful enumeration - All higher-level components (GUI, agent, CLI) route their device discovery through this crate
Frequently Asked Questions
What is the difference between enumerate and enumerate_standalone?
enumerate connects to a running OpenLogi agent and retrieves its cached device inventory—faster when the agent is active. enumerate_standalone performs fresh HID bus scans without agent coordination, making it suitable for CLI tools that need to work independently.
Does openlogi-device handle the actual USB/HID operations?
No. The crate delegates to openlogi-hid for platform-specific USB and HID operations. openlogi-device orchestrates the enumeration flow, manages NodeInfo caching, and provides the cross-platform API, while openlogi-hid implements the low-level HidBackend trait for each supported OS.
Can I use openlogi-device without the rest of OpenLogi?
Yes. The crate is designed as a standalone library. You can add it as a dependency to discover Logitech HID++ devices and probe their features without pulling in the GUI or agent runtime. The enumerate_standalone function exists specifically for this use case.
Where is hot-plug detection implemented?
The watch_hotplug async stream is defined in crates/openlogi-device/src/backend.rs, with platform-specific implementations in openlogi-hid. The backend abstraction ensures your code receives the same HotPlugEvent structure regardless of whether the underlying OS uses IOKit, libusb, WebHID, or another mechanism.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →