pythonraspberry-pibluetoothraspberry-pi4

Controlling raspberry pi bluetooth with a python script


I have a Raspberry Pi 4 Model B running Raspberry Pi OS Lite 64-bit with

Operating System: Debian GNU/Linux 12 (Bookworm)
Kernel: Linux 6.6.20+rpt-rpi-v8.

I have to control the Bluetooth of the Raspberry with a Python script. The script has to be able to enable/disable Bluetooth and rename the Raspberry Pi.
I need to change the Bluetooth name automatically on the fly, because the Bluetooth name has to correspond to connected devices that can be hot-swapped

Currently, I use os.system(f"sudo hostnamectl set-hostname '{name}'") to rename the device and os.system(f"sudo systemctl restart bluetooth") to restart bluetooth.

This only works some of the time, and often times I manually have to enter more commands in the console:

pi@One:~ $ bluetoothctl
[bluetooth]# discoverable on
[bluetooth]# exit

Is there a more elegant solution to do this, that may also allow for more functionality?


Solution

  • The official Bluetooth stack on Linux is BlueZ which has an API that it provides and is documented at:
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc

    It looks like you want to change settings on the adapter and so those commands and properties are documented at:
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/org.bluez.Adapter.rst

    The BlueZ API uses Linux D-Bus bindings to enable the Python script to communicate with the RPi's Bluetooth daemon. This can have a steep learning curve if you haven't used it before.

    BlueZ provides examples of using the API at:
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test

    There are various Python libraries that help. The main ones are listed at:
    https://wiki.python.org/moin/DbusExamples

    The BlueZ examples use dbus-python library. However, for simple scripts I find the pydbus library easier to get started with.

    To install the pydbus library then you will need to install the following in to your venv:

    pip install PyGObject
    pip install pydbus
    

    An example of what it would look like to toggle the Discoverable property with a Python script:

    import pydbus
    
    bus_name = 'org.bluez'
    sys_bus = pydbus.SystemBus()
    
    dongle = sys_bus.get(bus_name, '/org/bluez/hci0')
    
    print(dongle.Alias, dongle.Name)
    print(dongle.Discoverable)
    
    if dongle.Discoverable:
        dongle.Discoverable = False
    else:
        dongle.Discoverable = True
    
    print(dongle.Discoverable)
    
    

    For the hierarchy of where BlueZ looks for the name of the device, take a look at the file /etc/bluetooth/main.conf for more information.

    From a Python script, the adapter Name is "readonly", but the Alias is "readwrite". Changing the Alias is often enough depending what you are looking to do. An example of this is:

    dongle.Alias = "MyNewName"