How do I run a script when a Bluetooth device connects?
I didn't like the polling approach, so I did some digging on bluez and DBus. I ended up writing the following script:
#!/usr/bin/python
import dbus
from dbus.mainloop.glib import DBusGMainLoop
import gobject
import subprocess
# ID of the device we care about
DEV_ID = '00_1D_54_AB_DC_72'
dbus_loop = DBusGMainLoop()
bus = dbus.SystemBus(mainloop=dbus_loop)
# Figure out the path to the headset
man = bus.get_object('org.bluez', '/')
iface = dbus.Interface(man, 'org.bluez.Manager')
adapterPath = iface.DefaultAdapter()
headset = bus.get_object('org.bluez', adapterPath + '/dev_' + DEV_ID)
# ^^^ I'm not sure if that's kosher. But it works.
def cb(iface=None, mbr=None, path=None):
if ("org.bluez.Headset" == iface and path.find(DEV_ID) > -1):
print 'iface: %s' % iface
print 'mbr: %s' % mbr
print 'path: %s' % path
print "\n"
print "matched"
if mbr == "Connected":
subprocess.call(["clementine", "--play"])
print 'conn'
elif mbr == "Disconnected":
subprocess.call(["clementine", "--stop"])
print 'dconn'
headset.connect_to_signal("Connected", cb, interface_keyword='iface', member_keyword='mbr', path_keyword='path')
headset.connect_to_signal("Disconnected", cb, interface_keyword='iface', member_keyword='mbr', path_keyword='path')
loop = gobject.MainLoop()
loop.run()
To discover a successfully established Bluetooth connection we can run
sdptool browse xx:xx:xx:xx:xx:xx
By this the SDB connection will be tested for a connection to the given MAC address. It may take considerable time until browsing times out with an error like
Failed to connect to SDP server on 00:0C:78:4F:B6:B5: Host is down
We don't know the exact purpose of your script, but most likely you wish to play audio via Clementine when a headset was connected.
Then we could just see whether there is a Bluetooth audio sink with
pacmd list-sinks | grep xx_xx_xx_xx_xx_xx
Where xx_xx_xx_xx_xx_xx
is the MAC address (:
needs to be replaced with _
). The output will then tell you whether there is a Bluetooth audio sink available or nothing if not.
See this answer on how to switch audio to this sink.
Stream2ip
With stream2ip we can define a shell command or a script to run after a connection was established. There also is an option to automatically start a supported media player after a connection was established:
Stream2ip will also try to reconnect the currently running playback stream to the Bluetooth audio device in case the connection was interrupted.
@Erigami Your answer helped a lot but to make it work I'd to do some changes. I'm using ubuntu 14.04.
#!/usr/bin/python
import dbus
from dbus.mainloop.glib import DBusGMainLoop
import gobject
import subprocess
# ID of the device we care about
DEV_ID = 'CC:C3:EA:A5:16:90'.replace(":", "_")
dbus_loop = DBusGMainLoop()
bus = dbus.SystemBus(mainloop=dbus_loop)
# Figure out the path to the headset
man = bus.get_object('org.bluez', '/')
iface = dbus.Interface(man, 'org.bluez.Manager')
adapterPath = iface.DefaultAdapter()
print(adapterPath + '/dev_' + DEV_ID)
headset = bus.get_object('org.bluez', adapterPath + '/dev_' + DEV_ID)
# ^^^ I'm not sure if that's kosher. But it works.
def cb(*args, **kwargs):
is_connected = args[-1]
if isinstance(is_connected, dbus.Boolean) and is_connected:
print("Connected")
elif isinstance(is_connected, dbus.Boolean) and not is_connected:
print("Disconnected")
headset.connect_to_signal("PropertyChanged", cb, interface_keyword='iface', member_keyword='mbr', path_keyword='path')
loop = gobject.MainLoop()
loop.run()
Still if this does not work then use and monitor system dbus.
dbus-monitor --system
d-feet
can be used further. It is GUI tool to watch dbus objects.