You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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接口需要权限,可通过以下两种方式配置:

  1. 将pi用户加入蓝牙组:

    sudo usermod -aG bluetooth pi
    

    重启系统生效。

  2. 添加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 16:23:17