2015年10月18日日曜日

gatttool で Bluetooth デバイスの情報を取得する方法

概要

RaspberryPi 上に BlueZ をインストールして gatttool でデバイスの情報を取得する方法を紹介します
また今回使用した BLE デバイスは BL600 です

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.10
  • BlueZ 5.23-2+b1

BLEデバイスをスキャンし接続する

  • sudo hcitool -i hci0 lescan

でまずは Mac アドレスを調べます
対象の Mac アドレス (今回は xx:xx:xx:xx:xx:xx) が判明したら gatttool で接続します
これで gatttool のインタラクティブモードになります

  • gatttool -t random -b xx:xx:xx:xx:xx:xx -I

あとは connect コマンドを実行しましょう

[xx:xx:xx:xx:xx:xx][LE]> connect
Attempting to connect to xx:xx:xx:xx:xx:xx
Connection successful
[xx:xx:xx:xx:xx:xx][LE]>

connect に成功するとプロンプトの色が青色に変化すると思います

値を取得する

まず primary というコマンドを実行しましょう

[xx:xx:xx:xx:xx:xx][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0009, end grp handle: 0x000e uuid: 0000180d-0000-1000-8000-00805f9b34fb
attr handle: 0x000f, end grp handle: 0x0012 uuid: 0000180f-0000-1000-8000-00805f9b34fb
attr handle: 0x0013, end grp handle: 0xffff uuid: 0000180a-0000-1000-8000-00805f9b34fb

すると謎の文字列がずらーっと出てくると思います
これがこのデバイスから取得できるサービスの一覧です
サービスとは BLE が定めたもので各種値は必ずどこかのサービスに属しています

着目するのはこの中の uuid という項目でこの uuid を元にどんなデータが取得できるサービスなのか判断します

例えば一番上の uuid 00001800-0000-1000-8000-00805f9b34fb の初めの8桁の下4桁 1800 に着目します
この 1800 を先ほどの URL の中で探すと Generic Access という項目に該当することがわかります
そして Generic Access の中に Device Name という項目がありここの問い合わせることでデバイス名を取得することができます
では具体的に値を取得してみましょう

デバイス名を取得する

1800 のサービスの中でどの項目がデバイス名なのか調べる必要があります
どんな項目があるかは char-desc というコマンドを使用します

[xx:xx:xx:xx:xx:xx][LE]> char-desc 0x0001 0x0007
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb

するとまたずらーっと謎の文字列が登場します
この中のどれかがデバイス名になります
ここでまた登場するのが uuid です
先ほど紹介した Generic Access の詳細を説明するページに移動します
この中の「Device Name」をクリックすると「 Assigned Number: 0x2A00」というのが記載されていると思います
ble_device_name_number.png

この「2A00」を先ほどの char-desc の uuid 下4桁と照らし合わせると以下が該当することがわかります

handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb

ここにアクセスするとデバイス名を取得できそうです
で、アクセスする方法は以下になります

[xx:xx:xx:xx:xx:xx][LE]> char-read-hnd 0x0003
Characteristic value/descriptor: 46 5f 49 49 49

取得できたと思ったら謎の文字列がまた返ってきました
先ほどの Device Name の説明のページを見ると「Format」という欄がありそこに「utf8s」と記載されているのがわかると思います
つまりこの16進数の数字の羅列を utf8s に変換する必要があるのです(面倒くさい!)
そして utf8s への変換方法は以下の通り

  • echo ” 46 5f 49 49 49” | tr \ = | nkf -WwmQ

ちなみにこの文字列は「F_III」に変換されます
ちょっとわかりづらいですが、echo している文字列の先頭にはスペースが入っています
tr コマンドの変換元の文字列はスペースをエスケープしているため「\」が変換元の文字列になります

こんな感じでデバイス名は取得することができます

バッテリ残量を取得する

バッテリ残量も同様の方法で取得することができます
uuid は「0x180F Battery Service」になります

[xx:xx:xx:xx:xx:xx][LE]> connect
Attempting to connect to xx:xx:xx:xx:xx:xx
Connection successful
[xx:xx:xx:xx:xx:xx][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0009, end grp handle: 0x000e uuid: 0000180d-0000-1000-8000-00805f9b34fb
attr handle: 0x000f, end grp handle: 0x0012 uuid: 0000180f-0000-1000-8000-00805f9b34fb
attr handle: 0x0013, end grp handle: 0xffff uuid: 0000180a-0000-1000-8000-00805f9b34fb
[xx:xx:xx:xx:xx:xx][LE]> char-desc 0x000f 0x0012
handle: 0x000f, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0010, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0011, uuid: 00002a19-0000-1000-8000-00805f9b34fb
handle: 0x0012, uuid: 00002902-0000-1000-8000-00805f9b34fb
[xx:xx:xx:xx:xx:xx][LE]> char-read-hnd 0x0011
Characteristic value/descriptor: 52

Format を見ると uint8 なので符号なし整数です
値はもちろん16進数なのでこれを10進数に変換すると

52(16) = 82(10)

になります
単位はパーセンテージなので電池残量は残り 82 %だとわかります

最後に

紹介は以上です
取得の仕組みがわかるとスイスイ値を取得できますが、わかるまでが大変でした
基本的に英語の文献ばかりなので英語が読めないと辛いです

Tips

  • UUID を直接指定して値を取得する方法
    例えばデバイス名を取得する場合

char-read-uuid 2a00

でも取得することができます

  • インタラクティブモードじゃない方法で取得する方法

gatttool -t random -b xx:xx:xx:xx:xx:xx –char-read –uuid=0x2a00

この場合 connect -> disconnect も勝手に行ってくれます

  • 存在しない UUID もあります
    UUID は決められてはいますがデバイスによってはカスタマイズされており、存在していないものもあります
    なのでサービスの一覧と primary コマンド等で UUID を照らし合わせつつ値の取得を行ってください

0 件のコメント:

コメントを投稿