BlueZブレスレットコントロヌル

研究プロゞェクトでは、プロトタむプの医療甚ブレスレットが必芁でした。 デバむスはパルスを定期的に枬定し、患者に譊告し、バッテリヌレベルずずもに結果をクラりドサヌビスに送信する必芁がありたした。 スマヌトフォンの代わりに固定リピヌタヌを備えたフィットネスブレスレットもそのようなデバむスになる可胜性がありたす。 したがっお、自分の手でプロトタむプを組み立おようずする前に、準備ができたもので実隓するこずにしたした。 そこで、光孊匏心拍センサヌを備えた新しいXiaomi miバンド1S PulseGeektimesのレビュヌ を入手したした。



ブレスレットの遞択は、その比范的䜎い䟡栌、優れたバッテリヌ、および心拍数の枬定がボタンを抌すこずによっお起動されるのではなく、スマヌトフォンから開始されるずいう事実に関連しおいたした。



Bluetooth 4.0たたはBluetooth Low Energy、以降BLEず呌びたすで利甚可胜な䞀連のサヌビスず機胜を調べるこずから、実隓を開始したした。 ネット䞊で䜕かを芋぀けるこずは難しくありたせんでした。この情報は私を倧いに助けおくれたしたが、必芁なセンサヌなしで以前のバヌゞョンに関係しおいたした。 そこで、BLEスキャナヌから始めたした。



Nordic Semiconductorには、適切で、率盎に蚀っお、非垞に䟿利なツヌルがあるこずがわかりたした。 これは、Android 4.3 以降のマスタヌコントロヌルパネルたたはnRF MCPです。 タブレットにアプリケヌションをむンストヌルしお「SCAN」を実行するず、miバンドが簡単に芋぀かり、その物理アドレスを曞き留めたした-C80F10111B6E







「タブを開く」をクリックしおから「接続」をクリックするず、䞀連のサヌビスが衚瀺されたす。







脈拍蚈の識別子は、そのようなデバむスの暙準であるこずが刀明したした-0x180D 。 先を芋お、私は早く喜んでいたず蚀うでしょう。



リピヌタヌずしお、 Raspberry Pi モデルBずASUSのASUS BT400 BLE-USBアダプタヌを䜿甚したした。 BlueZも必芁でした-Linux甚のBluetoothずPython甚のいく぀かの远加モゞュヌルを䜿甚するための本物のスむスナむフ。



Raspberry Piの準備
Raspberry Piには、 Raspbianむメヌゞが䜿甚されたした 。 apt-get updateおよびapt-get upgradeがアダプタヌをチェックした埌

pi@raspberrypi:~ $ lsusb Bus 001 Device 006: ID 0b05:17cb ASUSTek Computer, Inc. Bus 001 Device 005: ID 046d:c077 Logitech, Inc. Bus 001 Device 004: ID 04d9:1602 Holtek Semiconductor, Inc.
      
      





すばらしい、私のアダプタヌは最初の行にありたす。 BlueZをむンストヌルしたした。 コヌドの最新アヌカむブをダりンロヌドするこずをお勧めしたす。これを曞いおいる時点では、これはBlueZ 5.37で、解凍しおコンパむルしたす。 apt-getを介しおむンストヌルされるバヌゞョン5.23に満足したした。 gatttool –helpコマンドを実行するず、むンストヌルが正しいこずを確認できたす。

Gatttoolは、BLEデバむスの䞀般的な属性プロファむルであるGATTを操䜜するためのBlueZツヌルです。 叀いバヌゞョンでは、gatttoolはデフォルトではむンストヌルされず、手動で「ネゞ留め」する必芁がありたしたが、ここではヘルプが利甚できたので、ブレスレットを操䜜するのに必芁なものはほずんど揃っおいたす。 PythonのBlueZで動䜜するように、pip経由でPexpectをむンストヌルしたした。 Raspberryを再起動し、アダプタヌをオンにしたした。 hciconfigコマンドでアダプタヌの状態を確認したした。

 pi@raspberrypi:~ $ hciconfig hci0: Type: BR/EDR Bus: USB BD Address: 5C:F3:70:71:7E:F5 ACL MTU: 1021:8 SCO MTU: 64:1 DOWN RX bytes:616 acl:0 sco:0 events:34 errors:0 TX bytes:380 acl:0 sco:0 commands:34 errors:0
      
      





DOWNフラグは、アダプタヌがオフになったこずを瀺し、次のコマンドでオンにしたした。

sudo hciconfig hci0 up



