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

求助:基于树莓派+Tkinter开发蓝牙扫描界面及配对连接功能

树莓派蓝牙连接应用开发求助:扫描展示、配对与连接功能实现

我正在使用Python bluetooth模块搭配Tkinter开发一款蓝牙连接应用,现寻求技术支持,在树莓派上实现蓝牙设备扫描界面,将扫描到的设备以列表形式展示在界面中,同时希望添加设备配对与连接功能。

当前代码

import time
from time import sleep
import serial
import bluetooth
import sys
import tkinter as tk
import tkinter.font as font 

from tkinter import *
from tkinter import  ttk
from tkinter import messagebox
from tkinter import scrolledtext

import datetime
now = datetime.datetime.now()

main_window = tk.Tk()

main_window.title('Scan for nearby Bluetooth devices')

#changes the size of the screens window
window_width = 900
window_height = 500

screen_width = main_window.winfo_screenwidth()
screen_height = main_window.winfo_screenheight()

center_x = int(screen_width/2 - window_width / 2)
center_y = int(screen_height/2 - window_height / 2)

main_window.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')


main_window.grid_columnconfigure(1, weight=1)
main_window.grid_rowconfigure(1, weight=1)


text = tk.Text(main_window, height=30, width=30)
text.grid(row=1, column=1, sticky=tk.EW)

def get_time():
    return now.strftime('%H:%M:%S')

text.insert('1.0','The time of the scan: ' + str(get_time()) + '\n\n')

def button_clicked():
    
    text['state'] = 'normal'

    now = datetime.datetime.now()

    def get_time():
        return now.strftime('%H:%M:%S')

    print()

    text.delete('0.0', tk.END)
    
    print("Scanning")  
    nearby_devices = bluetooth.discover_devices(lookup_names=True)
    print("Found {} devices.".format(len(nearby_devices)))

    for addr, name in nearby_devices:
        print("  {} - {}".format(addr, name))
    return 
      
    text.insert('1.0','The time of the scan: ' + str(get_time()) + '\n\n')

    text.insert('0.0', 'Amount of devices found: ' + str(len(out)) + '\n\n')

    text['state'] = 'disabled'

main_button = ttk.Button(
    main_window,
    text='Scan again',
    command=lambda: button_clicked()
)

main_button.grid(row=0, column=1, sticky=tk.EW)

exit_button = ttk.Button(
    main_window,
    text='Exit',
    command=lambda: main_window.quit()
)

exit_button.grid(row=2, column=1, sticky=tk.EW)

text['state'] = 'disabled'

main_window.mainloop()

问题修复与功能实现方案

1. 修复扫描结果不显示的问题

原代码中button_clicked函数在打印扫描结果后直接return,导致后续插入文本到界面的代码无法执行,需删除该多余的return。

2. 改用Listbox展示设备列表

将原Text控件替换为Listbox,方便后续选中单个设备执行配对、连接操作。

3. 添加配对与连接功能

由于Python bluetooth模块在树莓派上的配对支持有限,这里通过调用系统bluetoothctl命令实现配对和连接,树莓派默认已预装bluez工具包(依赖此工具)。

修改后的完整代码

import time
import bluetooth
import tkinter as tk
from tkinter import ttk, messagebox
import datetime
import subprocess

main_window = tk.Tk()
main_window.title('蓝牙设备扫描与管理')

# 设置窗口大小并居中
window_width = 900
window_height = 500
screen_width = main_window.winfo_screenwidth()
screen_height = main_window.winfo_screenheight()
center_x = int(screen_width/2 - window_width / 2)
center_y = int(screen_height/2 - window_height / 2)
main_window.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')

# 网格布局配置
main_window.grid_columnconfigure(1, weight=1)
main_window.grid_rowconfigure(1, weight=1)

# 设备列表展示控件
device_list = tk.Listbox(main_window, height=30, width=80)
device_list.grid(row=1, column=1, sticky=tk.EW)

# 存储扫描到的设备(显示文本:地址)
scanned_devices = {}

def get_current_time():
    return datetime.datetime.now().strftime('%H:%M:%S')

