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

Tkinter+Bleak异步开发问题:无法实时回传设备RSSI至GUI

问题修复方案:Bleak实时回传RSSI到Tkinter GUI

核心问题分析

  1. 异步线程执行逻辑错误:你继承threading.Thread后将run定义为async函数,但threading.Thread不支持异步协程调度,导致扫描回调无法实时触发,仅在扫描结束后一次性返回结果。
  2. RSSI值获取方式错误:advertisement_data是AdvertisementData对象而非元组,用索引[5]取值是错误的,需直接访问对象属性。

修复后的线程代码

import threading
import asyncio
from bleak import BleakScanner, BLEDevice, AdvertisementData

class MonThread(threading.Thread):
    def __init__(self, win):
        super().__init__()
        self.win = win  
        self._stop_event = threading.Event()  # 用于控制扫描启停

    async def callback(self, device: BLEDevice, advertisement_data: AdvertisementData):
        # 过滤指定MAC地址的设备
        if device.address == "AB:7E:48:E7:EE:1F":
            print('Name : ', advertisement_data.local_name)  # 正确获取设备名称
            rssi_value = advertisement_data.rssi  # 正确获取RSSI数值
            print('Signal : ', rssi_value)
            # 发送事件通知GUI更新
            self.win.event_generate("<<UpdateRSSI>>", x=rssi_value)

    async def scan_loop(self):
        scanner = BleakScanner(self.callback)
        await scanner.start()
        # 持续扫描直到收到停止信号
        while not self._stop_event.is_set():
            await asyncio.sleep(0.1)
        await scanner.stop()

    def run(self):
        # 在子线程中启动独立的asyncio事件循环
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self.scan_loop())

    def stop(self):
        # 触发停止信号,终止扫描循环
        self._stop_event.set()

修复后的GUI代码

import tkinter as tk

def lance_thread():
    global scan_thread
    scan_thread = MonThread(root)
    scan_thread.start()

def update_rssi(e):
    # 更新RSSI显示标签
    message2.config(text=str(e.x))

root = tk.Tk()
root.title("Analyzer")
root.geometry('600x400+100+100')
root.resizable(True, True)
root.config(relief=tk.RAISED, bd=3) 

b = tk.Button(text="Scan", command=lance_thread)
b.pack()
frameH = tk.Frame(root, width=200, height=80, background="bisque", relief=tk.GROOVE, bd=6, padx=20, pady=20)
frameH.pack(anchor="nw", padx=10, pady=10, fill="x")

message = tk.Label(frameH, text="RSSI : ", height=2, padx=50, background="bisque")
message.grid(row=0, column=1)
message2 = tk.Label(frameH, text="---", height=2)
message2.grid(row=0, column=9)

root.bind("<<UpdateRSSI>>", update_rssi)

# 窗口关闭时停止扫描线程,避免资源泄漏
def on_closing():
    if 'scan_thread' in globals() and scan_thread.is_alive():
        scan_thread.stop()
        scan_thread.join()
    root.destroy()

root.protocol("WM_DELETE_WINDOW", on_closing)

root.mainloop()

关键修复说明

  • 异步协程正确调度:在子线程中创建独立的asyncio事件循环,确保扫描回调能实时触发并推送RSSI值。
  • 属性化获取设备数据:通过advertisement_data.rssi和advertisement_data.local_name直接访问设备参数,避免类型错误。
  • 可控扫描循环:添加停止事件,支持主动终止扫描,避免程序退出时线程残留。
  • 语义化事件命名:将事件名改为<<UpdateRSSI>>,更贴合实时更新的业务逻辑。

内容的提问来源于stack exchange,提问作者François HEBERT

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 05:04:55