Read battery percentage and charging status from Rapoo gaming mice on Linux via their 2.4GHz USB dongle. No kernel module or proprietary driver needed.
| Device | USB ID (VID:PID) |
|---|---|
| VT3 Pro | 24ae:1215 |
| VT3 Pro Max | 24ae:1244 |
| VT3 Max Gen-2 | 24ae:3102 |
| VT9 Pro | 24ae:1417 |
| VT9 Pro Mini | 24ae:3103 |
The USB dongle exposes two HID interfaces:
- Interface 0 — Standard mouse input (X/Y/buttons/wheel)
- Interface 1 — Vendor-defined HID collections including battery status
The mouse sends a battery report (Report ID 0xBB, 7 bytes) every ~3 seconds:
Byte 0: 0xBB — Report marker
Byte 1: 0xB0 — Status flags
Byte 2: 0x81 — Mode flags
Byte 3: 0x20 — Polling/connection info
Byte 4: 0x03 — Connection type (2.4GHz)
Byte 5: 0x01/0x02 — Charging state (discharging / charging)
Byte 6: 0x00-0x64 — Battery percentage (0-100)
A second report type (0xBC, 10 bytes) may appear during cable plug/unplug transitions and is ignored.
Reports arrive every ~3 seconds, but the battery percentage value itself only changes every 5-10 minutes — this is a firmware design choice by Rapoo (saves power by not constantly reading the ADC). The charging state (0x01/0x02) updates instantly when you plug or unplug the cable.
# Copy script
sudo cp rapoo-battery.py /usr/local/bin/rapoo-battery
sudo chmod +x /usr/local/bin/rapoo-battery
# (Optional) Allow non-root access via udev rule
echo 'KERNEL=="hidraw*", ATTRS{idVendor}=="24ae", MODE="0666"' | sudo tee /etc/udev/rules.d/99-rapoo-mouse.rules
sudo udevadm control --reload-rules && sudo udevadm trigger
# Log out and back in for the rule to take full effect# Read battery once
rapoo-battery
# Monitor continuously (single-line, updates every ~3 seconds)
rapoo-battery --watch
# JSON output (generic, for polybar, i3bar, etc.)
rapoo-battery --json
# Waybar-compatible JSON output
rapoo-battery --waybar
# Show raw report bytes
rapoo-battery --raw
# Specify device explicitly (auto-detection if omitted)
rapoo-battery --device /dev/hidraw7
# Custom max wait time for watch mode
rapoo-battery --watch --interval 10$ rapoo-battery
Rapoo Mouse: ++[=========-----------] 45% Charging
$ rapoo-battery --json
{"battery_percent": 45, "charging": true, "device": "/dev/hidraw7"}
$ rapoo-battery --watch
Monitoring Rapoo mouse on /dev/hidraw7
Press Ctrl+C to stop.
[20:30:15] ++[=========-----------] 45% ⚡ CHARGING #42
"custom/rapoo": {
"exec": "rapoo-battery --waybar",
"return-type": "json",
"format": "🔋 {percentage}%",
"format-charging": "⚡ {percentage}%",
"format-critical": "🪫 {percentage}%",
"interval": 30,
"states": {
"warning": 30,
"critical": 15
}
}The --waybar flag outputs JSON with keys recognized by Waybar's custom module:
| Key | Value | Waybar placeholder |
|---|---|---|
text |
"45%" |
{text} |
percentage |
45 |
{percentage} |
alt |
"charging" or "discharging" |
{alt} |
tooltip |
"Rapoo Mouse: 45% — Charging" |
{tooltip} |
class |
"charging" / "warning" / "critical" / "discharging" |
CSS class |
The class value matches Waybar's states thresholds, so the format-critical and format-warning (default) variants activate automatically when battery drops.
- Python 3.6+
- Linux with hidraw support (any modern kernel)
lsusbandudevadm(fromusbutilsandsystemdpackages)- Root access or udev rule for
/dev/hidraw*permissions
Seems like this is the way how mouse firmware works. Maybe there is a special command to force re-update battery status, but currently i don't find it.