如何用Python脚本优雅控制树莓派4B的蓝牙及设备重命名?
解决方案:基于BlueZ D-Bus接口的Python实现
针对树莓派4B(Debian 12 Bookworm 64位Lite)的蓝牙控制需求,推荐使用BlueZ官方的D-Bus原生接口实现功能,相比调用系统命令更稳定、高效,无需频繁重启蓝牙服务。
一、环境准备
- 安装依赖包:
sudo apt install python3-dbus python3-pyudev - 确保蓝牙服务正常运行:
sudo systemctl enable --now bluetooth
二、核心功能实现(Python脚本)
以下脚本集成蓝牙启禁用、动态重命名、可发现模式设置,以及热插拔设备监听功能:
import dbus import dbus.mainloop.glib from gi.repository import GLib import pyudev class BluetoothController: def __init__(self): # 初始化D-Bus系统总线 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) self.bus = dbus.SystemBus() # 获取默认蓝牙适配器路径 manager = dbus.Interface(self.bus.get_object('org.bluez', '/'), 'org.freedesktop.DBus.ObjectManager') objects = manager.GetManagedObjects() self.adapter_path = None for path, interfaces in objects.items(): if 'org.bluez.Adapter1' in interfaces: self.adapter_path = path break if not self.adapter_path: raise Exception("未找到蓝牙适配器") # 初始化适配器接口与属性接口 self.adapter = dbus.Interface(self.bus.get_object('org.bluez', self.adapter_path), 'org.bluez.Adapter1') self.props = dbus.Interface(self.bus.get_object('org.bluez', self.adapter_path), 'org.freedesktop.DBus.Properties') def toggle_power(self, enabled): """启用/禁用蓝牙""" self.props.Set('org.bluez.Adapter1', 'Powered', dbus.Boolean(enabled)) def update_name(self, new_name): """设置蓝牙别名(即时生效,无需重启服务)""" self.props.Set('org.bluez.Adapter1', 'Alias', dbus.String(new_name)) def set_discoverable(self, enabled, timeout=0): """设置可发现模式,timeout=0表示永久可发现""" self.props.Set('org.bluez.Adapter1', 'Discoverable', dbus.Boolean(enabled)) if timeout >= 0: self.props.Set('org.bluez.Adapter1', 'DiscoverableTimeout', dbus.UInt32(timeout)) def handle_hotplug_event(action, device): """处理热插拔设备事件,示例针对USB设备,可按需修改匹配规则""" if device.subsystem == 'usb' and action in ['add', 'remove']: device_name = device.get('ID_MODEL', 'UnknownDevice') try: bt_ctrl = BluetoothController() if action == 'add': new_bt_name = f"Pi-{device_name.replace(' ', '-')}" bt_ctrl.update_name(new_bt_name) bt_ctrl.set_discoverable(True) print(f"设备[{device_name}]已连接,蓝牙名称更新为[{new_bt_name}],可发现模式已开启") elif action == 'remove': bt_ctrl.update_name("RaspberryPi") bt_ctrl.set_discoverable(False) print(f"设备[{device_name}]已移除,蓝牙名称恢复为[RaspberryPi],可发现模式已关闭") except Exception as e: print(f"处理热插拔事件失败:{str(e)}") if __name__ == '__main__': # 初始化蓝牙控制器 try: BluetoothController() except Exception as e: print(f"蓝牙控制器初始化失败:{str(e)}") exit(1) # 初始化热插拔设备监听 context = pyudev.Context() monitor = pyudev.Monitor.from_netlink(context) monitor.filter_by(subsystem='usb') # 可修改为'block'监听存储设备等 observer = pyudev.MonitorObserver(monitor, handle_hotplug_event) observer.start() # 启动主循环保持脚本运行 loop = GLib.MainLoop() try: loop.run() except KeyboardInterrupt: loop.quit() print("脚本已终止")
三、权限配置
普通用户操作蓝牙D-Bus接口需要权限,可通过以下两种方式配置:
将pi用户加入蓝牙组:
sudo usermod -aG bluetooth pi重启系统生效。
添加Polkit规则允许pi用户操作蓝牙:
创建文件/etc/polkit-1/rules.d/50-bluetooth.rules:polkit.addRule(function(action, subject) { if (action.id.indexOf("org.bluez.") == 0 && subject.isInGroup("pi")) { return polkit.Result.YES; } });重启Polkit服务:
sudo systemctl restart polkit
四、简化替代方案(基于bluetoothctl交互)
如果不想使用D-Bus,可通过pexpect库自动化bluetoothctl交互,但稳定性略差:
- 安装依赖:
sudo apt install python3-pexpect - 示例代码:
import pexpect def set_bluetooth_alias(name): child = pexpect.spawn('bluetoothctl') child.expect(r'\[bluetooth\]# ') child.sendline(f'system-alias {name}') child.expect(r'\[bluetooth\]# ') child.sendline('exit') child.wait() def toggle_discoverable(enabled): child = pexpect.spawn('bluetoothctl') child.expect(r'\[bluetooth\]# ') child.sendline(f'discoverable {"on" if enabled else "off"}') child.expect(r'\[bluetooth\]# ') child.sendline('exit') child.wait()
内容的提问来源于stack exchange,提问作者Plat00n
相关产品推荐
相关产品推荐

