Skip to content

Instantly share code, notes, and snippets.

@ralt
Last active July 6, 2019 22:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ralt/b25095dcc1be680e581a9a53f2edcb43 to your computer and use it in GitHub Desktop.
Save ralt/b25095dcc1be680e581a9a53f2edcb43 to your computer and use it in GitHub Desktop.
How to make bluetooth flawless in gnome shell
#!/usr/bin/env bash
# This shell script setups bluetooth to be flawless in gnome shell.
# Devices are now instantly connected when they're near the laptop.
# (It probably works as a service for random WMs too.)
# The issue is essentially that gnome-bluetooth is issuing the wrong
# dbus calls to connect the device immediately; org.bluez gets EAGAIN
# from the kernel when it processes gnome-bluetooth dbus calls (until
# it eventually succeeds, 20-30s later). However, bluetoothctl is
# flawless at it. Maybe some day gnome-bluetooth will fix this. In the
# meantime, this hack lets me have a seamless bluetooth experience.
# PS: I tried to report the bug to gnome-bluetooth but haven't figured
# out how. Apparently I need to register to 2 or 3 bug trackers? I may
# just be dense.
# To be able to run this hack, you need: bluez (which provides the
# bluetoothctl binary) and python3-gevent.
# Source: https://gist.github.com/ralt/b25095dcc1be680e581a9a53f2edcb43
# License: MIT (is that even needed for such a small amount of code?)
set -e
# Start with checking the requirements.
python3 -c 'import gevent' &> /dev/null || echo 'You need python3-gevent' && exit 1
which bluetoothctl &> /dev/null || echo 'You need bluez (for bluetoothctl)' && exit 1
# And now the fun begins.
cd ~
# Create a systemd user service for our hack.
cat > .config/systemd/user/fix-bluetooth.service <<EOF
[Unit]
Description=Fix bluetooth
[Service]
ExecStart=/home/$USER/bin/fix-bluetooth
[Install]
WantedBy=default.target
EOF
# Now put the hack in the ~/bin folder.
mkdir -p bin
cat > bin/fix-bluetooth <<EOF
#!/usr/bin/env python3
import gevent.monkey
gevent.monkey.patch_all()
import subprocess
import time
import gevent
def _refresh(device):
while True:
try:
subprocess.check_call(["bluetoothctl", "connect", device])
except subprocess.CalledProcessError:
time.sleep(1)
else:
time.sleep(10)
if __name__ == "__main__":
refreshers = {}
while True:
out = subprocess.check_output(["bluetoothctl", "devices"])
devices = []
for line in out.splitlines():
try:
_, device, _ = line.split(b" ", 2)
except ValueError:
continue
devices.append(device)
for device in devices:
if device not in refreshers:
print("Taking care of device: {}".format(device))
refreshers[device] = gevent.spawn(_refresh, device)
delete = []
for device in refreshers:
if device not in devices:
print("Forgetting about device: {}".format(device))
refreshers[device].kill()
delete.append(device)
for device in delete:
del refreshers[device]
time.sleep(60)
EOF
# Don't forget this or you look stupid.
chmod +x bin/fix-bluetooth
# Finally, enable and start our systemd user service.
systemctl --user enable fix-bluetooth
systemctl --user start fix-bluetooth
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment