0x1001 · batteryVoltage
Battery state as a measured millivolt reading plus charging flags — the only battery source on many G-series wireless devices.
Reports a device's battery as a measured voltage plus a charging-flags byte.
G-series wireless gaming devices (G915, G903 LIGHTSPEED, G502 LIGHTSPEED) expose
0x1001 and neither 0x1000 nor 0x1004, so without it the inventory probe
finds no battery source for them at all.
Unlike its siblings the feature reports no percentage; OpenLogi estimates one from the voltage when it renders the battery indicator.
The wire layout is not in a public Logitech spec. The big-endian millivolt
u16 followed by one flags byte was reverse-engineered; the decoding follows
Solaar's decipher_battery_voltage and libratbag's consensus on the flag bits.
Spec: reverse-engineered — x1001 batteryVoltage. Used by: battery state on G-series wireless devices.
Function reference
The BatteryVoltageFeature wrapper (0x1001) exposes:
Methods
| Function | HID++ fn | Signature | Returns |
|---|---|---|---|
get_battery_info | 0 | () | VoltageBatteryInfo |
The method is async and returns Result<…, Hidpp20Error>. The broadcast event
is not implemented.
Types
VoltageBatteryInfo
| Field | Type | Description |
|---|---|---|
voltage_mv | u16 | Measured battery voltage in millivolts — roughly 3500 (empty) to 4200 (full) for the single-cell Li-Po batteries these devices carry. |
status | VoltageChargingStatus | Charging state decoded from the flags byte. |
critical | bool | The firmware's "charge level critical" marker (flags bit 5). |
VoltageChargingStatus
| Variant | Description |
|---|---|
Discharging | Running on battery (bit 7 clear). |
Charging | Charging at the standard rate. |
ChargingFast | Charging at a raised current (bit 3). |
ChargingSlow | Charging at reduced current (bit 4). |
Full | On external power with charge complete (status bits 0b01). |
NotCharging | On external power but not charging — a charge fault (status bits 0b10). |
Decoding is total on purpose: a contradictory or future flag combination falls into the nearest charging bucket rather than failing, so a battery reading never vanishes over an unknown bit.
Wire format
get_battery_info (fn 0)
Request: [0x00, 0x00, 0x00] (no parameters)
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0–1 | voltage_mv | big-endian u16, millivolts |
| 2 | flags | charging state, decoded below |
Flags byte:
| Bit(s) | Meaning |
|---|---|
| 7 | External power present. Clear → Discharging, and every other bit is meaningless. |
| 0–1 | Charge status: 0b01 (or 0b11) → Full, 0b10 → NotCharging. Takes precedence over the rate bits. |
| 3 | Fast charging → ChargingFast. |
| 4 | Slow charging → ChargingSlow. |
| 5 | critical — surfaced independently of the status. |
Usage (Rust)
use hidpp::{device::Device, feature::battery_voltage::BatteryVoltageFeature};
// device: &mut Device, already created via Device::new(channel, index)
device.enumerate_features().await?;
if let Some(feat) = device.get_feature::<BatteryVoltageFeature>() {
let info = feat.get_battery_info().await?;
println!("{} mV — {:?} (critical: {})", info.voltage_mv, info.status, info.critical);
}See also: 0x1004 unifiedBattery, 0x1000 batteryStatus.