Source code for i3pystatus.bluetooth

from os.path import basename

import dbus

from i3pystatus import IntervalModule, formatp
from i3pystatus.core.util import TimeWrapper


def proxyobj(bus, path, interface):
    """ commodity to apply an interface to a proxy object """
    obj = bus.get_object('org.bluez', path)
    return dbus.Interface(obj, interface)


def filter_by_interface(objects, interface_name):
    """ filters the objects based on their support
        for the specified interface """
    result = []
    for path in objects.keys():
        interfaces = objects[path]
        for interface in interfaces.keys():
            if interface == interface_name:
                result.append(path)
    return result


def getprop(obj, prop, t):
    return t(obj.Get("org.bluez.Device1", prop))


def get_bluetooth_device_list(show_disconnected):
    # shamelessly stolen from https://stackoverflow.com/questions/14262315/list-nearby-discoverable-bluetooth-devices-including-already-paired-in-python/14267310#14267310
    bus = dbus.SystemBus()

    # we need a dbus object manager
    manager = proxyobj(bus, "/", "org.freedesktop.DBus.ObjectManager")
    objects = manager.GetManagedObjects()

    # once we get the objects we have to pick the bluetooth devices.
    # They support the org.bluez.Device1 interface
    devices = filter_by_interface(objects, "org.bluez.Device1")

    # now we are ready to get the informations we need
    bt_devices = []
    for device in devices:
        obj = proxyobj(bus, device, 'org.freedesktop.DBus.Properties')
        # skip blocked and unpaired devices.
        if getprop(obj, "Blocked", bool):
            continue
        if not getprop(obj, "Paired", bool):
            continue
        if not show_disconnected:
            if not getprop(obj, "Connected", bool):
                continue
        bt_devices.append({
            "name": getprop(obj, "Name", str),
            "dev_addr": getprop(obj, "Address", str),
            "connected": getprop(obj, "Connected", bool)
        })
    return bt_devices


[docs]class Bluetooth(IntervalModule): """ Shows currently connected bluetooth devices. * Requires ``python-dbus`` from your distro package manager, or \ ``dbus-python`` from PyPI. Left click on the module to cycle forwards through devices, and right \ click to cycle backwards. .. rubric:: Available formatters (uses :ref:`formatp`) * `{name}` — (the name of the device) * `{dev_addr}` — (the bluetooth device address) .. rubric:: Available callbacks * ``next_device`` — iterate forward through devices * ``prev_device`` — iterate backwards through devices Example module registration with callbacks: :: status.register("now_playing", on_leftclick="next_device", on_rightclick="prev_device", on_upscroll="next_device", on_downscroll="prev_device") """ interval = 1 settings = ( ("format", "formatp string"), ("color", "Text color"), ("connected_color", "Connected device color"), ("show_disconnected", "Show disconnected but paired devices") ) format = "{name}: {dev_addr}" color = "#ffffff" connected_color = "#00ff00" on_leftclick = "next_device" on_rightclick = "prev_device" on_upscroll = 'next_device' on_downscroll = 'prev_device' num_devices = 0 dev_index = 0 devices = [] show_disconnected = True def run(self): try: self.devices = get_bluetooth_device_list(self.show_disconnected) if len(self.devices) < 1: if hasattr(self, "data"): del self.data self.output = None return self.dev_index = self.dev_index % len(self.devices) self.num_devices = len(self.devices) fdict = { "name": self.devices[self.dev_index]['name'], "dev_addr": self.devices[self.dev_index]['dev_addr'] } self.data = fdict color = self.color if self.devices[self.dev_index]['connected']: color = self.connected_color self.output = { "full_text": formatp(self.format, **fdict).strip(), "color": color, } return except dbus.exceptions.DBusException as e: self.output = { "full_text": "DBus error: " + e.get_dbus_message(), "color": "#ff0000", } if hasattr(self, "data"): del self.data return def next_device(self): self.dev_index = (self.dev_index + 1) % self.num_devices def prev_device(self): self.dev_index = (self.dev_index - 1) % self.num_devices