# Which OpenLogi Crate Handles HID++ Enumeration and Probing?

> Discover which OpenLogi crate handles HID++ enumeration and probing. Learn how the openlogi-device crate manages device discovery and interaction in the OpenLogi project.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: internals
- Published: 2026-09-01

---

**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`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/lib.rs) (lines 4-7), the crate defines `[backend::HidBackend]`—the seam that abstracts platform-specific HID implementations:

```rust
// 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`](https://github.com/AprilNEA/OpenLogi/blob/main/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:

```rust
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](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-device/src/lib.rs#L44-L45)*

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:

```rust
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](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-device/src/lib.rs#L43-L44)*

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:

```rust
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](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-device/src/lib.rs#L42)*

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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/lib.rs) | Public façade that re-exports enumeration, backend, and write APIs |
| [`crates/openlogi-device/src/inventory/mod.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/inventory/mod.rs) | Core enumeration implementation (`enumerate`, `enumerate_standalone`) |
| [`crates/openlogi-device/src/backend.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/backend.rs) | `HidBackend` definition and hot-plug streaming infrastructure |
| [`crates/openlogi-device/src/write.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/write.rs) | Probing helpers that read HID++ feature tables after enumeration |
| [`crates/openlogi-hid/src/lib.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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.