Releases: HeyOkay/HaloBattery
Release list
Halo Battery 1.13.0
A new Windows 11 style tray menu and a batch of tray features: turn device types off,
an alert level per device, estimated time left, the percentage in the icon, quiet while
gaming and a status file for other apps. PS4 / PS5 controllers over Bluetooth no longer
break DirectInput games (#96), and 8BitDo controllers in D-input mode are read the same
listen-only way. New devices: Corsair Dark Core RGB Pro SE, Razer BlackWidow V3 Pro,
Hitscan Hyperlight, HyperX Cloud Alpha 2 and Angry Miao AM Infinity 8K, plus many fixes
from contributors' reviews. Notifications are now titled "HaloBattery".
Added
- 8BitDo Pro 2, Pro 3, SN30 Pro and SF30 Pro in D-input mode (#101). The level is read
from the controller's enhanced report while Steam or a game has switched it on; the app
never switches it itself, because that mode hides the controller from DirectInput games
until it is turned off. Otherwise the icon shows the controller without a level. In
XInput mode these controllers already worked. Unverified on hardware here. - LAMZU Maya X: confirmed on a real mouse on its 8K dongle with 1.12.0, so it is no longer
marked unverified. - Device types in Preferences: turn off any brand or device family (Razer, Logitech,
PlayStation controllers, ...). A type that is off is not polled and its devices are not
opened; its icons go away at once. - Low battery alert at in the menu of a device: an alert level for that device only,
or Default to follow Preferences. The red ring of the icon follows it too. - Estimated time left in the tooltip ("about 5 h of use left"), from a least-squares
fit of the level against the time the device was awake and on battery since its last
charge. Time asleep, switched off or with the PC suspended does not count. No estimate
until 30 minutes of use and a 3% drop; kept in%APPDATA%\HaloBattery\history.json
so it survives a restart. Can be turned off in Preferences. - Percentage in the icon in Preferences: the level as a number in the ring instead of
the pictogram, sized to stay inside the ring ("100" included) and amber or red like the
arc when the battery is low. Devices that only report rough steps keep their pictogram. - Quiet while gaming in Preferences (on by default): while a full-screen app is in
front (SHQueryUserNotificationState), notifications are held and shown when it
closes, one per device and kind, and the poll interval becomes 5 minutes so the app
talks to the devices less during a game (#76). A plug-in still polls at once. - Status file for other apps in Preferences (off by default):
%APPDATA%\HaloBattery\status.json, rewritten after every poll (atomically), with each
device's name, level, charging, online, kind, alert level, seconds of use left and
tooltip text, for Rainmeter, Stream Deck or scripts. - Audeze Maxwell: a stuck dongle is recognised. An Xbox dongle (
3329:4B18) that said a
headset was linked, in PC mode with the headset on and playing audio, answered every
packet with an empty echo of the request (07 00 80 00 ...), so no battery ever arrived
and there was no icon; unplugging the dongle and plugging it back in fixed it at once.
After two such polls in a row the headset now gets a greyed icon that says to replug the
dongle, and the diagnostics say what was seen. This may be HeadsetControl #460. - Corsair Dark Core RGB Pro SE: the battery over its 2.4 GHz dongle (1B1C:1B7F),
through the Dark Core / Ironclaw "nxp" protocol from ckb-next. Its five-step
level is shown as a gauge ("about 50%") and no charging state is reported.
Unverified here: no Corsair mouse was on hand, so the collection and the
offsets are the reference's until the reporter of #56 confirms. - Razer BlackWidow V3 Pro: the battery over its 2.4 GHz receiver (1532:025C), through
the same class 0x07 commands the mice use (OpenRazer's RazerBlackWidowV3ProWireless
class lists them). The wired id 1532:025A has no battery and is left out.
Unverified here: no Razer keyboard was on hand, so the level arrives as the
reference describes it until the reporter of #56 confirms. - HyperX Cloud Alpha 2 (station 03F0:08BE): the battery percentage and the charging
state over the station's vendor collection. Decoded from the two USBPcap captures
attached to issue #26 at 51 % and 67 % and matched to NGENUITY's own display;
confirmed on real hardware by the reporter. - AM Infinity 8K (Angry Miao) on its 2.4 GHz receiver (3151:5007), the same id
as the AJAZZ AJ159 APEX (2.4G 8K): the AJAZZ Control Center project's
AJ-series exchange over the receiver's ffff:0002 control collection - a
zero-payload 0xF7 status poll brings the 2.4G telemetry up, then the charge
reads from status report 0x05. No charging state is reported. Unverified
here: the exchange is confirmed on the reference project's own unit, so the
layout stands until the reporter of #72 confirms it on the AM Infinity. - Hitscan Hyperlight over its receiver (3770:0200) and on the cable (3770:0100):
the same 17-byte frame the Pulsar / ATK / VXE mice use, from @sopparus's captures, notes and
Linux reader (sopparus/hitscan-battery).
Unverified: no Hyperlight was on hand, so #105
will confirm.
Changed
- New tray menu in the Windows 11 style: Segoe UI Variable text, Fluent icons, an acrylic
(blurred, translucent) background, rounded corners on Windows 11 and the light or dark
app theme. It fades in, opens next to the taskbar centred on the click (like the menus
of the Windows 11 taskbar) and opens submenus on hover; Esc or a
click elsewhere closes it, and it works from the keyboard. Set"fluent_menu": false
in the settings file to get the classic Windows menu back. - Poll interval and Low battery alert are now − / + counters in Preferences; the
menu stays open while you change them, and the mouse wheel works on them too. - The top of the tray menu shows the device's name on one line and its level,
charging state and time left on the line below. A long name or state wraps onto
more lines instead of making the whole menu wider. A small pencil at the right of the
name renames the device; it replaces the Rename item (the classic menu keeps it).
Fixed
- Notifications were titled "Python" instead of the app's name: the app now sets its
own app id and registers the name "HaloBattery" (and its icon) for the notification
header, per user, no admin rights. - The menu text was small and blurry on displays scaled above 100 %: the app is now DPI
aware, so the menu and the tray icons are drawn at the display's real resolution. - PS4 / PS5 controllers over Bluetooth stopped working in some games (DirectInput, for
example Rocket League from the Epic launcher) until they were turned off and on (#96).
To read the battery, the app switched the controller to its full report, and that
mode stays on. Over Bluetooth the app now only listens: the level shows while Steam or
a game has already switched the controller, and the icon shows no level otherwise.
Preferences > PlayStation full mode (Bluetooth) brings the old behaviour back for
those who do not play such games. USB is unchanged. - Audeze Maxwell: no more "Low battery, 0% left" when the headset is switched on. Right
after power-on it reports 0% for a moment (measured on an Xbox dongle: 0%, then the real
80% a poll later). A 0% in the first 90 seconds is now shown as "battery level not
reported yet", and the app re-checks every 3 seconds until the real level arrives
instead of waiting a full poll interval. After 90 seconds 0% is believed. - A Razer mouse could show "no link (off or asleep)" while in use, when Synapse or other
RGB software was sending lighting frames to it (#108). Every reply the app read was an
answer to the other app, and the app took that as a success without a level. It now
asks again up to three times, keeps the last level greyed out, and the diagnostics say
that another app is using the device. - An Xbox controller over Bluetooth could show a wrong "10%" when Windows Bluetooth
devices was off (#97, #108). Windows.Gaming.Input reports 100 of 1000 for it, and the
app did not always see that the controller is on Bluetooth. The product ids that Xbox
controllers use only over Bluetooth (from SDL) now say so, and the icon asks you to turn
on Windows Bluetooth devices for the real level. - An 8BitDo Ultimate controller on its dock's 2.4 GHz dongle showed "on cable, charging"
while it was off the dock and off the cable (#110). The dongle tells XInput that the
controller is wired, but Windows.Gaming.Input says that its battery is discharging. The
app now believes the second: no "charging", and the icon shows no level, because the
dongle does not report a real one (it always says 100%). - A device list that hidapi returned incomplete is no longer cached for the rest of the
session.hidlist.enumerate()caches its result against the set of HID paths, and only
re-reads when that set changes - but hidapi opens every device it lists, so a collection it
could not open at that moment is simply missing from the result, with the path set unchanged.
The short list was then served from the cache indefinitely: measured on this machine, 9 of 10
present collections came back for 5 calls in a row with a single hidapi call, and only an
unplug cleared it. A result with fewer entries than the vendor has present interfaces is now
re-read, at most once everySHORT_RETRY(30 s) so that a permanently unopenable collection
cannot turn every call into a full enumeration. Reported by @ahmedkhursheed23 in
#62. - The Bluetooth watcher now notices a stalled PowerShell instead of pretending to be
healthy. Its output was read with `for li...
Halo Battery 1.12.0
A big device release: support for many more mice, keyboards and headsets - ASUS, G-Wolves,
LAMZU, Lofree, Keychron, Pulsar/ATK/VXE, Nintendo Switch controllers, Logitech headsets,
more SteelSeries Arctis and Aerox models, HyperX Cloud III, Astro A50 Gen 5 and Corsair
headsets, among others. Devices can now be hidden or renamed, the app can tell you when
a device is fully charged, and each device can get the pictogram you pick. Tray icons keep
their place between starts, the extra "No devices found" icon is gone, and settings and
autostart are more robust. Many of the new devices are marked Unverified below: if you
own one, please tell us whether the level matches.
Added
- Hide a device (#23): "Hide this device" in the menu of a device icon removes the
icon and stops the low battery alert for that device, for example a controller that
always reports 100%. "Hidden devices" lists them; a click shows one again. - Rename a device: "Rename…" opens a Windows input box. The name is used in the
tooltip, the menu header and the low battery alert; "Reset name" goes back to the
device's own name. The pictogram does not change. - Fully charged: a notification when a charging device reaches 100%, once per charge
(a 99/100% wobble on the charger does not repeat it). "Alert when fully charged" in
Preferences turns it off. - Icon in the menu of a device: pick its pictogram (Automatic, Mouse, Keyboard, Headset,
Controller, Bluetooth), for example a controller over Bluetooth that got the Bluetooth
pictogram. The choice is kept per device, like the name. - Logitech headsets: G533, G535, G633, G635, G733, G933, G935, G PRO, G PRO X and
G PRO X 2 (HID++ models). The app reads the battery voltage with feature 0x1F20 and
shows the level, charging, and "headset off". The model list comes from
HeadsetControl; the feature layout comes from Solaar. A G733 is read on hardware (#75);
its percentage is an estimate from the voltage and can differ from G HUB's. - HyperX Cloud III Wireless (
03F0:05B7) over HID: battery and charging from the dongle's0xFF13vendor collection, next to the Cloud II support and alongside NGENUITY. Unverified on hardware - the packets, the reply ids and the level byte come from LennardKittner/HyperHeadset's implementation for this product id, which also documents the Windows-only fallback where a dongle accepts the packet only as a feature report; that fallback is implemented and the diagnostics say which path was taken. A level above 100 and the reference's all-zero state are both refused rather than shown as a reading - Lofree Hyzen keyboards on their 2.4 GHz dongle (
388D:0025, #82), with the battery query of Lofree's
own web driver (command1Ain its report 0x04 transaction). Unverified - no Lofree keyboard was on
hand.tests/test_lofree.pyuses the collections from the #82 report. - Astro A50 Gen 5 support through its base station, without G HUB: exact level, and
charging while the headset sits on the dock (the station reports that as byte 8).
The protocol is HeadsetControl's, reverse-engineered from G HUB captures and
verified on the same station (046D:0B1C); it is neither HID++ nor the A50 X's
"Centurion" protocol, and the provider only matches that USB id.
Unverified here: no A50 was on hand, so a level out of 0..100 is refused
rather than shown. - Corsair wireless headsets (Void v2 Wireless, Virtuoso Max Wireless, HS80 Max
Wireless) through their receiver, without iCUE: exact level, from HeadsetControl's
corsair_void_v2w protocol. A minimal handshake wakes a sleeping headset for the
read, the same one HeadsetControl uses, which avoids the audible pop of switching
the headset into software mode.
Unverified here: no Corsair headset was on hand, and the receiver sometimes
answers with something other than a level, so that is retried and then refused
rather than shown. Charging is not reported - the reply carries no such flag, and
HeadsetControl reports this family as not charging either. - JBL Quantum 910 Wireless support through its dongle: the headset pushes report 0x08
with the level in byte 1, the pattern plugato/JBL_Baterry_Monitor confirmed on this
USB id (0ECB:2088, one vendor collectionff13:0001, interface 5 on a real unit). There is no request to send, and the headset can
stay quiet for long stretches, so the last level heard is kept and shown greyed out.
Confirmed on a real unit: the provider finds the receiver, matches its collection and shows the level,
and a capture from that unit reads08 5f 03 ...- report 0x08 with byte 1 =0x5f= 95%, at the
moment JBL's own app showed 95%. The report is an event: it arrives when the headset is plugged into
its charger, and pressing buttons or the volume rocker does not produce it, so the listen window is ten
seconds and the last level heard is kept. The receiver also pushes a power report 0x09 (byte 1 is 0x00
when the headset is off and 0x01 when it is on, confirmed on a real unit) and a 0x02 frame; none of them
is a level, and a headset last seen switched off explains itself in the diagnostics. The report has no charging flag, so none is shown. - Keychron support over the Ultra-Link 8K receiver (3434:D028) and the cable (3434:D048,
the M5), without Keychron's own software: the vendor protocol - a 64-byte feature
reportb3 06answered by a 64-byte input reportb4 06whose byte 20 is the level -
as implemented by csutcliff/keychron-battery-dkms for these two ids.
Unverified here: no Keychron device was on hand, so a level above 100 is refused
rather than shown. Charging is not reported - the reply carries no such flag. - Pulsar, ATK and VXE wireless mice (Pulsar X2 V2 Mini, ATK VXE R1 SE+) over their dongle
or cable, without vendor software: 17-byte frames carrying a checksum, command 0x04 for
the power details, level in byte 6 and the on-cable flag in byte 7. Protocol from
andrewrabert/python-pulsar-mouse-tool, which also backs the "HID: pulsar" driver in
review for Linux. Unverified here: no such mouse was on hand, so a frame whose
checksum does not match is refused rather than shown. - Pulsar/ATK: the VXE R1 Pro Max 1 kHz dongle (
3554:F58A) reported in #87. The
provider never queried it, because the id was not in its table. The ATK/VXE control panel of
the OpenMouse project (@openmouse/protocol,drivers/atk) lists it as the R1 Pro Max receiver and reads
the battery with the same command0x04frame this provider already speaks, from the
collection with usage page0xFF02and usage0x0002- which is now preferred, because
the dongle has five other interface-1 collections and the first of them is not the one
that answers. The level, the charging flag and the millivolts come out at the same
offsets. A collection whose output report cannot carry the 17-byte frame is skipped, so a
dongle whose control collection only takes a longer report still gets read instead of
looking switched off (spotted by ahmedkhursheed23). The cable id (3554:F58C) is added
from the reporter's second report, where the wired mouse lists the same eight collections
and the same frame applies. Both transports are now confirmed on the reporter's hardware:
the receiver read the mouse's level, and on the cable the level matched ATK's own panel
(hub.atk.pro) with the charging flag following the cable in both directions. Reported by
huyxs2005. - Nintendo Switch Pro Controller and Joy-Con over Bluetooth (#63). Windows does not report
their battery, so the app reads the battery byte from the controller's own input report,
as SDL does: five levels (full, medium, low, critical, empty) and the charging bit. The
controller mode is never changed: the app only listens, or sends one read-only subcommand
(0x02, request device info). Unverified - no Switch controller was on hand.
tests/test_nintendo.pycovers every battery byte, the packet, both modes and the timeouts. - ASUS ROG / TUF wireless mice on their receiver or cable (#81: ROG Gladius III Wireless
AimPoint), with the battery command that G-Helper uses (12 07on the vendor collection of
interface 0): Gladius III / III Aimpoint / Eva 2, Chakram / Chakram X, Keris Wireless /
Aimpoint / EVA, Harpe Ace Aim Lab, Spatha X, Pugio II, Strix Impact II Wireless, TUF M4
Wireless and TX / TUF Gaming Mini. Unverified - no ASUS mouse was on hand.
tests/test_asus.pyuses the interfaces from the #81 report. - G-Wolves mice on the 8K receiver (
33E4:3854) or the cable (#82: G-Wolves WARG 8K), with the
WLmouse feature report exchange that G-Wolves' own web driver (mouse.xyz) uses for these
mice. The request goes only to the collection with a 64-byte feature report. Unverified -
no G-Wolves mouse was on hand.tests/test_gwolves.pyuses the collections from the #82 report. - LAMZU Maya X on its 8K dongle (
373E:001E) or the cable (373E:001C), without Lamzu's own
software. It is the same feature report exchange as the WLmouse and G-Wolves mice - one
request,00 00 02 02 00 83, answered bya1 00 02 02 00 83 <charging> <battery %>- sent
only to the vendor collection (usage page0xFFFF) of interface 2. Protocol from
Sheroune/lamzu-battery-monitory (MIT) and its Linux port; the collections match a
diagnostics report from a real Maya X 8K dongle. Unverified on hardware here. - SteelSeries Aerox 3 Wireless (
1038:1838) over HID: battery and charging on the receiver's vendor protocol, next to the existing Nova headsets and alongside SteelSeries GG. Unverified on hardware - the interface, the0xD2query and the level scale come from three sources that agree on this product id (alloyctl's reverse engineering of1038:1838, yurtemre7/steel-mouse, and the capture notes at gort818/aerox3-wireless), but no Aerox 3 Wireless was available here. A level byte of 0 is read as off or asleep rather than e...
v1.11.0
Added
- Update check: once a day the app asks GitHub for the latest release. When a newer
one is out, a notification says so once, and the tray menu gets a "Download vX.Y.Z…"
item that opens the release page. Nothing is downloaded or installed automatically,
and "Check for updates" in the menu turns it off (#14). - Sony DualShock 4 and DualSense / DualSense Edge over USB and Bluetooth, read straight
from the controller's HID input report (the same source as the Linux drivers and
DS4Windows): exact level and charging state. A controller on the cable and on
Bluetooth at once keeps one icon. Thanks to @dendr203 (#7). - HyperX Cloud II Wireless over HID (
03F0:0696,03F0:018B): battery and charging, using the exchange HeadsetControl documents for these product ids. Unverified - no Cloud II Wireless was on hand, so a reply that does not echo the command is ignored and a level above 100 refused rather than shown - SteelSeries Rival 3 Wireless (
1038:1830) over HID: battery and charging on the mouse exchange, next to the existing Nova headsets and alongside SteelSeries GG. Unverified - the reply layout is the open question in #5, so a reply without the command echo is skipped and a level above 100 refused rather than shown - Logitech support over HID++ 2.0, without G HUB (and alongside it). Every device
paired to a Lightspeed or Unifying receiver gets its own icon, named as the device
reports itself; the level comes from the unified battery, battery status or battery
voltage feature, whichever the device has. The icon follows the device's unit id, so
two identical mice get two icons and a mouse keeps its icon between the receiver and
the cable. Tested on the G502 LIGHTSPEED (voltage, matches G HUB) and the G502 X PLUS
(unified battery); other HID++ 2.0 mice and keyboards should work the same way.
A dozing radio takes up to half a second to answer, so the first request waits up
to 2 s; once a paired device stops answering (asleep or switched off) it is only
pinged briefly until it answers again, and keeps its last level, greyed out, for
5 minutes. - SteelSeries Arctis Nova 7 support through its 2.4 GHz dongle, without SteelSeries GG
(and alongside it): exact level and charging state. The other Arctis Nova 7 / 7X /
7x variants and the Arctis Nova 5 / 5X are included from HeadsetControl's device
list but not tested; new models with the same protocol are one line in
providers/steelseries.py. - Audeze Maxwell support, over the 2.4 GHz dongle (3329:4B19) and the USB-C cable
(3329:4B1A), reading the vendor collection (usage page 0xFF13) with the sequence
HeadsetControl uses: no Audeze HQ needed, and it works alongside it. The battery is
attribute 0x0CD6, so the level is read as an attribute rather than hunted as an
offset. Dongle and cable are one headset and share one icon, keyed on the serial
number they report, so plugging in the cable does not make the icon disappear and
come back. The Maxwell counts as a headset, so its icon gets the headset pictogram. - Razer DeathAdder V4 Pro (1532:00BF) confirmed on hardware, listed in the README's
table: transaction id 0x1F, command class 0x07, command 0x80 answers
02 1f 00 00 00 02 07 80 00 ab, raw 0xAB = 171/255 = 67%, stable across polls and
unchanged while Razer Synapse runs. - MCHOSE M7 Ultra (5253:1020) over the 2.4 GHz receiver, on the vendor collection
(usage page 0xFF01, whose sibling 0xFF0B never answers): feature report 0x11 (the shorter
report, tried first) or 0x12 with command 0x06, every payload byte inverted, which returns
53 52 31 00 02 05 07 00 09 64 00 64(vid, model, firmware, flags, level, charging).
The request has to be repeated for every read, and the receiver only relays a real
value while the mouse is awake - asleep it answers with zeros, so a silent mouse keeps
its last level on a greyed icon, the same as an idle Razer mouse. On the cable the mouse
answers on its own PID (5253:0031) with the charging byte set to 1 while the receiver
goes quiet, and the two connections still share one icon. - MCHOSE G7 (A8A5:2255, chip 'YJX-CHIP'), which is a different chip and a different
protocol from the M7 Ultra: a 65-byte output report00 55 30 A5 0B 2E 01 01 01,
answered by an input report startingAA 30with the level at byte 8 and the charging
flag at byte 9. Implemented from @kek353's monitor and the device dump in #8 and
confirmed on their G7: it answersaa 30 a5 0b 0a 01 01 01 2e 00 00 00, byte 8 =
0x2E = 46% and byte 9 = 0 on the dongle, the same level their own tool shows. On its cable
the same 0xFF01 read answers with the same level and the PID unchanged (aa 30 a5 3c 0a 01 01 01 2e 01 00 00, byte 9 = 1 while charging), so a G7 keeps one icon either way; only the
AA 30header is relied on, since byte 3 differs between dongle (0x0b) and cable (0x3c).
A level out of range is still refused rather than reported as a made-up number. It gets an icon
of its own, so it and an M7 Ultra on the same machine do not fight over one. - MCHOSE A7 V2 Ultra (3837:100B), which is the same protocol as the M7 Ultra on MCHOSE's
newer vendor id: the reference driver treats both identically and matches on the vendor
id plus the vendor collection rather than by model list, which is what this provider
does too. Its status read is documented on the shorter 0x11 report, so both report ids
are tried, and a model the name table does not know is named from the receiver's own
product string. Unverified - from the diagnostics in #4, no device here - and it
gets an icon of its own, so it and an M7 Ultra on one machine stay two icons.
Changed
- Audeze: the poll sends one packet instead of twenty. The packet that asks for
attribute 0x0CD6 comes back with the marker on its own, on the dongle and on the
USB-C endpoint alike: 0.19 s against 1.48 s. Both ran against each other every 30 s
through a charge from 85% to 91% and agreed in 19 of 20 cycles, the one difference
being the long sequence reading an older copy out of the device's rolling buffer.
The full sequence stays as the fallback for a firmware that only reports after the
initialisation. - Audeze: charging is inferred from the cable endpoint answering, because the protocol
carries no charging flag. Verified by diffing every record the headset returns while
charging and while running off the dongle: identical apart from the echo of the query
that was just sent. Docked and already full the icon still breathes where the LED is
solid green, which is the trade for not telling someone to charge a headset that is
plugged in. - Razer: a sleeping mouse now keeps its last level on a greyed icon for five minutes
instead of losing the icon after two failed polls (STATUS_TIMEOUT, "receiver
present, device not responding"). That is what the README already described; the
behaviour is gated so a switched-off headset still loses its icon. - New controller pictogram for Xbox-compatible controllers (XInput and
Windows.Gaming.Input), traced from the Xbox controller glyph: flat top, rounded
shoulders, straight sides down to the grips, and the two sticks in the Xbox layout
(left stick high, right stick low and nearer the middle). Nothing else is cut out,
so it stays readable at 16 px. - PlayStation controllers get a DualShock 4 pictogram in the same style: the outline
with its stepped shoulder buttons and long grips, the touchpad and the two symmetric
sticks cut out. The DualSense uses it too for now. - HyperX: when the dongle has no 0xFF90:0x0303 collection, nothing is written to any
other collection; the diagnostics list what the dongle offers instead.
Fixed
- Razer mice that answer a battery request with somebody else's packet first are no
longer written off as "off or asleep". Razer Synapse polls LED state on the same
collection and its replies carry the same status byte as the battery reply, so the
first packet could belong to a different command (seen on a DeathAdder V2 Pro in
#3). The reply is now read on - bounded by the same deadline - until the answer to
the request arrives, and a packet that is not that answer is never turned into a
level, so a device that never answers still shows nothing rather than a number. - After a device went missing (e.g. a Razer headset switched off while its receiver
stays plugged in), all devices were polled every 3-4 seconds for as long as the app
ran, instead of at the poll interval: the quick re-check that confirms a disconnect
never stopped after the icon had been removed. Besides filling the log, this would
keep waking wireless mice (e.g. Logitech) over the radio. - A Razer device that is switched off while its receiver stays plugged in no longer
writes the same six log lines on every poll: the failure is logged once, and again
only when the reason changes or the device answers again. - Bluetooth: a device that is also read over HID no longer gets a second icon from
Windows' own Bluetooth battery API. A paired Maxwell reports the same level over both
transports at once (90% over the cable endpoint and 90% over Bluetooth), so the
Bluetooth copy is dropped and the HID reading - the device's own protocol, carrying
the charging state - is kept. A device only Bluetooth can see keeps its Bluetooth
icon, which is how a Maxwell used purely over Bluetooth is covered at all: the vendor
collection the provider needs does not exist over Bluetooth. Game controllers are
left out of this: for a controller on Bluetooth, Windows' own value is still the one
shown, as in 1.10.1. - Audeze: a switched-off headset no longer pays for the battery packet that cannot be
answered (1.5 s per poll instead of 1.7 s), and its failure block is written once per
outage instead of every poll. - Audeze: a Maxwell that is switched off is no longer reporte...
v1.10.1
Added
- Icon colour in the tray menu: Automatic (as before), White or Black. For a
transparent taskbar (e.g. TranslucentTB), where the Windows theme does not match
what is behind the icons. - README: the Razer Basilisk V3 Pro and Basilisk Ultimate, the FlyDigi Vader Pro
controller, and Audio-Technica and JBL Tune 760NC Bluetooth headphones,
confirmed working by users.
Changed
- Releases are now a zip with a
HaloBatteryfolder (HaloBattery.exeplus its
libraries in_internal) instead of a singleHaloBattery.exe. The single-file
.exe unpacked Python into a temp folder at every start, which Windows Defender
and other antivirus machine-learning heuristics flagged as a trojan by mistake
(e.g.Trojan:Win32/Sabsik.TE.A!ml). The .exe now also carries version
information (name, version, description) in its Properties, and is built
without UPX compression. To update, replace the oldHaloBattery.exewith the
folder; "Start with Windows" is pointed at the new copy the first time it runs. - "Windows Bluetooth devices" is now on by default for new installations, since
many people use the app with Bluetooth headphones and controllers. Existing
settings are kept: if the option was saved as off, it stays off. - Bluetooth devices get a pictogram by their type instead of the Bluetooth rune:
headphones and headsets the headset, mice the mouse, controllers the gamepad.
The type comes from the device itself (the Bluetooth Class of Device, or the
Appearance value for Bluetooth LE) or from its audio services; devices of other
types, or whose type is unknown, keep the Bluetooth rune. Diagnostics show the
detected type.
Fixed
- An Xbox controller connected over Bluetooth showed up twice with "Windows
Bluetooth devices" on: once as a Bluetooth device with the level Windows shows
in Settings, and once as a controller with a wrong level (e.g. 10% instead of
71%) and a generic "HID-compliant game controller" name. When the Bluetooth
entry is there, the controller entry is now dropped; with Bluetooth devices
turned off, it is shown without a level instead of the wrong one (over
Bluetooth, Windows.Gaming.Input reported 100 of 1000 mWh for a controller at
82%). Controllers named with a generic HID name are now called by their vendor
("Xbox controller") instead. - Wired Razer devices without a battery (e.g. the Huntsman V2 keyboard) could show
up as a tray icon: some of them answer the battery command too. Razer devices are
now polled only when they are on the list of known wireless models or their name
suggests a battery (HyperSpeed, wireless, receiver, dongle, dock, or a BlackShark,
Barracuda or Nari headset). Skipped devices are still listed in the diagnostics.
v1.10.0
Added
- MyDockFinder support. MyDockFinder draws its own macOS-style menu bar and switches
it between light and dark by the wallpaper or the full-screen app, while the Windows
theme stays the same. While MyDockFinder is running, the icon colour now follows the
same rule as its bar: when windows cover the whole area right under the bar
(maximized, full-screen or snapped side by side), by their title bars (a thin strip
at the top right of the screen is sampled; no cursor flicker, nothing is saved);
as soon as the desktop shows anywhere under the bar, by the wallpaper as a whole,
so a dark sky over a light landscape still counts as light. Shell overlays such as
Task View, Snap Assist, Alt+Tab and the Start menu do not count as windows.
The colour is re-checked the moment a window is maximized, restored, snapped,
moved, minimized, closed or brought to the front (the same system window events
MyDockFinder reacts to), again as the window animation settles, and every
0.25 seconds otherwise; both colour variants of each icon are drawn in advance,
so the icons switch together with the bar. The icons are black on a
light bar and white on a dark one. With the standard Windows shell nothing changes:
the icons follow the Windows theme as before.
v1.9.1
Fixed
- Possible USB keyboard dropouts while the app is running. To notice devices being
plugged in or removed, the app listed all HID devices every 2.5 seconds through
hidapi, which briefly opens every HID device on the system, the keyboard included;
some high-polling-rate keyboards (e.g. NuPhy Air75 HE) may not tolerate that.- Plug and unplug detection now reads only the list of device paths from the
Windows configuration manager and does not open any device. - The full device list is re-read only when a device is actually plugged in or
removed, and only for the vendors the app supports (Razer, WLmouse, and the
controller vendors used for naming); vendors that are not present are skipped. - Controller polls no longer read the product strings of every HID device.
- Plug and unplug detection now reads only the list of device paths from the
- The icon of a device whose receiver was unplugged or that was switched off could
stay for up to a minute: the second, confirming check waited for the next
scheduled poll. It now runs 3 seconds after the first miss. - Bluetooth devices took about a minute to appear after connecting (and to disappear
after disconnecting): they were checked by a new PowerShell run once a minute.
One long-lived PowerShell process now checks only the connection state every
2 seconds (a direct WinRT query by MAC address, no device scan) and reads the
battery levels right after a device connects or disconnects, again at +3, +8 and
+15 seconds (Windows reports the battery a moment after connecting) and once a
minute. A connected device now shows up within a few seconds. If that process
cannot run, the app falls back to the old once-a-minute check. The process exits
together with the app.
v1.9.0
Added
- Xbox-compatible controllers, tested with the GameSir G7 Pro on its 2.4 GHz receiver.
The battery is read through Windows.Gaming.Input (the API the Xbox Accessories app
uses): an exact percentage and the charging state. XInput is used as a fallback;
it only reports four levels, so the tooltip then shows an approximate value
such as "about 55% (medium)". - Gamepad pictogram: an Xbox controller silhouette with symmetric sticks.
- A controller's icon appears within a few seconds of switching it on and
disappears within a few seconds of switching it off. Until Windows reports the
battery, the icon is shown without an arc ("connected, battery level not reported yet"). - Automatic release builds: pushing a
v*tag buildsHaloBattery.exeon GitHub
Actions and attaches it to the release. "Run workflow" builds it without releasing. - The .exe has its own icon (a green ring on a dark disc), also used by
build_exe.bat.
Changed
- Devices that are switched off no longer stay in the tray as grey icons:
- a Razer headset that is off while its receiver stays plugged in is hidden after
two failed polls in a row; - a silent WLmouse keeps its greyed-out last level for 5 minutes (the receiver
cannot tell a switched-off mouse from one that fell asleep) and is then hidden.
Both come back as soon as the device answers again.
- a Razer headset that is off while its receiver stays plugged in is hidden after
- The low battery notification says "battery is low" for devices that only report
approximate levels, instead of an invented percentage. - README: the supported devices table lists only hardware tested for real, and
installation starts with the ready-made .exe.
Fixed
--probeno longer crashes on a cp1252 console when a device name contains
non-ASCII characters.
v1.8.0
Full Changelog: https://github.com/HeyOkay/HaloBattery/commits/v1.8.0