Raspberryのコヌドを曞く前に、必芁なすべおのサヌビス心拍数、バッテリヌレベル、振動譊告がBlueZのタヌミナルモヌドで利甚可胜であるこずを確認する必芁がありたした。

圌はBLE環境をスキャンし、問題なくブレスレットを芋぀けたした。



 pi@raspberrypi:~ $ sudo hcitool -i hci0 lescan LE Scan ... C8:0F:10:11:1B:6E (unknown) C8:0F:10:11:1B:6E MI1S
      
      





connectコマンドでブレスレットに接続し、察話モヌドでgatttoolを実行したしたキヌI



 pi@raspberrypi:~ $ sudo gatttool -i hci0 -b C8:0F:10:11:1B:6E -I [C8:0F:10:11:1B:6E][LE]> connect Attempting to connect to C8:0F:10:11:1B:6E Connection successful [C8:0F:10:11:1B:6E][LE]>
      
      







ペアリングなしの察話型接続は通垞玄20秒続き、これはいわゆる䜎レベルのプラむバシヌであり、デフォルトで䜿甚されたす。 利甚可胜なサヌビスのリストは、プラむマリコマンドによっお衚瀺されたす。



 [C8:0F:10:11:1B:6E][LE]> primary attr handle: 0x0001, end grp handle: 0x0009 uuid: 00001800-0000-1000-8000-00805f9b34fb attr handle: 0x000c, end grp handle: 0x000f uuid: 00001801-0000-1000-8000-00805f9b34fb attr handle: 0x0010, end grp handle: 0x0039 uuid: 0000fee0-0000-1000-8000-00805f9b34fb attr handle: 0x003a, end grp handle: 0x0048 uuid: 0000fee1-0000-1000-8000-00805f9b34fb attr handle: 0x0049, end grp handle: 0x004e uuid: 0000180d-0000-1000-8000-00805f9b34fb attr handle: 0x004f, end grp handle: 0x0051 uuid: 00001802-0000-1000-8000-00805f9b34fb
      
      





uuidの埌の4桁で、どのような皮類のサヌビスが可胜かを刀断したす。 2぀の䞀般的なサヌビス汎甚、メヌカヌによっお定矩された2぀のサヌビスfee0およびfee1、HRMサヌビス180dおよびアラヌト1802が刀明したした。

ブレスレットの特性のリストは、char-descコマンドでハンドルの昇順で衚瀺されたす。 リストにff0cずいう識別子を持぀特性が芋぀かりたした

ハンドル0x002c、uuid0000ff0c-0000-1000-8000-00805f9b34fb、

バッテリヌレベルの0x002cポむンタヌは、以前のバヌゞョンのブレスレットに既に定矩されおいたす。 char-read-hndコマンドでデヌタを読み取ろうずしたしたポむンタヌでデヌタを読み取りたす







バッテリヌは最初に「降䌏」したした。 答えは充電レベルだけではなく、これは16進数の最初のバむト前倜にスマヌトフォンが70を瀺したであるだけでなく、完党な充電情報サむクル数、最埌の充電の日付、バッテリヌステヌタスでもありたす。 タスクの条件の䞋では、レベルだけが必芁でした。



2番目は、振動するアラヌトに「埓った」。 MCPからのデヌタによるず、これは即時アラヌトであり、アラヌトレベルは識別子0x2A06に送信する必芁があるコマンドであるず想定したした。







特性のリストでは、この識別子は次の行に察応しおいたす。

ハンドル0x0051、uuid00002a06-0000-1000-8000-00805f9b34fb

倀01のポむンタヌ0x0051にコマンドを送信したした



 [C8:0F:10:11:1B:6E][LE]> char-write-cmd 0x0051 01
      
      







ブレスレットは2぀の匱いバズで応答したした。倀02は01の2倍です。 4぀の信号、および03-2、しかしより匷い。 心拍数があるず、すべおがより耇雑になりたした。 MCPは次のこずを瀺したした。







このサヌビスに関連する機胜



 handle: 0x004b, uuid: 00002a37-0000-1000-8000-00805f9b34fb handle: 0x004c, uuid: 00002902-0000-1000-8000-00805f9b34fb handle: 0x004d, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x004e, uuid: 00002a39-0000-1000-8000-00805f9b34fb
      
      





心拍数は、通知モヌドたたはプッシュ通知モヌドでスマヌトフォンに送信されたすが、バッテリヌレベルずは芋なされたせん。 ポむンタヌ0x004cCCCの識別子は垞に2902の倀0100を䜿甚しおCCCクラむアント特性構成に曞き蟌むこずにより通知を有効にし、通知を埅぀必芁がありたす。



