# Battery level of Bluetooth headphones

**URL:** <https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832>\
**Category:** Configuration Help & General Discussion\
**Tags:** bluetooth\
**Created:** [March 15, 2025, 7:12am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832 "2025-03-15T07:12:15Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![MStankiewiczOfficial](https://community.folivora.ai/user_avatar/community.folivora.ai/mstankiewiczofficial/32/30271_2.png) [@MStankiewiczOfficial](https://community.folivora.ai/u/MStankiewiczOfficial)\
**Post date:** [March 15, 2025, 7:12am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/1 "2025-03-15T07:12:15Z")

</div>

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!

---

<div class="post-metadata">

**Author:** ![fortred2](https://community.folivora.ai/letter_avatar_proxy/v4/letter/f/e79b87/32.png) [@fortred2](https://community.folivora.ai/u/fortred2)\
**Post date:** [March 15, 2025, 8:14am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/2 "2025-03-15T08:14:43Z")

</div>

What's the model of the bluetooth headphones?

I'm able to display my AirPods Pro Gen 2 battery device information using this script:

```bash
#!/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?

---

<div class="post-metadata">

**Author:** ![MStankiewiczOfficial](https://community.folivora.ai/user_avatar/community.folivora.ai/mstankiewiczofficial/32/30271_2.png) [@MStankiewiczOfficial](https://community.folivora.ai/u/MStankiewiczOfficial)\
**Post date:** [March 15, 2025, 8:29am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/3 "2025-03-15T08:29:41Z")

</div>

> [@fortred2](#):
>
> What's the model of the bluetooth headphones?

Bowers & Wilkins Px7 S2

* * *

> [@fortred2](#):
>
> I'm able to display my AirPods Pro Gen 2 battery device information using this script

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.

---

<div class="post-metadata">

**Author:** ![Andreas\_Hegenberg](https://community.folivora.ai/user_avatar/community.folivora.ai/andreas_hegenberg/32/39221_2.png) [@Andreas\_Hegenberg](https://community.folivora.ai/u/Andreas_Hegenberg)\
**Post date:** [March 15, 2025, 8:51am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/4 "2025-03-15T08:51:30Z")

</div>

is it maybe included here?

```auto
ioreg -r -c AppleDeviceManagementHIDEventService | grep Battery

```

---

<div class="post-metadata">

**Author:** ![fortred2](https://community.folivora.ai/letter_avatar_proxy/v4/letter/f/e79b87/32.png) [@fortred2](https://community.folivora.ai/u/fortred2)\
**Post date:** [March 15, 2025, 9:09am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/5 "2025-03-15T09:09:51Z")

</div>

Here's ChatGPT Deep Research's [answer](https://chatgpt.com/share/67d542c5-0e8c-8004-9ac5-25d8d7a85be6). 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:

```auto
# 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:

```auto
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:

```auto
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:

```auto
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:**

1. **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.

2. **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:

```auto
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 .

---

<div class="post-metadata">

**Author:** ![MStankiewiczOfficial](https://community.folivora.ai/user_avatar/community.folivora.ai/mstankiewiczofficial/32/30271_2.png) [@MStankiewiczOfficial](https://community.folivora.ai/u/MStankiewiczOfficial)\
**Post date:** [March 15, 2025, 9:26am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/6 "2025-03-15T09:26:44Z")

</div>

@Andreas_Hegenberg

> [@Andreas\_Hegenberg](#):
>
> is it maybe included here?
> 
> `ioreg -r -c AppleDeviceManagementHIDEventService | grep Battery`

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

---

<div class="post-metadata">

**Author:** ![fortred2](https://community.folivora.ai/letter_avatar_proxy/v4/letter/f/e79b87/32.png) [@fortred2](https://community.folivora.ai/u/fortred2)\
**Post date:** [March 15, 2025, 10:08am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/7 "2025-03-15T10:08:45Z")

</div>

> [@MStankiewiczOfficial](#):
>
> 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.

1. Could you tell me how old your B&W Px7 S2 headphones are?
2. Are you able to see the battery level of your headphones using the official iOS app? [‎Music | Bowers & Wilkins on the App&nbsp;Store](https://apps.apple.com/us/app/music-bowers-wilkins/id1551992219). 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](https://www.andreasjakl.com/read-battery-level-bluetooth-le-devices/) b) [https://www.baeldung.com/linux/check-bluetooth-device-battery-level](https://www.baeldung.com/linux/check-bluetooth-device-battery-level)).
3. Dumb and genius question, have you restarted both your headphones and your Mac?

---

<div class="post-metadata">

**Author:** ![MStankiewiczOfficial](https://community.folivora.ai/user_avatar/community.folivora.ai/mstankiewiczofficial/32/30271_2.png) [@MStankiewiczOfficial](https://community.folivora.ai/u/MStankiewiczOfficial)\
**Post date:** [March 15, 2025, 10:22am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/8 "2025-03-15T10:22:52Z")

</div>

1. They are fairly new, about a month old.
2. 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.
3. Of course.

---

<div class="post-metadata">

**Author:** ![fortred2](https://community.folivora.ai/letter_avatar_proxy/v4/letter/f/e79b87/32.png) [@fortred2](https://community.folivora.ai/u/fortred2)\
**Post date:** [March 16, 2025, 12:03am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/9 "2025-03-16T00:03:51Z")

</div>

It's not easy to troubleshoot with you given I don't own Bowers & Wilkins headphones, but here is what I suggest doing:

1. Install this BLE sniffer app [‎BLE Scanner 4.0 on the App&nbsp;Store](https://apps.apple.com/us/app/ble-scanner-4-0/id1221763603).

2. Find your B&W Px7 S2 headphones listed from the nearby devices and connect to them.

3. Figure out which BLE service or characteristic contains the headphone battery level.

4. If that doesn't work, try using [GitHub - pybluez/pybluez: Bluetooth Python extension module](https://github.com/pybluez/pybluez) to obtain the battery level information.

---

<div class="post-metadata">

**Author:** ![MStankiewiczOfficial](https://community.folivora.ai/user_avatar/community.folivora.ai/mstankiewiczofficial/32/30271_2.png) [@MStankiewiczOfficial](https://community.folivora.ai/u/MStankiewiczOfficial)\
**Post date:** [March 16, 2025, 7:39am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/10 "2025-03-16T07:39:54Z")

</div>

I found it, but now I don't know what to do with it. AI hasn't helped. 😅

 ![obraz](https://community.folivora.ai/uploads/default/original/3X/9/a/9a5c6ec5f2be30ab6b23276426bf7a9fe78ad9fe.png)

---

<div class="post-metadata">

**Author:** ![fortred2](https://community.folivora.ai/letter_avatar_proxy/v4/letter/f/e79b87/32.png) [@fortred2](https://community.folivora.ai/u/fortred2)\
**Post date:** [March 16, 2025, 9:06am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/11 "2025-03-16T09:06:10Z")

</div>

> [@MStankiewiczOfficial](#):
>
> I found it, but now I don't know what to do with it. AI hasn't helped. 😅

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.

```python
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`.

---

<div class="post-metadata">

**Author:** ![MStankiewiczOfficial](https://community.folivora.ai/user_avatar/community.folivora.ai/mstankiewiczofficial/32/30271_2.png) [@MStankiewiczOfficial](https://community.folivora.ai/u/MStankiewiczOfficial)\
**Post date:** [March 17, 2025, 10:08am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/12 "2025-03-17T10:08:40Z")

</div>

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.

```auto
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'

```

---

<div class="post-metadata">

**Author:** ![fortred2](https://community.folivora.ai/letter_avatar_proxy/v4/letter/f/e79b87/32.png) [@fortred2](https://community.folivora.ai/u/fortred2)\
**Post date:** [March 17, 2025, 10:22pm UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/13 "2025-03-17T22:22:24Z")

</div>

This probably is a problem with your Python environment.

Relevant meme:

 ![image](https://community.folivora.ai/uploads/default/original/3X/e/6/e632496aac44399b354d6e081fe553d02990c60b.png)

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?

---

<div class="post-metadata">

**Author:** ![fortred2](https://community.folivora.ai/letter_avatar_proxy/v4/letter/f/e79b87/32.png) [@fortred2](https://community.folivora.ai/u/fortred2)\
**Post date:** [March 18, 2025, 7:16am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/14 "2025-03-18T07:16:43Z")

</div>

Also, make sure to install `asyncio` using `pip install asyncio`.

---

<div class="post-metadata">

**Author:** ![fortred2](https://community.folivora.ai/letter_avatar_proxy/v4/letter/f/e79b87/32.png) [@fortred2](https://community.folivora.ai/u/fortred2)\
**Post date:** [March 18, 2025, 7:19am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/15 "2025-03-18T07:19:10Z")

</div>

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`.

---

<div class="post-metadata">

**Author:** ![Andreas\_Hegenberg](https://community.folivora.ai/user_avatar/community.folivora.ai/andreas_hegenberg/32/39221_2.png) [@Andreas\_Hegenberg](https://community.folivora.ai/u/Andreas_Hegenberg)\
**Post date:** [March 18, 2025, 7:47am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/16 "2025-03-18T07:47:29Z")

</div>

Maybe it would be a good idea for me to add a "Read / Write Bluetooth LE Characteristic" action 😉

---

<div class="post-metadata">

**Author:** ![MStankiewiczOfficial](https://community.folivora.ai/user_avatar/community.folivora.ai/mstankiewiczofficial/32/30271_2.png) [@MStankiewiczOfficial](https://community.folivora.ai/u/MStankiewiczOfficial)\
**Post date:** [March 22, 2025, 8:39am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/17 "2025-03-22T08:39:32Z")

</div>

> [@fortred2](#):
>
> You should either use a more recent version of Python or run `pip install async_timeout`.

I did it and it still doesn't work – same error.

---

<div class="post-metadata">

**Author:** ![fortred2](https://community.folivora.ai/letter_avatar_proxy/v4/letter/f/e79b87/32.png) [@fortred2](https://community.folivora.ai/u/fortred2)\
**Post date:** [March 22, 2025, 9:12am UTC](https://community.folivora.ai/t/battery-level-of-bluetooth-headphones/42832/18 "2025-03-22T09:12:58Z")

</div>

> [@fortred2](#):
>
> 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)?

@MStankiewiczOfficial did you try this?
