# How OpenLogi Uniquely Identifies and Keys Devices in Configuration

> Discover how OpenLogi uniquely identifies and keys devices using DeviceStableId, combining transport route and serial number for persistent configuration.

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

---

**OpenLogi uses a stable identifier called `DeviceStableId` that combines transport route information with per-unit identity (serial number or unit ID) to create unique, persistent configuration keys for each physical device.**

In `AprilNEA/OpenLogi`, every mouse, keyboard, or raw-HID device receives a deterministic identifier that survives disconnections, transport changes, and system restarts. This article explains the four route variants, three key-generation methods, and how they map to the TOML configuration structure.

---

## DeviceStableId: The Core Identifier

The **`DeviceStableId`** enum in [`crates/openlogi-core/src/device_order.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/device_order.rs) is OpenLogi's answer to reliable device identification. Rather than relying on volatile OS node names, it derives a stable ID from two inputs: the **`DeviceRoute`** (transport path) and **`DeviceIdentity`** (per-unit serial or unit ID)【/cache/repos/github.com/AprilNEA/OpenLogi/master/crates/openlogi-core/src/device_order.rs#L24-L33】.

The `from_parts` constructor assembles this identifier:

```rust
let stable_id = DeviceStableId::from_parts(
    Some(&device_route),  // transport route
    slot,                 // receiver slot if applicable
    serial,               // optional serial string
    unit_id,              // 4-byte fallback identifier
);

```

---

## Four Route Variants for Complete Device Coverage

`DeviceStableId` supports every possible connection method through four enum variants:

| Variant | Connection Type | Key Format |
|---------|-----------------|------------|
| **Bolt** | Logitech receiver (Bolt/Unifying) | `receiver:<uid>:slot:<slot>` |
| **Direct** | USB or Bluetooth direct attachment | `direct:<vendor_id>:<product_id>` + identity |
| **RawHid** | Stand-alone raw-HID device | `raw:<vendor_id>:<product_id>:<usage_page>:<usage_id>:<identity>` |
| **Unknown** | Cached device without live route info | `unknown:slot:<slot>` + identity |

Each variant ensures the resulting key contains enough information to locate and identify the device if it reconnects.

---

## DeviceIdentity: Per-Unit Serial vs. Unit ID

Inside `DeviceStableId`, the **`DeviceIdentity`** enum captures the actual hardware identifier. The `from_parts` helper implements a clear precedence rule: **serial number preferred, unit ID as fallback**【/cache/repos/github.com/AprilNEA/OpenLogi/master/crates/openlogi-core/src/device_order.rs#L68-L85】.

```rust
// Case-folded serial string (preferred)
DeviceIdentity::Serial("ABC12345".to_lowercase())

// 4-byte unit ID when serial unavailable
DeviceIdentity::UnitId([0x12, 0x34, 0x56, 0x78])

```

This design accommodates both premium devices with unique serials and mass-market hardware that only exposes a unit ID.

---

## Three Key Methods for Different Use Cases

`DeviceStableId` exposes three distinct string representations, each serving a specific purpose in the codebase:

### runtime_key(): Transient Session Key

Returns the **full key including route-derived identity**. Used for short-lived UI bookkeeping and internal device tracking. **Not persisted to configuration files**【/cache/repos/github.com/AprilNEA/OpenLogi/master/crates/openlogi-core/src/device_order.rs#L35-L45】.

### route_key(): Configuration Link Key

Returns the **path portion without device-specific identity**. This string is the map key for the `links` table inside `DeviceConfig.links`【/cache/repos/github.com/AprilNEA/OpenLogi/master/crates/openlogi-core/src/device_order.rs#L67-L77】.

### physical_key(): Persistent Device Identifier

Returns `Option<PhysicalDeviceKey>` — a **stable, cross-session key** only when the device has genuine physical identity (non-empty serial or non-zero unit ID). This becomes the top-level map key in per-device TOML configuration【/cache/repos/github.com/AprilNEA/OpenLogi/master/crates/openlogi-openlogi-core/src/device_order.rs#L88-L103】.

`PhysicalDeviceKey` can be round-tripped via `PhysicalDeviceKey::parse`.

---

## Configuration Layout: How Keys Map to TOML

In [`crates/openlogi-core/src/config/device.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/config/device.rs), the `DeviceConfig` struct defines the persisted configuration:

