Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pbutils

Linux utilities for Google Pixel Buds — battery monitor and desktop notification widget. Supports Pixel Buds Pro 2, Pixel Buds Pro, and Pixel Buds A-Series on any Linux desktop running dunst.

Pixel Buds Pro connected, ANC on, left 85%, case 34%, right 87%

Supported devices

Model Battery monitoring ANC display
Pixel Buds Pro 2 (2024)
Pixel Buds Pro (2022)
Pixel Buds A-Series (2021)
Pixel Buds (2020) untested untested
Pixel Buds (2017, wired)

✓ confirmed · — hardware doesn't support this feature · ✗ protocol not supported · untested = reports welcome (see Contributing)

How it works

The project is two programs that work together:

pbwatch is a background daemon. It opens an RFCOMM connection to your buds on Bluetooth channel 2 and speaks the Google Fast Pair Message Stream protocol to read battery levels, charging state, bud placement, and ANC mode. Whenever any of that changes, it writes the new state to flat files under $XDG_RUNTIME_DIR/pbwatch/ and runs a configurable command — by default pbwidget.

pbwidget is that command. It reads the state files pbwatch wrote, looks up the device name via BlueZ, renders a PNG using pycairo, and fires a dunst notification. It is entirely stateless: it reads, renders, and exits. You can replace it with any script of your own using pbwatch's --on-update flag.

Pixel Buds ──RFCOMM──▶ pbwatch ──state files──▶ pbwidget ──PNG──▶ dunst
                           │
                           └──▶ --on-update / --on-disconnect (any command)

pbwatch runs as a systemd user service and reconnects automatically if the buds disconnect or go back in the case.

pbwatch

pbwatch is configured entirely via CLI flags. There is no config file.

Flag Default Description
--mac MAC (required) Bluetooth MAC address of your buds (e.g. AB:CD:EF:01:23:45)
--on-update CMD pbwidget Command run on battery, ANC, or placement change
--on-disconnect CMD pbwidget --disconnected Command run when the buds disconnect
--heal-audio off Wait for WirePlumber to register the BT sink and switch to A2DP on connect
--debug off Print raw RFCOMM messages to stdout (useful for bug reports)

State files written to $XDG_RUNTIME_DIR/pbwatch/:

  • battery — key=value pairs: left, left_charging, right, right_charging, case, case_charging. Values are percentages (0–100) or -1 if the component is not present (e.g. a bud is in the case).
  • anc — two lines: the active mode on line 1 (noise_cancellation, off, transparency, or adaptive), comma-separated supported modes on line 2.

Any script that reads these files can serve as a custom --on-update handler.

pbwidget

pbwidget reads pbwatch's state files and renders a dunst notification. It is configured via ~/.pbwidget (copy from pbwidget.conf.example).

Key Default Description
DEVICE_MAC (empty) Bluetooth MAC; used only to look up the device name via BlueZ for the title. Optional — set DEVICE_LABEL instead if you prefer a fixed label.
DEVICE_LABEL (empty) Fixed label shown at the top of the widget. If empty, uses the device's Bluetooth alias (bluetoothctl set-alias "My Buds" to customise it).
BG_COLOR #1e1e2e Background colour
TEXT_COLOR #cdd6f4 Text and percentage labels
ACCENT_COLOR #89b4fa Highlight colour for the active ANC mode
RING_COLOR #ffffff20 Battery gauge track (8-digit hex = with alpha)
OPACITY 0.0 Background opacity: 0.0 is fully transparent, 1.0 is solid
AUTO_CLOSE 5000 Milliseconds before the notification dismisses itself (0 = stays until clicked)
IMAGE_SIZE 300 Width of the notification image in pixels
ICON_THEME hicolor Icon theme for battery and ear icons. hicolor works everywhere; richer options: Yaru (Ubuntu), Adwaita (GNOME), breeze (KDE)
BATTERY_WARN 50 Gauge arc turns yellow below this percentage
BATTERY_CRITICAL 10 Gauge arc turns red below this percentage
ANC_ADAPTIVE auto Whether to show the Adaptive ANC button: auto reads device capabilities, true always shows it, false hides it

pbwidget can be run at any time, not only from pbwatch — as long as the state files exist the notification will render correctly. Calling pbwidget --disconnected renders a "disconnected" screen instead.

Install

sudo apt install python3-cairo python3-gi gir1.2-rsvg-2.0 python3-pil python3-dbus dunst bluez dbus yaru-theme-icon
git clone https://github.com/yom/pbutils.git
cd pbutils
./install.sh

The script copies pbwatch and pbwidget to /usr/local/bin/ (requires sudo), generates the sprite sheet, copies the example config to ~/.pbwidget, enables the pbwatch systemd user service, and patches ~/.config/dunst/dunstrc with the required [pbwidget] display rule. If dunstrc doesn't exist yet it prints the block for you to add manually.

After install, set your Pixel Buds MAC address:

# Find your MAC:
bluetoothctl devices

# Edit the service file and set --mac:
$EDITOR ~/.config/systemd/user/pbwatch.service

# Apply the change:
systemctl --user restart pbwatch

Customising pbwatch

To change pbwatch's flags (on-update command, heal-audio, etc.) without editing the installed service file directly, use a systemd override — this survives reinstalls:

systemctl --user edit pbwatch

Add a block like this (the blank ExecStart= clears the original value before setting the new one):

[Service]
ExecStart=
ExecStart=/usr/local/bin/pbwatch --mac AB:CD:EF:01:23:45 --on-update "my-script" --on-disconnect "my-script --disconnected"

Troubleshooting

Audio doesn't switch to the buds when they connect. Enable --heal-audio. pbwatch will wait for WirePlumber to register the Bluetooth sink, switch the card profile to A2DP, and set it as the default output. If the sink never appears it restarts WirePlumber automatically (you'll see a brief "Audio routing failed" notification). Add it via a systemd override:

systemctl --user edit pbwatch
[Service]
ExecStart=
ExecStart=/usr/local/bin/pbwatch --mac AB:CD:EF:01:23:45 --heal-audio

pulseaudio-utils and wireplumber must be installed for this to work: sudo apt install pulseaudio-utils wireplumber.

The widget stops updating.

systemctl --user status pbwatch
journalctl --user -u pbwatch -n 30

Battery or ear icons are missing. The hicolor theme is a minimal fallback. Set ICON_THEME in ~/.pbwidget to a theme you have installed — e.g. Yaru on Ubuntu (sudo apt install yaru-theme-icon), Adwaita on GNOME, or breeze on KDE.

Contributing

Bug reports, compatibility reports, and feature requests are welcome on the GitHub Issues page.

Compatibility reports are especially useful. If you own a Pixel Buds model listed as untested above, please open an issue with the result — even a "works fine" comment helps confirm coverage. To attach useful diagnostic data, run pbwatch with --debug and grab the output:

journalctl --user -u pbwatch -f

Then paste the relevant lines (connect event + a few message lines) into your issue.

References

Protocol specifications, BlueZ D-Bus API docs, and the Rust reference implementation used to build this project are documented in REFERENCES.md.

About

Linux battery monitor and desktop notification widget for Google Pixel Buds Pro, Pro 2 and A-Series

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages