如何模仿nRF Connect(适用于Android)操作到pygatt脚本?



我正在使用适用于Android的nRF Connect来测试BLE外设。外围设备是BSX Insight残余肌肉氧监测仪,其软件应用程序不再起作用或不受制造商支持。因此,我使用我的设备(BSX(的唯一选择是编写自己的控制软件。我编写了一个 Python 3.7 脚本,在我的 64 位 Win 10 笔记本电脑上的 tkinter 例程中运行。另外,我正在使用 Pygatt 库和 BLED112 BT 加密狗。

我可以连接到外围设备,读取和写入值就可以到特征,但我确信从 nRF Connect 中使用的过程到我的脚本的"转换"是不完整且效率低下的。因此,我想确认的第一件事是使用了来自 Pygatt 的正确相应函数。一旦我使用了 Pygatt 中的正确函数,我就可以比较要捕获和存储的两个数据(特征值(流的相应输出。

nRF 连接的基本流程:
1. 扫描
2. 选择/连接 BSX 洞察
3. 公开感兴趣的
服务和特征 4. 启用 CCCD
5. 写入"启动数据"值 (04-02(

这些是来自 nRF 连接日志文件的进程命令结果。从数字四开始:4.D 09:04: 54.491 gatt.set特征通知(00002a37-0000-1000-8000-00805f9b34fb,真( 11 D 09:04:54.496 gatt.set特征通知(2e4ee00b-d9f0-5490-ff4b-d17374c433ef,真( 20x D 09:04:54.499 gatt.set特征通知(2e4ee00d-d9f0-5490-ff4b-d17374c433ef,真(



25x
D 09:04:54.516 gatt.set特征通知(2e4ee00e-d9f0-5490-ff4b-d17374c433ef,真( 32x
D 09:04:54.519 gatt.set特征通知(00002a63-0000-1000-8000-00805f9b34fb,真( 36
D 09:04:54.523 gatt.set特征通知(00002a53-0000-1000-8000-00805f9b34fb,真( 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
  1. 写入 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代码段中复制相同的过程:

# 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"t{device.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-00

在"流"停止之前,我会看到大约七到十行数据。会有大约 20 秒的间隔,然后是大量的值转储。这与 nRF Connect 的输出不同,后者是即时且连续的。

我有来自nRF Connect和Python的日志...但我不确定哪个日志条目指向停止的原因。此问题是否与外围设备首选连接参数有关?nRF Connect 属性读取显示:

  • 连接间隔 = 50ms~100ms
  • 从属延迟 = 1
  • 超级超时监视器 = 200

Python 日志条目显示以下内容:

INFO:pygatt.backends.bgapi.bgapi:连接状态:handle=0x0,标志=5,地址=0xb'760b81afef0c',连接间隔=75.000000ms,超时=1000,延迟=0间隔,绑定=0xff

有人想吗?(真的,提前感谢。

我已经回答了我的问题。我现在必须解决为什么我的 tKinter 对话框作为一个单独的问题"没有响应"的新问题。 谢谢大家 编辑 3/31/2020:我使用 pyQt 重写了脚本,现在有一个功能应用程序。

最新更新