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?
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"