Battery levels for wireless mice, keyboards, headsets and controllers in the Windows system tray - one icon per device, no vendor software.
While charging, the arc slowly "breathes":
Each device gets its own tray icon: a battery ring with the device's pictogram in the middle. The arc fills clockwise from the top, turns amber as the level approaches your alert threshold and red at or below it, and breathes green while the device charges. Hover over an icon for the exact percentage; right-click it to rename, hide, change the preferences or take a diagnostics report.
Levels are read over USB/HID (a dongle, a receiver or a cable), from Xbox-style controller reports, and from Windows itself for Bluetooth devices.
yes means the level has actually been seen on the device - here, from a report, or from a user who tried it. no means the support was written from another tool's code and nobody has tried it on real hardware yet. likely means other models of the same family share the code, so they should work too - they just haven't been tried one at a time. Each device links to notes on how its level is read.
PlayStation controllers over Bluetooth: a DualShock 4 or DualSense sends its battery level over Bluetooth only in its "full report" mode. Switching a controller into that mode makes it invisible to games that use DirectInput until it is turned off and on again (#96), so the app does not switch it: the level shows while Steam or a game has already put the controller in that mode, and otherwise the icon shows the controller without a level. If you do not play such games, turn on Preferences > PlayStation full mode (Bluetooth) to always see the level. Over USB the level is always shown.
8BitDo controllers in D-input mode: the battery level is only in the controller's enhanced report. Switching the controller into that mode makes it invisible to DirectInput games until it is turned off and on (tested by the reporter of #101), so the app never switches it: the level shows while Steam or a game has already put the controller in that mode, and otherwise the icon shows the controller without a level. In XInput mode the level is always shown.
The devices marked likely are the same code paths with other models: the rest of the Razer list
OpenRazer reads, the other WLmouse models, more Logitech HID++ 2.0 devices and G-series headsets,
the other Arctis Nova and older Arctis models, and other Xbox-compatible controllers.
Support for other devices is not guaranteed. New devices are added based on feedback and diagnostics logs: if yours is not detected or shows a wrong level, open an issue and attach the diagnostics report - see Troubleshooting below.
- Download
HaloBattery-<version>.zipfrom the Releases page. - Extract it somewhere permanent, e.g.
C:\Tools, so you getC:\Tools\HaloBattery\HaloBattery.exe, and runHaloBattery.exe. Keep theHaloBatteryfolder together: the .exe needs the_internalfolder next to it. - Right-click the tray icon → Start with Windows.
The app checks for a new release once a day and adds Download vX.Y.Z… to the menu when there is one. To update: tray menu → Exit, then replace the folder; Start with Windows follows the new copy. If you used the old single-file HaloBattery.exe, delete it.
Windows SmartScreen may warn about an unrecognized app on first launch, because the file is not code-signed: More info → Run anyway. Some antivirus tools flag unsigned Python apps by mistake (usually a generic !ml detection). The release is built by GitHub Actions straight from this repository, with public build logs; if you would rather not trust it, use Option 2.
- Install Python 3.10+ with Add python.exe to PATH checked.
- Download or clone this repository somewhere permanent, e.g.
C:\Tools\HaloBattery. - Run
install_and_run.bat, then right-click the tray icon → Start with Windows.
build_exe.bat builds it yourself into dist\HaloBattery. Releases are built automatically: pushing a tag like v1.8.0 makes GitHub Actions build the app and attach the zip (.github/workflows/release.yml).
- Centre: a headset, a mouse, a keyboard (a keycap with a K), an Xbox or PlayStation controller, or the Bluetooth rune - the pictogram can be turned off in the menu.
- Colour: follows the taskbar (white on a dark bar, black on a light one). With MyDockFinder running it follows its top menu bar instead. With a transparent taskbar (e.g. TranslucentTB) pick Icon colour → White or Black.
- Amber: close to the alert threshold. Red: at or below it.
- Green and breathing: charging - the animation can be turned off in the menu, leaving a plain green arc.
- Translucent: the mouse is asleep and keeps its last level for 5 minutes. A device that is switched off leaves the tray and comes back when it is switched on.
The low battery notification fires once, and again only after the device has been charged.
Right-click a device icon to open its menu. It looks like a Windows 11 menu (acrylic background, rounded corners, the light or dark app theme) and is sharp at any display scale. If it does not work on your PC, set "fluent_menu": false in %APPDATA%\HaloBattery\config.json to get the classic Windows menu back.
- Rename…: give the device your own name (for example, two controllers with the same name). Reset name goes back to the device's own name.
- Icon: pick the pictogram of this device (Automatic, Mouse, Keyboard, Headset, Controller or Bluetooth), for example a controller over Bluetooth that shows the Bluetooth pictogram.
- Low battery alert at: an alert level for this device only (off, 10–30%), or Default to follow Preferences. The red ring follows it too.
- Hide this device: remove its icon, for example for a controller that always reports 100%.
- Refresh now
- Preferences:
- Poll interval (15 s to 5 min) and Low battery alert (off, 10–30%): change them with the − and + buttons or the mouse wheel, the menu stays open
- Alert when fully charged (a notification once per charge, on by default)
- Estimated time left: "about 5 h of use left" in the tooltip, from how fast the device has drained since its last charge. Only time the device is awake and on battery counts, and there is no estimate until it has been used for 30 minutes and dropped 3%. The history is kept in
%APPDATA%\HaloBattery\history.json. - Quiet while gaming (on by default): while a game or other app is full screen (the same signal Windows uses to hold its own notifications), alerts are held and shown once it closes - one per device, and a low battery alert is dropped if the device was put on the charger meanwhile. Devices are polled only every 5 minutes then, since every poll talks to them; plugging something in still updates at once.
- Windows Bluetooth devices, Device pictogram, Percentage in the icon (the level as a number in the ring instead of the pictogram, amber or red when low), Charging animation
- PlayStation full mode (Bluetooth) (off by default): always read the battery of a PS4 / PS5 controller over Bluetooth. Some games stop seeing the controller in that mode until it is turned off and on
- Status file for other apps (off by default): writes
%APPDATA%\HaloBattery\status.jsonafter every poll, for Rainmeter, a Stream Deck plugin or a script. Each device hasname,level,charging,online,kind,seconds_leftand the tooltiptext;runningturns false when the app exits, andupdated_unixsays how fresh it is. Turning it off deletes the file. - Device types: turn off a brand or device family; its devices are then not opened at all
- Icon colour: Automatic (the Windows theme, or MyDockFinder's menu bar while it is running), White or Black
- Start with Windows (per-user registry key, no admin rights needed)
- Check for updates: once a day, on by default; a notification and a Download vX.Y.Z… item appear when a new release is out
- Hidden devices (only when a device is hidden): click a device to show it again
- Diagnostics…: writes a detailed report and opens it
- Close Synapse, the WLmouse web driver and other battery tools - they may hold the receiver.
- Wake the mouse up by moving it.
- Run
probe.bator choose Diagnostics… from the tray menu. The report lists every HID device and the raw protocol replies. Attach it to an issue in this repository to get a new device supported. The report contains Bluetooth MAC addresses and device serial numbers; you may want to redact them before posting. CONTRIBUTING.md tells you what to attach, how to record a USB capture for a device that is not supported yet, and how to open a pull request. - "python312.dll was not found", or Start with Windows says the app runs from a temporary folder: the app was started straight from the ZIP, or only
HaloBattery.exewas copied out of it. Extract the whole ZIP to a folder of its own (the_internalfolder must stay next to the .exe) and runHaloBattery.exefrom there.
Settings, the log and the diagnostics report live in %APPDATA%\HaloBattery.
- WLmouse protocol: @len0c (incconutwo/mouse-battery-tray, MIT).
- MCHOSE protocol: the write-up by @alexfrih (alexfrih/mchose-linux, recovered from MCHOSE's own web driver); the G7 from @kek353's monitor and the dump in #8.
- Hitscan Hyperlight protocol: @sopparus (sopparus/hitscan-battery), who mapped it from the vendor application's USB traffic and confirmed it in the libratbag discussion.
- AM Infinity 8K protocol: the AJAZZ Control Center project (Aiacos/ajazz-control-center, GPL-3.0), which reads the same USB id on its own AJ159 APEX unit.
- BlackShark V2 Pro 2023: the OpenRazer driver (PR #2862). Razer PIDs and transaction ids: OpenRazer and RazerBatteryTaskbar.
- The reference implementations behind individual devices - HeadsetControl, rivalcfg, Solaar, G-Helper, HyperHeadset, mouse.xyz,
@openmouse/protocol, keychron-battery-dkms, JBL_Baterry_Monitor and others - are credited next to the device they were used for in docs/protocols.md.
MIT, see LICENSE.