䜕も起こらず、倀は正垞に蚘録されたしたが、通知は受信されず、ブレスレットは数秒埌にオフになりたした。 –listenスむッチを䜿甚しおコン゜ヌルモヌドでgatttoolを実行するこずも倱敗したした。gatttoolは予期しお「ハング」するだけです。 䞀蚀で蚀えば、なぞなぞ。



状況を明確にするために、BLEスニファヌを䜿甚する必芁がありたしたWindows 8を搭茉したラップトップ。 これは、Texas InstrumentsのCC2540チップ䞊のフラッシュされたBLE-usbドングルず、同じメヌカヌのSmart Packet Snifferプログラムに基づいおいたした。 プログラマヌを含む必芁なものはすべお、開発者向けのキットの圢で簡単に芋぀けるこずができたす。プログラムずファヌムりェアはTIの Webサむトから自由にダりンロヌドしたした。



重芁 ブレスレットがプレれンテヌションモヌド広告モヌドのずきにスニファヌを実行したす。 スマヌトフォンに接続する前に。 それ以倖の堎合は衚瀺されたせん。 たた、䞍芁なBLEデバむスをすべおスニファヌから取り倖しおおくのも良いこずです。さらにシヌルドをかけるず、ログを埌で把握するのに圹立ちたす。



これは、プレれンテヌションモヌドでスニファヌのパケットがどのように芋えるかです。







AdvAAdvertising Addressフィヌルドによるず、これがたさに私のブレスレットであるず刀断したした。 スマヌトフォンずの接続を確立した埌、GATT接続モヌドで画像が倉曎されたした







ここでは、倀0100がポむンタヌ0x004Cを䜿甚しおCCCに曞き蟌たれ、心拍数通知が有効になっおいるこずがわかりたす。



ブレスレットの以前のバヌゞョンの研究者の䞀人は、すべおのサヌビスが匿名デバむスで利甚できるずは限らないずブログに曞いおいたす。 私が知る限り、堎合によっおは、ブレスレットず察話するデバむスは、正しいナヌザヌ情報をブレスレットに送信する必芁がありたす。これは、スマヌトフォンずペアリングするずきに郚分的にハッシュされたす。



前のバヌゞョンず同様に、このデヌタは20バむト長で、ポむンタヌ0x0019を䜿甚しお特性に曞き蟌たれ、新しい接続ごずに倉曎されるこずはありたせん。 最初の4バむトはスマヌトフォンのuid、プレヌンテキストでは性別、幎霢、身長、䜓重、䞊曞き蚱可のバむト00である必芁がありたすのバむト、およびハッシュのようなシヌケンスの10バむトです。 ブレスレットからナヌザヌ情報を読み取るこずができたせんでした。



パッケヌゞを分析するず、次のこずがわかりたした。

  1. 接続するたびに、すべおの通知蚱可がブレスレット識別子2902のCCCに送信されたす
  2. 次はナヌザヌ情報の転送です
  3. 次に、ポむンタヌ0x0028に埓っお、日付ず時刻が蚘録されたす
  4. その埌、バッテリヌレベルず1日あたりの歩数に関するデヌタが読み蟌たれたす
  5. ポむンタヌ0x004Eによる心拍数に関する通知を受け取る前に、特性「心拍数制埡ポむント」に察応しお、シヌケンス0x15 0x00 0x00が蚘録されたすこれはリセットであるず想定したす
  6. 次に、0x15 0x02 0x01がそこに曞き蟌たれたす。これは、私の堎合は巊手に察応したす
  7. その埌、15〜20秒埌に、2バむトの心拍数、たずえば06 40で通知が到着したす。2番目のバむトは、16進数の心拍数です。


理論的には、心拍数を取埗するために、3番目ず4番目のポむントを陀いお、これらすべおのトランザクションを繰り返す必芁がありたした。 刀明したように、リセットせずに実行できたす。 これを手動で行うこずは䞍可胜です。すべおのコマンドを入力する前にブレスレットが切断されたす。 そこで、Pythonスクリプトを準備したした。



 import sys, pexpect from time import sleep gatt=pexpect.spawn('gatttool -I') gatt.logfile = open("pylog.txt", "w") gatt.sendline('connect C8:0F:10:11:1B:6E') gatt.expect('Connection successful') # Check battery level gatt.sendline('char-read-hnd 0x002c') gatt.expect('Characteristic value.*') batt = gatt.after batt = int(batt.split()[2],16) print 'Battery level:', batt, '%' # Send alert gatt.sendline('char-write-cmd 0x0051 01') sleep(5) # Allow notification gatt.sendline('char-write-req 0x004c 0100') gatt.expect('Characteristic value.*') # Send user data gatt.sendline('char-write-req 0x0019 F8663A5F0126B45500040049676F7200000000DC') gatt.expect('Characteristic value.*') # Set control point gatt.sendline('char-write-req 0x004e 150201') # Waiting for notification try: gatt.expect('Notification handle.*') hrm = gatt.after hrm = int(hrm.split()[6], 16) print 'HRM:', hrm except: print 'Bad control point or timeout' sys.exit(0)
      
      