def scan_devices():
    device_list.delete(0, tk.END)
    scanned_devices.clear()
    
    # 记录扫描时间
    scan_time = get_current_time()
    print(f"[{scan_time}] 开始扫描蓝牙设备...")
    
    # 扫描附近蓝牙设备
    try:
        nearby_devices = bluetooth.discover_devices(lookup_names=True, duration=8)
        print(f"找到 {len(nearby_devices)} 个设备")
        
        # 将设备添加到列表和字典
        for addr, name in nearby_devices:
            display_text = f"{name} - {addr}"
            device_list.insert(tk.END, display_text)
            scanned_devices[display_text] = addr
            
        # 显示扫描信息
        device_list.insert(0, f"扫描时间: {scan_time} | 找到设备: {len(nearby_devices)} 个")
    except Exception as e:
        messagebox.showerror("扫描错误", f"扫描失败: {str(e)}")

def pair_device():
    selected = device_list.curselection()
    if not selected:
        messagebox.warning("提示", "请先选择一个设备")
        return
    
    selected_text = device_list.get(selected[0])
    if "扫描时间" in selected_text:
        messagebox.warning("提示", "请选择具体设备")
        return
    
    device_addr = scanned_devices[selected_text]
    
    # 调用bluetoothctl进行配对
    try:
        proc = subprocess.Popen(
            ["bluetoothctl"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        proc.stdin.write(f"pair {device_addr}\n")
        proc.stdin.flush()
        # 等待配对操作(若设备需PIN码,需手动在终端输入,可扩展GUI输入框)
        time.sleep(5)
        proc.stdin.write("quit\n")
        proc.stdin.flush()
        
        stdout, stderr = proc.communicate()
        if "Pairing successful" in stdout:
            messagebox.showinfo("成功", "设备配对成功")
        else:
            messagebox.showerror("配对失败", f"错误信息: {stderr.strip()}")
    except Exception as e:
        messagebox.showerror("配对错误", f"配对过程出错: {str(e)}")

def connect_device():
    selected = device_list.curselection()
    if not selected:
        messagebox.warning("提示", "请先选择一个设备")
        return
    
    selected_text = device_list.get(selected[0])
    if "扫描时间" in selected_text:
        messagebox.warning("提示", "请选择具体设备")
        return
    
    device_addr = scanned_devices[selected_text]
    
    # 调用bluetoothctl进行连接
    try:
        proc = subprocess.Popen(
            ["bluetoothctl"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        proc.stdin.write(f"connect {device_addr}\n")
        proc.stdin.flush()
        time.sleep(3)
        proc.stdin.write("quit\n")
        proc.stdin.flush()
        
        stdout, stderr = proc.communicate()
        if "Connection successful" in stdout:
            messagebox.showinfo("成功", "设备连接成功")
        else:
            messagebox.showerror("连接失败", f"错误信息: {stderr.strip()}")
    except Exception as e:
        messagebox.showerror("连接错误", f"连接过程出错: {str(e)}")

# 按钮控件
scan_btn = ttk.Button(main_window, text='扫描设备', command=scan_devices)
scan_btn.grid(row=0, column=1, sticky=tk.EW, padx=5, pady=5)

pair_btn = ttk.Button(main_window, text='配对选中设备', command=pair_device)
pair_btn.grid(row=2, column=0, sticky=tk.EW, padx=5, pady=5)

connect_btn = ttk.Button(main_window, text='连接选中设备', command=connect_device)
connect_btn.grid(row=2, column=2, sticky=tk.EW, padx=5, pady=5)

exit_btn = ttk.Button(main_window, text='退出', command=main_window.quit)
exit_btn.grid(row=3, column=1, sticky=tk.EW, padx=5, pady=5)

# 程序启动时自动扫描一次设备
scan_devices()

main_window.mainloop()

说明

  • 程序启动后会自动执行一次设备扫描
  • 选中列表中的设备后,可点击对应按钮完成配对或连接操作
  • 若配对需要PIN码,当前版本需手动在终端输入,可根据需求扩展GUI PIN码输入功能
  • 确保树莓派蓝牙已开启,可通过bluetoothctl power on命令开启

内容的提问来源于stack exchange,提问作者Depua

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 11:10:40