python - 使用 asyncio 在后台运行 bleak(python 库)
问题描述
我想使用 Python 中的 bleak 库从蓝牙低功耗设备接收数据。这部分正在工作。我现在的问题是,我不知道如何在后台或并行运行此代码。
最终,我想构建一个处理蓝牙设备数据的小型 python 应用程序。所以 bleak 一直在循环从蓝牙设备获取数据并将其发送到处理和显示数据的主进程。
出于某种原因,bleak 不会在线程中运行。是否可以为此使用 asyncio (因为它已经被 bleak 使用了,这可能是一个好方法)?
我检查了线程和多处理,但不知何故,我只发现了没有无限循环并发送数据的进程的示例。我对并行化和/或异步进程的主题完全陌生。也许你们中的一个人可以提示在哪里寻找适合这种情况的解决方案。
下面是我到目前为止的代码(现在我只是循环和打印数据)。
from bleak import BleakClient
import json
import time
current_index = 0
time_array = [0] * 20
def TicTocGenerator():
# Generator that returns time differences
ti = 0 # initial time
tf = time.time() # final time
while True:
ti = tf
tf = time.time()
yield tf-ti # returns the time difference
TicToc = TicTocGenerator() # create an instance of the TicTocGen generator
# This will be the main function through which we define both tic() and toc()
def toc(tempBool=True):
# Prints the time difference yielded by generator instance TicToc
tempTimeInterval = next(TicToc)
global current_index
if tempBool:
#print( "Elapsed time: %f seconds.\n" %tempTimeInterval )
time_array[current_index] = tempTimeInterval
if current_index == 19:
current_index = 0
else:
current_index += 1
def tic():
# Records a time in TicToc, marks the beginning of a time interval
toc(False)
def Average(lst):
return sum(lst) / len(lst)
#address = "30:ae:a4:5d:bc:ba"
address = "CCA9907B-10EA-411E-9816-A5E247DCA0C7"
MODEL_NBR_UUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8"
async def run(address, loop):
async with BleakClient(address, loop=loop) as client:
while True:
tic()
model_number = await client.read_gatt_char(MODEL_NBR_UUID)
toc()
json_payload=json.loads(model_number)
print()
print(json_payload)
print("Temp [°C]: "+"{:.2f}".format(json_payload["Temp"]))
print("Volt [V]: "+"{:.2f}".format(json_payload["Volt"]))
print("AngX: "+str(json_payload["AngX"]))
print("AngY: "+str(json_payload["AngY"]))
print("AngZ: "+str(json_payload["AngZ"]))
#print("Millis: {0}".format("".join(map(chr, model_number))))
print("Average [ms]: {:.1f}".format(Average(time_array)*1000))
loop = asyncio.get_event_loop()
loop.run_until_complete(run(address, loop))
解决方案
我必须为在多个 BLE 设备上自动化 FUOTA 的应用程序制作 GUI,所以我的解决方案是将 bleak loop 放在单独的线程中,以便能够在主线程中使用 tkinter mainloop。您需要使用 asyncio.run_coroutine_threadsafe 从主线程安排新任务。
from threading import Thread
import tkinter as tk
from Bleak import BleakScanner
async def scan():
device = await BleakScanner.discover()
for device in devices:
print(device)
def startScan():
# call startScan() from main thread
asyncio.run_coroutine_threadsafe(scan(), loop)
if __name__ == "__main__":
window = tk.Tk()
# ...
loop = asyncio.get_event_loop()
def bleak_thread(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
t = Thread(target=bleak_thread, args=(loop,))
t.start()
window.mainloop()
loop.call_soon_threadsafe(loop.stop)
推荐阅读
- java - Thymeleaf + Spring MVC - 使用复选框输入时 Thymeleaf 模板解析错误
- java - Kotlin java.lang.NoSuchMethodException:
() - r - 有效地将数据帧中的两列或多列转换为逐行的向量列表
- grafana - Grafana 7:如何隐藏表列但仍在数据链接中使用其值
- javascript - 如何解决这个问题?页面转换的 GSAP 动画只有第一次才能完美工作
- dax - PowerPivot 计数重复项
- c - 在c中使用嵌套结构、数组和循环
- python - 如何将此 html 数据存储回另一个数据库
- android - 如何知道电话中的哪些联系人使用我们的应用程序
- angular - 带有导航栏的 Angular 登录页面 - 事件顺序问题