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 GUI
  • enumerate_standalone — Low-overhead enumeration for CLI usage when no agent is running
  • watch_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 to watch_hotplug() for live updates
  • The agent uses enumerate() for its device registry and delegates write module 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-device is the authoritative crate for HID++ enumeration and probing in OpenLogi
  • It provides three entry points: enumerate (agent/GUI), enumerate_standalone (CLI), and watch_hotplug (async events)
  • The HidBackend abstraction in backend.rs enables portable code across macOS, Linux, Windows, and WebHID
  • Device probing happens through the write module 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:

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 →