使用 bluez/bluetoothctl/gatttool 连接到蓝牙 smart/LE 体重秤

Connecting to a Bluetooth smart/LE weight scale with bluez/bluetoothctl/gatttool

我想做的事情:

我想将我的 Raspberry Pi 2 连接到蓝牙智能体重秤 (Medisana BS440) 并接收我的数据。

我知道的:

只有一项有趣的主要服务具有 5 个特征:

 - handle: 0x001a
     -  properties: 0x20 (Indication), char value handle: 0x1b uuid:00008a21-0000-1000-8000-00805f9b34fb
 - handle: 0x001d
     -  properties: 0x20 (Indication), char value handle: 0x1e uuid:00008a22-0000-1000-8000-00805f9b34fb
 - handle: 0x0020
     -  properties: 0x02 (Read-Only),  char value handle: 0x21 uuid:00008a20-00..
 - handle: 0x0022
     -  properties: 0x08 (Write-Only), char value handle: 0x23 uuid:00008a81-00..
 - handle: 0x0024
     -  properties: 0x20 (Indication), char value handle: 0x25 uuid:00008a82-00..

我使用 Android-Phone 的 HCI-Snoop-Developer-Funktion 来查看相应的应用程序如何与我的体重秤通信。

  1. 写入 0200 -> 0x1f(启用指示 0x1d)
  2. 读取 0x21 -> 0x21(值:37fb)
  3. 写入 0200 -> 0x1c(启用指示 0x1a)
  4. 写入 0200 -> 0x26(启用指示 0x24)
  5. write 02a31e2c0b -> 0x23(我在这里不完全理解这个,但我知道如果你在 02 (a3 1e 2c 0b -> 0b 2c 1e a3 -> this is the current Unix-timestamp但对于这一年?1975 年?)

在第 4 步之后。第一个指示(句柄 0x25)为我提供了我存储的个人数据(我的身高、性别、年龄等)

在第 5 步之后。有一些指示(句柄 0x1b 和句柄 0x1e)应该传输我的测量数据。 (此时没有分析十六进制值)

我做了什么:

我在我的 raspi (kernel 4.1.13) 上安装了 bluez.5.32,并使用 gatttool 和所有东西完成了第 1 - 5 步在第 5 步之前工作正常。我没有从句柄 0x1b 和 0x1e 收到任何指示消息)在第 5 步之后没有任何反应。

gatttool -t random -b DE:70:4A:XX:XX:XX -I
char-write-cmd 0x1f 0200
char-read-hnd 0x21 (37fb)
char-write-cmd 0x1c 0200
char-write-cmd 0x26 0200
char-write-cmd 0x23 0000000000

(我什至用 1975 年的 unix-timestamp-timestamp 来做这件事.. 没有成功)

经过数十亿小时后,我开始在我的 raspi 上使用 bluetoothctl(存在 dbus 问题),并且我对 bluetoothctl 进行了同样的尝试。我启用了所有指示并将 0000000000 写入 hnd=0x23。切换到处理 0x1a 并且它起作用了!我收到许多十六进制值,它们应该是我正在搜索的数据。

所以问题是什么? 我想将 gatttool 用于我的目的,或者至少我想了解,为什么它不能与 gatttool

一起使用

当我使用 bluetoothctl 时,我只能 select 并观察一个属性,在收到数据后,我的体重秤会自动断开与我的树莓派的连接。所以当我 select 特性 0x1a 时,我看不到特性 0x01d 的指示消息,反之亦然。

当我使用 gatttool 或使用 bluetoothctl 时,我的 Pi 和 Scale 之间是否有其他连接?还是他们与我的体重秤沟通的方式有所不同?

好的..我自己解决了这个问题..我需要做的就是将 ,char-write-cmd" 更改为 ,char-write-req".. 在我的日志文件中 Android-Hci-Snoop 它总是一个写请求。不知道为什么一直认不出来...

如果有人和我一样对 bluez/bluetoothd/bluetoothctl & dbus 有同样的问题 (要在 bluetoothctl 中使用命令 "list-attributes"、"select" "write",您必须在实验模式下执行 bluetoothd,例如 "bluetoothd -n -E",但每次我这样做时都会收到一些错误消息像 "D-Bus: name already in use" 或类似 "d'bus setup failed: connection is not allowed to own the service due to security..." 的东西(不记得确切的错误消息))

我做了什么:

  • 使用 ./configure [...] 安装 bluez --enable-experimental(阅读自述文件)

  • sudo nano /etc/dbus-1/system.d/bluetooth.conf

    --> 复制以 >policy user="root"> 开头的整个块,并将其粘贴到该块下方。然后我在两个块之一中将 "root" 更改为 "pi"

如果有人想知道这个秤是如何提供测量结果的,请查看这个link:

体重秤在测量重量等后的短时间内似乎可以连接 我在 bash 脚本中使用了 gatttool 的 non-interactive 模式,如下所示:

gatttool -t random -b F1:37:57:XX:XX:XX --char-write --handle 0x001f -n 0200
gatttool -t random -b F1:37:57:XX:XX:XX --char-read --handle 0x0021
gatttool -t random -b F1:37:57:XX:XX:XX --char-write --handle 0x001c -n 0200
gatttool -t random -b F1:37:57:XX:XX:XX --char-write --handle 0x0026 -n 0200
gatttool -t random -b F1:37:57:XX:XX:XX --char-write-req --handle 0x0023 -n 0000000000 --listen

信息取自 Pratik Sinha here。 要显示响应,需要明确给出 --listen ,然后收到大约 25 行数据(交替 1b 和 1e 响应)。 感谢您的信息,节省了我几天的工作时间!

新年快乐!

编辑:

使用 Python 和 pygatt module 这归结为:

import pygatt.backends
from binascii import hexlify

def printIndication(handle, value):
    print('Indication received {} : {}'.format(hex(handle), hexlify(str(value))))

adapter = pygatt.backends.GATTToolBackend()
adapter.start()
# wait for someone to step on the scale
while True:  
    try:
        device = adapter.connect('f1:37:57:xx:xx:xx', 5, 'random')
        break
    except pygatt.exceptions.NotConnectedError:
        print('Waiting...')
device.subscribe('00008a22-0000-1000-8000-00805f9b34fb', callback = printIndication, indication = True)
device.subscribe('00008a21-0000-1000-8000-00805f9b34fb', callback = printIndication, indication = True)
device.subscribe('00008a82-0000-1000-8000-00805f9b34fb', callback = printIndication, indication = True)
try:
    device.char_write_handle(0x23, [02,00,00,00,00], True)
except pygatt.exceptions.NotificationTimeout:
    pass
device.disconnect()
adapter.stop()

备注:

  • 根据我的经验,读取句柄 0x21 没有任何意义
  • 用 02 写入句柄 0x23,后跟 unix 时间戳同步秤的 RTC
  • 使用多字节修改的pygatt(拉34)能够在一个指示中接收多个字节
  • 虽然写入 0x23 不会产生任何通知,但需要等待通知才能接收 0x1b 和 0x1e 指示。当收到最后一个指示时,收到 NotificationTimeout 异常。