```rust
pub struct DeviceConfig {
    pub links: BTreeMap<String, LinkConfig>,  // keyed by route_key()
    // ... other fields
}

```

The `links` field uses **`route_key()`** as its map key【/cache/repos/github.com/AprilNEA/OpenLogi/master/crates/openlogi-core/src/config/device.rs#L71-L78】. Meanwhile, the entire `DeviceConfig` entry is keyed by **`PhysicalDeviceKey`** when the configuration file is serialized or deserialized.

This two-level key structure separates **transport-specific link configuration** from **device identity**, allowing a single physical device to maintain consistent settings across multiple connection methods.

---

## Practical Examples

### Bolt-Receiver Mouse

```rust
use openlogi_core::device_order::{DeviceStableId, DeviceIdentity};
use openlogi_core::hid::DeviceRoute;

let bolt_route = DeviceRoute::Bolt {
    receiver_uid: "AABBCCDD".into(),
    slot: 1,
};
let stable_id = DeviceStableId::from_parts(Some(&bolt_route), 1, None, [0; 4]);

assert_eq!(stable_id.runtime_key(), "receiver:aabbccdd:slot:1");
assert_eq!(stable_id.route_key(), "receiver:aabbccdd:slot:1");
assert!(stable_id.physical_key().is_some());

```

### Direct-USB Keyboard with Serial

```rust
let direct_route = DeviceRoute::Direct {
    vendor_id: 0x046d,   // Logitech
    product_id: 0xc08d,  // G915 TKL
};
let stable_id = DeviceStableId::from_parts(
    Some(&direct_route),
    0xff,  // unused slot for direct
    Some("ABC12345"),
    [0; 4],
);

assert_eq!(stable_id.runtime_key(), "direct:046d:c08d:serial:abc12345");
assert_eq!(stable_id.route_key(), "direct:046d:c08d");
assert_eq!(
    stable_id.physical_key().map(|k| k.into_string()),
    Some("direct:046d:c08d:serial:abc12345".to_string())
);

```

### Using route_key in Configuration

```rust
let config_key = stable_id.route_key(); // "direct:046d:c08d"
// Insert into DeviceConfig.links map
device_config.links.insert(config_key, link_config);

```

---

## Summary

- **`DeviceStableId`** combines transport route and hardware identity to create deterministic device identifiers in OpenLogi.
- Four route variants (**Bolt**, **Direct**, **RawHid**, **Unknown**) cover all connection scenarios.
- Three key methods serve distinct purposes: `runtime_key()` for session tracking, `route_key()` for link configuration maps, and `physical_key()` for persistent device identity.
- Configuration uses a two-level key structure: `PhysicalDeviceKey` for top-level device entries and `route_key()` for per-link settings inside `DeviceConfig.links`【/cache/repos/github.com/AprilNEA/OpenLogi/master/crates/openlogi-core/src/config/device.rs#L71-L78】.
- The implementation guarantees configuration persistence across sleep/wake, transport changes, and system restarts.

---

## Frequently Asked Questions

### What happens if a device has no serial number?

OpenLogi falls back to the 4-byte **unit ID**. If both are absent, the device can still be managed at runtime but cannot produce a `PhysicalDeviceKey`, meaning its configuration won't persist across restarts. This is handled by `DeviceIdentity::from_parts` in [`device_order.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/device_order.rs).

### Can the same physical device have multiple configuration entries?

No. The **`PhysicalDeviceKey`** is designed to be unique per physical device. However, a single device can have **multiple link configurations** keyed by different `route_key()` values if it supports multiple connection methods (e.g., both Bluetooth and USB receiver).

### How does OpenLogi handle a device switching from USB to receiver?

The `physical_key()` remains stable because it incorporates the underlying device identity (serial or unit ID). Only the `route_key()` changes to reflect the new transport path, so link-specific settings may differ per connection method while core device settings persist.

### Where is the configuration actually stored on disk?

Per-device TOML files use the `PhysicalDeviceKey` string as their identifier. The exact storage path is determined by the configuration backend, but the key format follows the `direct:046d:c08d:serial:abc12345` pattern shown in the examples above.