はじめに
Fitbit Charge HRなどFitbitデバイス(以下、Tracker)からBLE経由でLiveDataを取得するための備忘録。
何か進み次第更新する予定。
# などと書き始めたら、FitbitのAPI群がだいぶ追加されてた模様。
# 本メモの内容を全く知らなくても下記「やりたいこと」ができる予感。
# Tracker上で実行するもの?新デバイス限定?
(2017/11/15追記)
下記シーケンスでは、Fitbit IonicからLiveDataを取得することはできなかった。もうちょっと調査が必要。
(2017/11/17追記)
下記シーケンスで再び試したら、Fitbit IonicからLiveDataを取得できてた。ホスト側は何も変更していないので、Tracker(Ionic)側が何か変わった?
確かにスマホとの同期も怪しかった気はする。
LiveDataとは
ここでLiveDataと書いているものは、Trackerがその瞬間に検出して表示しているデータ(心拍数、歩数、距離等)のこと。
Fitbitからデータを取るには
Fitbitのデータ取得方法には二通りある。
一つは、FitbitのwebAPIを使う方法。
スマホやWindows/Macの公式アプリ(Linux向けにはOSSのgalileoが利用可能)と連携すると、Tracker内のデータをFitbitの公式サーバと同期し、その後webAPIを通してデータが取得可能になる。おそらくmegadump
と呼ばれるもの。
ただしアプリの同期が1回/10〜15分という頻度なのと(手動で強制同期は可能)、同期したとしてもwebAPIから取れるまでにはまた少し時間がかかるっぽい。
もう一つは、Fitbitアプリが動くスマホやPCとペアリングされたTrackerとの間では、BLEを使ってLiveDataを飛ばしているので、アプリ上でそれを表示する方法。これはTrackerとアプリに表示されるだけなのでまともな手段では再利用不可。
やりたいこと
公式アプリを使わずに、何とかしてLiveDataをリアルタイムに取得すること。
できたこと
公式AndroidアプリとTrackerとの間のBLE通信を解析し、LiveData送受信の手順を確立、
限定的な環境ながら、LiveDataの取得に成功。
# ただし一般的に使うにはまだ情報が足りてない。
BLE通信の中を覗いてみた
実験環境
ホストがBLE Centralだが、TrackerがPeripherarlで、一般的にCentralがClient、PeripheralがServerになることが多いが、接続手順の中でTrackerからホストへのリクエストが発生するので、双方Server/Clientになる。
ホストとTrackerのやり取り
公式AndroidアプリとTrackerとの通信をベースに。
認証情報取得プロセス(ホスト ⇔ Fitbit API Server)
- ホストは、Fitbitのアカウント(ユーザ名・パスワード)、またはOAuth2 Authorization Codeを使って、FitbitのAPI ServerからOAuthアクセストークンを取得する
- 取得したアクセストークンを使って、アカウントに紐付いたTrackerの情報(シリアルNo.)を取得する
- アクセストークンとTrackerのシリアルNo.を使って、認証情報を取得する
(ホスト ⇔ Tracker)
-
TrackerがAdvertisingする
なおTrackerとペアリング済みのスマホ/PCとBLE接続していると、
そちらに優先的につながってしまいAdvertisingしてくれないことが多い -
ホストがBLEのスキャンを開始し、対象のTrackerからのAdvertisingパケットを拾うと指定のTrackerのアドレスに対して接続を開始する
なのでTrackerのアドレスは予め知っているか、製品名や製造者を取得し「このAdvertisingはTrackerからだ」と判断する処理を事前に必要にある
----
この辺りまではnobleのサンプルを動かせばできる
----
Charge HRの場合は、つなぐ前にアドレスの照合ができたが、それ以降のモデルでは、一度つなげてみないと所望のTrackerかどうかを確認できないかもしれない
BLE接続に使っているnobleのREADMEには
Note: on OS X the address will be set to 'unknown' if the device has not been connected previously.
と書かれているので、一度noble以外の手段で繋がないとアドレスからは紐付けることはできない -
ホストに
notify
プロパティを持ったCharacteristic16bcfd02-253f-c348-e831-0db3e334d580
(Service16bcfd00-253f-c348-e831-0db3e334d580
)を立てておき、TrackerからのSubscribeを受け入れるようにしておく(ここでホストがServerになるので、blenoが必要になる)
Fitbit Charge HRの場合、これをやっておかないと、取れるLiveDataが2バイト短い現象が起こった -
ホストは、Tracker上のnotify用Characteristic
adabfb01-6e7d-4601-bda2-bffaa68956ba
(Serviceはadabfb00-6e7d-4601-bda2-bffaa68956ba
)に対してSubscribeする -
Subscribeが成功したら、write用Characteristic
adabfb02-6e7d-4601-bda2-bffaa68956ba
(通知用Characteristicとは、8文字目だけ異なる。Serviceは同じ)に
OPEN_SESSION
命令である0xc00a0a00080010000000c80001
を書き込む
writeが成功すると、notify用Characteristicから何度かデータがnotifyされるが、最終的にc014
から始まる長さ14バイトのデータがnotifyされればセッションオープン成功
データ残り部分は解析してないが、まだ特に支障はない -
write用Characteristicに
AUTH_TRACKER
命令(c050
から始まり、次に乱数4バイト、その後認証用nonce
(認証情報取得プロセスで取得したもの。4バイトの計10バイト)をwriteする
writeが成功すると、notify用Characteristicから0xc051
から始まる長さ14バイトのデータがnotifyされれば認証開始成功。
まだ認証プロセスが始まっただけ -
認証用
authSubKey
(認証情報取得プロセスで取得)と6.でnotifyを受けたデータ(0xc051
から始まる長さ14バイトのデータ)を使ってSEND_AUTH
命令(0xc052
から始まり長さ10バイト)を生成し、write用Characteristicにwriteする。
writeが成功し認証に成功すると、notify用Characteristicから0xc002
がnotifyされる -
notify用CharacteristicのSubscribeを終了し、代わりにLiveData用Characteristic
558dfa01-4fa8-4105-9f02-4eaa93e62980
(Serviceは558dfa00-4fa8-4105-9f02-4eaa93e62980
)に対してSubscribeする
Subscribeが成功すると、以降LiveData用CharacteristicからLiveDataがどんどん流れてくる
LiveDataのフォーマットについて
Fitbit Charge HRの場合、LiveDataは20バイトで構成。
心拍測定機能がないTrackerの場合は、おそらく18バイトで構成。
基本的に、LittleEndian。
開始位置 | バイト長 | 意味 |
---|---|---|
0 | 4 | 時間[sec] (通知時刻なのか取得時刻なのか不明) |
4 | 4 | 歩数 |
8 | 4 | 距離 |
12 | 2 | 消費カロリー |
14 | 2 | 段数×10 |
16 | 2 | 活動時間 (表示と一致しない) |
18 | 1 | 心拍数 |
19 | 1 | (不明) |
ちなみに、Fitbit Charge HRの場合、「ホストとTrackerのやり取り」の3.を実施しないと、心拍数以降のデータが欠落し18バイトのものしか通知されない。