Hello everyone,
I’m looking for a way to display the battery level of my Bluetooth headphones in the macOS menu bar using BetterTouchTool. I attempted to retrieve the information using the command system_profiler SPBluetoothDataType
, but it does not return the battery level for my headphones.
I know that my device sends battery data to the Mac because the battery level is visible in the Control Center and in the AllMyBatteries app. Has anyone managed to access this battery information in BetterTouchTool? Any pointers or alternative methods to capture and display this data in the menu bar would be greatly appreciated.
Thank you in advance for your help!
What's the model of the bluetooth headphones?
I'm able to display my AirPods Pro Gen 2 battery device information using this script:
#!/bin/bash
# AirPods battery level script for macOS
# Ensure AirPods are connected before running this script.
# Use system_profiler to get Bluetooth device info, then parse battery levels.
BT_INFO=$(system_profiler SPBluetoothDataType 2>/dev/null)
# Extract the battery percentages for case, left, and right
case_level=$(echo "$BT_INFO" | awk -F': ' '/Case Battery Level/{print $2}')
left_level=$(echo "$BT_INFO" | awk -F': ' '/Left Battery Level/{print $2}')
right_level=$(echo "$BT_INFO" | awk -F': ' '/Right Battery Level/{print $2}')
# Print the results in a user-friendly format
echo "AirPods Pro Battery - Case: ${case_level}, Left: ${left_level}, Right: ${right_level}"
Maybe this will point you in the right direction?
Bowers & Wilkins Px7 S2
As I mentioned at the beginning of the thread, I've already tried using the system_profiler SPBluetoothDataType
command, but it doesn't contain battery level information for my headphones at all.
is it maybe included here?
ioreg -r -c AppleDeviceManagementHIDEventService | grep Battery
Here's ChatGPT Deep Research's answer. I've had very good results from using Deep Research for generating tricky shell and AppleScript commands. Fun fact, the response references this forum several times!
Retrieving Battery Level of Bowers & Wilkins Px7 S2 on macOS
You can retrieve the battery percentage of your B&W Px7 S2 headphones on an M1 MacBook Pro using built-in macOS tools. Below are a few reliable methods. Each method runs as a one-time shell command or script (not continuously), and outputs the battery percentage:
1. Using the ioreg Command (IORegistry)
Recent macOS versions expose Bluetooth device battery info in the I/O Registry. You can query this via the ioreg command:
# Example: fetch battery percentage via ioreg and extract the number
ioreg -r -n AppleDeviceManagementHIDEventService -k BatteryPercent | \
perl -nE '/"BatteryPercent" = (\d+)/ && print $1'
This uses ioreg to list devices with the BatteryPercent property and a Perl one-liner to extract just the numeric value. On modern macOS, third-party Bluetooth devices that report battery levels (like Bose, Sony, B&W, etc.) often appear under the AppleDeviceManagementHIDEventService class with a BatteryPercent key . The above command will output the battery percentage (e.g. 85 for 85%). You can append a % in the output if desired (e.g., echo "$( ... )%").
Note: If you have multiple Bluetooth devices with battery info (keyboard, mouse, etc.) connected, the ioreg approach might return multiple entries. In that case, you can filter by the device name. For example:
ioreg -r -l -k BatteryPercent | grep -A3 -i "Px7 S2"
This will show the battery info section for the Px7 S2. You could then refine the extraction to that section.
2. Using system_profiler
Apple’s built-in System Information can list Bluetooth device details, including battery level. The command-line system_profiler SPBluetoothDataType reports all Bluetooth devices. You can filter its output for the Px7 S2’s battery. For example:
system_profiler SPBluetoothDataType 2>/dev/null | awk -v RS="" '/Px7 S2/ { if(match($0, /Battery Level: ([0-9]+%)/, m)) print m[1] }'
This command finds the section for “Px7 S2” and prints the “Battery Level: xx%” value. On recent macOS, the Battery Level field is shown for many Bluetooth audio devices in the SPBluetoothDataType report (it mirrors what you see in the Bluetooth menu) . For a quick check, you can simply run:
system_profiler SPBluetoothDataType | grep -A1 -i "Px7 S2"
and look for a line like “Battery Level: 77%” (the number will vary) . This confirms the battery percentage. You can script this extraction as shown with awk or use simpler text parsing since the output format is consistent.
3. Reading the Bluetooth Preferences Plist
If the above direct queries don’t work (on some systems the headphones might not show up with BatteryPercent), you can read macOS’s Bluetooth device cache, which stores battery info for connected devices. The cache is in a property list file: /Library/Preferences/com.apple.Bluetooth.plist. Within this plist, under the DeviceCache dictionary, each device is identified by its MAC address and may have keys for battery level. Common keys include:
• BatteryPercent – for single-percentage devices (often Apple keyboards/mice)
• BatteryPercentSingle – used for some headsets (e.g. certain Beats or other single-battery devices)
• BatteryPercentLeft / BatteryPercentRight – for devices with dual batteries (e.g. AirPods earbuds)
Steps:
-
Find the headphone’s MAC address: You can get this from the Bluetooth menu (Option-click the Bluetooth icon) or via system_profiler. For example: system_profiler SPBluetoothDataType | grep -B2 "Px7 S2" will show the device’s Address.
-
Query the plist for the battery key: Use the MAC address in a Plist query. For instance, if your Px7 S2’s MAC is AA-BB-CC-DD-EE-FF, run:
sudo /usr/libexec/PlistBuddy -c "Print :DeviceCache:AA-BB-CC-DD-EE-FF:BatteryPercent" /Library/Preferences/com.apple.Bluetooth.plist
This will print the battery percentage value stored for that device. If it returns an error or empty, try "BatteryPercentSingle" in place of BatteryPercent. (For some devices, Apple uses a different key; Beats headphones, for example, have used BatteryPercentSingle in this file .)
As an example, AppleScripts for BetterTouchTool use this method to read battery keys from the Bluetooth plist for various devices . This approach does not require any continuously running process – it simply reads the cached battery value when you execute the script.
4. Third-Party Utilities (Alternative)
If you prefer not to script this yourself, there are third-party utilities that can report Bluetooth headphone battery levels. One popular option was Akku – a free, open-source menu bar app designed to show headphone battery percentages. It worked for many brands (Bose, Sony, etc.) . However, note: Akku is no longer actively maintained and reportedly doesn’t work on macOS Monterey or later .
Other tools include general Bluetooth managers and system monitors (for example, iStat Menus or similar apps) that display connected device battery levels. But since macOS now natively provides this info, the built-in methods above are usually sufficient.
Using the ioreg or system_profiler approaches are the most direct ways on macOS to get the Px7 S2’s battery level via a one-off shell command. If those don’t yield a result, the plist-reading method will tap into the same data used by the Bluetooth menu. All these methods will output the battery percentage (as a number or with a % sign) when the script/command is run, and then exit immediately, satisfying the requirement for a one-shot query (not a continuous monitor).
Sources: Methods adapted from user-contributed solutions on Apple StackExchange and official macOS behavior. The Bluetooth cache file keys are documented through community scripts , and the use of Akku was suggested in multiple forums .
Nope.
@fortred2 I have tried everything listed here by GPT - it does not work. Interestingly, the file com.apple.Bluetooth.plist
doesn't list my headphones at all - there are only Beats, which I don't have for a long time now
Interesting.
- Could you tell me how old your B&W Px7 S2 headphones are?
- Are you able to see the battery level of your headphones using the official iOS app? Music | Bowers & Wilkins on the App Store. If yes, then we can try to sniff the Bluetooth Low Energy packets being sent between your headphones and your iPhone – I'll share with you some commands to run once you confirm (reference: a) How to Read the Battery Level of Bluetooth LE Devices – andreasjakl.com b) https://www.baeldung.com/linux/check-bluetooth-device-battery-level).
- Dumb and genius question, have you restarted both your headphones and your Mac?
- They are fairly new, about a month old.
- Yes, I can see the battery level in the official iOS app. As I mentioned at the beginning of the thread, I can also see it on the Mac in the AllMyBatteries app.
- Of course.
It's not easy to troubleshoot with you given I don't own Bowers & Wilkins headphones, but here is what I suggest doing:
-
Install this BLE sniffer app BLE Scanner 4.0 on the App Store.
-
Find your B&W Px7 S2 headphones listed from the nearby devices and connect to them.
-
Figure out which BLE service or characteristic contains the headphone battery level.
-
If that doesn't work, try using GitHub - pybluez/pybluez: Bluetooth Python extension module to obtain the battery level information.
That's good news.
Do you see a blue botton with the letter "R" in it to the right of you screenshot? If yes, what do you see if you click on it? Do you see the battery level value (i.e. are you able to "read" the value)?
Next, could you please run this Python script and tell me what the output is? This script tries to programmatically obtain the battery level value from your headphones.
import asyncio
import logging
from bleak import BleakClient, BleakScanner
# -----------------------
# User-defined parameters
# -----------------------
# The substring of the BLE device's name to look for.
# For B&W Px7 S2 headphones, you might use "Px7 S2" or "Bowers & Wilkins".
TARGET_DEVICE_NAME = "Px7 S2"
# How many seconds to scan for devices.
SCAN_TIMEOUT = 5.0
# Enable debug logging if needed (set to True for more verbose output)
DEBUG_LOGGING = False
# -----------------------
# Standard UUIDs
# -----------------------
# The standard Battery Service UUID (expanded from 0x180F)
BATTERY_SERVICE_UUID = "0000180f-0000-1000-8000-00805f9b34fb"
# The standard Battery Level Characteristic UUID (expanded from 0x2A19)
BATTERY_LEVEL_CHAR_UUID = "00002a19-0000-1000-8000-00805f9b34fb"
async def read_battery_level():
logging.info(f"Scanning for BLE devices (looking for '{TARGET_DEVICE_NAME}')...")
devices = await BleakScanner.discover(timeout=SCAN_TIMEOUT)
if not devices:
logging.warning("No BLE devices found.")
return None
target = None
for d in devices:
if d.name and TARGET_DEVICE_NAME.lower() in d.name.lower():
target = d
break
if not target:
logging.warning(
f"Could not find any device whose name contains '{TARGET_DEVICE_NAME}'."
)
return None
logging.info(f"Found device: {target.name} ({target.address}). Connecting...")
try:
async with BleakClient(target) as client:
# Ensure services are discovered
if not client.services:
await client.get_services()
services = client.services
# Check for the Battery Service
battery_service = next(
(s for s in services if s.uuid.lower() == BATTERY_SERVICE_UUID), None
)
if not battery_service:
logging.warning("Battery Service (0x180F) not found on this device.")
return None
try:
battery_data = await client.read_gatt_char(BATTERY_LEVEL_CHAR_UUID)
if not battery_data:
logging.warning(
"Battery Level characteristic read returned empty data."
)
return None
battery_percent = int(battery_data[0])
logging.info(f"Battery Level read successfully: {battery_percent}%")
return battery_percent
except Exception as e:
logging.error(f"Error reading Battery Level characteristic: {e}")
return None
except Exception as conn_ex:
logging.error(
f"Failed to connect to {target.name} ({target.address}): {conn_ex}"
)
return None
def main():
# Set up logging
log_level = logging.DEBUG if DEBUG_LOGGING else logging.INFO
logging.basicConfig(
level=log_level, format="%(asctime)s [%(levelname)s] %(message)s"
)
battery_level = asyncio.run(read_battery_level())
if battery_level is None:
print("Battery level could not be read.")
else:
print(f"B&W Px7 S2 battery level: {battery_level}%")
if __name__ == "__main__":
main()
To run the Python script, you'll need to first install the "Bleak" Python library using either pip install bleak
or uv add bleak
.
I don't know why, but I can't run this code. It shows me that I don't have Bleak, but I installed it.
Traceback (most recent call last):
File "/Users/michalstankiewicz/Desktop/px7_battery/script.py", line 4, in <module>
from bleak import BleakClient, BleakScanner
File "/Users/michalstankiewicz/Library/Python/3.9/lib/python/site-packages/bleak/__init__.py", line 43, in <module>
from async_timeout import timeout as async_timeout
ModuleNotFoundError: No module named 'async_timeout'
This probably is a problem with your Python environment.
Relevant meme:
I recommend creating a new Python virtual environment, installing Bleak in that new virtual environment, and then running the script with the virtual environment active.
Does this make sense?
Also, make sure to install asyncio
using pip install asyncio
.
Hold on, I just realized you're using Python3.9. If you use Python < 3.11.3 then you'll get the ModuleNotFoundError: No module named 'async_timeout'
error.
You should either use a more recent version of Python or run pip install async_timeout
.
Maybe it would be a good idea for me to add a "Read / Write Bluetooth LE Characteristic" action
I did it and it still doesn't work – same error.
@MStankiewiczOfficial did you try this?