如何将 nRF Connect(适用于 Android)操作模拟到 Pygatt 脚本?
Posted
技术标签:
【中文标题】如何将 nRF Connect(适用于 Android)操作模拟到 Pygatt 脚本?【英文标题】:How to Mimic nRF Connect (for Android) Actions to Pygatt Script? 【发布时间】:2020-01-25 21:08:35 【问题描述】:我正在使用 nRF Connect for android 来测试 BLE 外围设备。外围设备是 BSX Insight 残余肌肉氧监测仪,其软件应用程序不再起作用或不受制造商支持。因此,我使用我的设备 (BSX) 的唯一选择是编写我自己的控制软件。我编写了一个 Python 3.7 脚本,在我的 64 位 Win 10 笔记本电脑上的 tkinter 例程中运行。另外,我正在使用 Pygatt 库和 BLED112 BT 加密狗。
我可以连接到外围设备,读取和写入特性值,但我确信从 nRF Connect 中使用的进程到我的脚本的“转换”是不完整且低效的。所以我想确认的第一件事是使用了来自 Pygatt 的正确的相应函数。一旦我使用了 Pygatt 的正确函数,我就可以比较我想要捕获和存储的两个数据(特征值)流的各自输出。
nRF Connect 中的基本流程: 1.扫描 2. 选择/连接 BSX Insight 3. 公开感兴趣的服务和特征 4. 启用 CCCD 5.写入“起始数据”值(04-02)
这些是来自 nRF Connect 日志文件的进程命令结果。从第四个开始: 4. D 09:04:54.491 gatt.setCharacteristicNotification(00002a37-0000-1000-8000-00805f9b34fb,真)11 D 09:04:54.496 gatt.setCharacteristicNotification(2e4ee00b-d9f0-5490-ff4b-d17374c433ef, true) 20x D 09:04:54.499 gatt.setCharacteristicNotification(2e4ee00d-d9f0-5490-ff4b-d17374c433ef, true) 25x D 09:04:54.516 gatt.setCharacteristicNotification(2e4ee00e-d9f0-5490-ff4b-d17374c433ef, true) 32x D 09:04:54.519 gatt.setCharacteristicNotification(00002a63-0000-1000-8000-00805f9b34fb, true) 36 D 09:04:54.523 gatt.setCharacteristicNotification(00002a53-0000-1000-8000-00805f9b34fb, true) 40
以上结果是使用 nRF 命令“启用 CCCD”造成的。基本上每个可以启用的特性都被启用了,这很好。 'x' 是我需要启用的三个。其他都是额外的。请注意,我已在行尾注释了这些 UUID 的相应句柄。
-
V 09:05:39.211 将命令写入特征 2e4ee00a-d9f0-5490-ff4b-d17374c433ef
D 09:05:39.211 gatt.writeCharacteristic(2e4ee00a-d9f0-5490-ff4b-d17374c433ef, value=0x0402)
I 09:05:39.214 数据写入 2e4ee00a-d9f0-5490-ff4b-d17374c433ef,值:(0x) 04-02
A 09:05:39.214 "(0x) 04-02" 发送
第五个是我在上面的 UUID 中写入 0402 的地方。此操作从以下位置发送数据/值流:
2e4ee00d-d9f0-5490-ff4b-d17374c433ef,带有描述符句柄 26 2e4ee00e-d9f0-5490-ff4b-d17374c433ef,带有描述符句柄 33一旦我在 nRF Connect 中完成了上述基本步骤,两个特征值流就会激活,我可以立即在我的 Garmin Edge 810 主机中看到转换后的值。
因此尝试在我的 tkinter sn-p 中复制相同的进程:
# this function fires from the 'On' button click event
def powerON():
powerON_buttonevent = 1
print(f"\tpowerON_buttonevent OK powerON_buttonevent")
# Connect to the BSX Insight
try:
adapter = pygatt.BGAPIBackend() # serial_port='COM3'
adapter.start()
device = adapter.connect('0C:EF:AF:81:0B:76', address_type=pygatt.BLEAddressType.public)
print(f"\tConnected: device")
except:
print(f"BSX Insight connection failure")
finally:
# adapter.stop()
pass
# Enable only these CCCDs
try:
device.char_write_handle(21, bytearray([0x01, 0x00]), wait_for_response=True)
device.char_write_handle(26, bytearray([0x01, 0x00]), wait_for_response=True)
device.char_write_handle(33, bytearray([0x01, 0x00]), wait_for_response=True)
print(f"\te00b DESC: device.char_read_long_handle(21)") # notifiy e00b
print(f"\te00d DESC: device.char_read_long_handle(26)") # notify e00d SmO2
print(f"\te00e DESC: device.char_read_long_handle(33)") # notify e00e tHb
# Here's where I tested functions from Pygatt...
# print(f"\tdevice.get_handle('UUID_here')") # function works
# print(f"\tvalue_handle/characteristic_config_handle: device._notification_handles('UUID_here')") # function works
# print(f"device.char_read('UUID_here')")
# print(f"device.char_read_long_handle(handle_here)") # function works
except:
print(f"CCCD write value failure")
finally:
# adapter.stop()
pass
# Enable the data streams
try:
device.char_write('2e4ee00a-d9f0-5490-ff4b-d17374c433ef', bytearray([0x04, 0x02]), wait_for_response=True) # function works
print(f"\te00a Power ON: device.char_read('2e4ee00e-d9f0-5490-ff4b-d17374c433ef')")
except:
print(f"e00a Power ON write failure")
finally:
# adapter.stop()
pass
# Subscribe to SmO2 and tHb UUIDs
try:
def data_handler(handle, value):
"""
Indication and notification come asynchronously, we use this function to
handle them either one at the time as they come.
:param handle:
:param value:
:return:
"""
if handle == 25:
print(f"\tSmO2: value Handle: handle")
elif handle == 32:
print(f"\ttHb: value Handle: handle")
else:
print(f"\tvalue: value, handle: handle")
device.subscribe("2e4ee00d-d9f0-5490-ff4b-d17374c433ef", callback=data_handler, indication=False, wait_for_response=True)
device.subscribe("2e4ee00e-d9f0-5490-ff4b-d17374c433ef", callback=data_handler, indication=False, wait_for_response=True)
print(f"\tSuccess 2e4ee00d: device.char_read('2e4ee00d-d9f0-5490-ff4b-d17374c433ef')")
print(f"\tSuccess 2e4ee00e: device.char_read('2e4ee00e-d9f0-5490-ff4b-d17374c433ef')")
# this statement causes a run-on continuity when enabled
# while True:
# sleep(1)
except:
print("e00d/e00e subscribe failure")
finally:
adapter.stop()
# pass
问题:在我的 Atom 编辑器的输出窗口中,两个数据流按预期启动。例如:
I 09:05:39.983 从 2e4ee00d-d9f0-5490-ff4b-d17374c433ef 收到通知,值:(0x) 00-00-00-00-C0-FF-00-00-C0-FF-84-65 -B4-3B-9E-AB-83-3C-FF-03
还有……
I 09:05:39.984 从 2e4ee00e-d9f0-5490-ff4b-d17374c433ef 收到通知,值:(0x) 1C-00-00-FF-03-FF-0F-63-00-00-00-00 -00-00-16-32-00-00-00-00
在“流”停止之前,我会看到大约七到十行数据。会有大约 20 秒的间隔,然后是大量的值转储。这与 nRF Connect 的输出不同,后者是即时且连续的。
我有来自 nRF Connect 和 Python 的日志...但我不确定哪个日志条目指向停止的原因。这个问题可能与外围首选连接参数有关吗?读取的 nRF Connect 属性显示:
ConnectionInterval = 50ms~100ms SlaveLatency = 1 SuperTimeoutMonitor = 200Python 日志条目显示如下:
INFO:pygatt.backends.bgapi.bgapi:连接状态:handle=0x0,flags=5,address=0xb'760b81afef0c',连接间隔=75.000000ms,timeout=1000,latency=0间隔,bonding=0xff
有人想吗? (真的,在此先感谢。)
【问题讨论】:
2020 年 1 月 29 日编辑。通过将 wait_for_response 参数更改为“False”来修复数据流“转储”。现在,流看起来就像来自 nRF Connect 的那样。通过向 adapter.connect() 语句添加适当的参数来修复设备连接首选项。我可以在 Python 日志文件中看到连接条件。 【参考方案1】:我已经回答了我的问题。我现在必须解决一个新问题,即为什么我的 tKinter 对话框“没有响应”作为一个单独的问题。 谢谢大家 2020 年 3 月 31 日编辑:我使用 pyQt 重新编写了脚本,现在有了一个功能性应用程序。
【讨论】:
嗨,skipper0802,我尝试了您的代码,但对于 device.subscribe(),它总是给我错误“pygatt.backends.bgapi.exceptions.ExpectedResponseTimeout: Timed out after 10.000000s waiting for.. ."。有什么想法吗? 嗨 @Abhishek,我将 sleep() 循环更改为:# 此处的睡眠循环允许回调不受阻碍地调用 'data_handler' while button_stopData_event == 0: sleep(1) print(f"BSX数据流发送...") if button_stopData_event == 1: break 另外,我使用 pyQt 重新编写了脚本,并利用单独的线程来容纳流集合。感谢您的回复。 您好,skipper0802 非常感谢您提供的信息。我会尝试从这里解决。以上是关于如何将 nRF Connect(适用于 Android)操作模拟到 Pygatt 脚本?的主要内容,如果未能解决你的问题,请参考以下文章
iOS:scanForPeripheralsWithServices 无法找到设备,而 nRF Connect 应用程序能够找到它
Zephyr RTOS -- nRF Connect SDK (NCS) 环境搭建
Zephyr RTOS -- nRF Connect SDK (NCS) 环境搭建