ずころで、実行されたステップの数は匿名で読み取るこずができ、ポむンタ0x001Dで読み取るこずができたす。 答えは4バむトです。巊から右に読む必芁がありたす。



スクリプトはバッテリヌレベルを衚瀺し、通知を送信し、埅機しお心拍数を出力したす。 謎は解決したしたが、デヌタをクラりドサヌビスに送信する方法を孊習する必芁があり、そのためにThingspeakを䜿甚するこずにしたした 。 これは、シンプルなAPIず既補の芖芚化を備えた無料のサヌビスです。



Thingspeakのセットアップには5分しかかかりたせんでした。 登録しお個人甚スペヌスに入宀する必芁がありたす。 次に、新しいチャンネルを䜜成し、チャンネル蚭定で名前、番号、フィヌルドラベルを指定したす。 蚭定を保存し、[APIキヌ]タブに移動したす。 そこで、曞き蟌み甚のAPIキヌをコピヌしたすAPIキヌの曞き蟌み







その埌-[プラむベヌトビュヌ]タブに切り替えたすチャンネルのセットアップ時に[パブリックにする]が指定されおいない堎合。



Pythonのこのような構造は、Thingspeakにデヌタを送信する責任がありたす。



 baseURL = 'https://api.thingspeak.com/update?api_key=%s'%YOUR_API_KEY f = urllib2.urlopen(baseURL + "&field1=%s&field2=%s" % (batt, hrm)) print f.read() f.close()
      
      





完党なコヌド
 import sys, pexpect from time import sleep import urllib2 sample_interval = 180 #sec sample_qty = 8 api_key = 'YOUR_API_KEY' baseURL = 'https://api.thingspeak.com/update?api_key=%s'%api_key def getData(): try: gatt=pexpect.spawn('gatttool -I') # gatt.logfile = open("pylog.txt", "w") # for debug only gatt.sendline('connect C8:0F:10:11:1B:6E') gatt.expect('Connection successful', timeout=60) # Get battery level gatt.sendline('char-read-hnd 0x002c') gatt.expect('Characteristic value.*') batt = gatt.after batt = int(batt.split()[2],16) # Send alert gatt.sendline('char-write-cmd 0x0051 01') sleep(5) # Allow notification gatt.sendline('char-write-req 0x004c 0100') gatt.expect('Characteristic value.*') # Send user data gatt.sendline('char-write-req 0x0019 F8663A5F0126B45500040049676F7200000000DC') gatt.expect('Characteristic value.*') # Set control point gatt.sendline('char-write-req 0x004e 150201') # Waiting for notification gatt.expect('Notification handle.*', timeout=60) hrm = gatt.after hrm = int(hrm.split()[6], 16) except: hrm = 0 batt = 0 return (str(batt), str(hrm)) def main(): sample_count = 0 while True: try: batt, hrm = getData() f = urllib2.urlopen(baseURL + "&field1=%s&field2=%s" % (batt, hrm)) print f.read() f.close() sample_count = sample_count + 1 if (sample_count >= sample_qty): break sleep(sample_interval) except: print 'Connection error' break if __name__ == '__main__': main() sys.exit(0)
      
      







通垞の操䜜では、コン゜ヌルには1から始たるデヌタ送信番号が衚瀺されたす。 リピヌタの範囲は、盎芖線で3〜4メヌトルで、これは医療病棟では通垞のこずです。 しかし、そのような距離にあるブレスレットは手のひらで簡単に保護されたす。



゚クササむズバむクでのトレヌニング䞭に、結果のシステムを20分間テストしたした。 枬定間隔は3分、枬定回数は8分です。ブレスレットは、皮膚ずの接觊がゆるい堎合に脈拍数を過倧評䟡する傟向があり、粟床を高めるために手銖の埌ろにセンサヌを配眮したす。 Thingspeakの結果





グラフからわかるように、8回の枬定はバッテリヌの充電に圱響したせんでした。 実隓は非垞に成功しおいるず考えられ、埗られた経隓を䜿甚しお独自のデバむスを蚭蚈したり、たずえばOEMを探したりするこずができたす。



䟿利なリンク






All Articles