Fitbit LiveData取得備忘録


# はじめに
Fitbit Charge HRなどFitbitデバイス（以下、Tracker）からBLE経由でLiveDataを取得するための備忘録。
何か進み次第更新する予定。

\# などと書き始めたら、[FitbitのAPI群](https://dev.fitbit.com/reference/#overview)がだいぶ追加されてた模様。
\# 本メモの内容を全く知らなくても下記「やりたいこと」ができる予感。
\# Tracker上で実行するもの？新デバイス限定？

**(2017/11/15追記)**
下記シーケンスでは、[Fitbit Ionic](https://www.fitbit.com/ionic)からLiveDataを取得することはできなかった。もうちょっと調査が必要。

**(2017/11/17追記)**
下記シーケンスで再び試したら、[Fitbit Ionic](https://www.fitbit.com/ionic)からLiveDataを取得できてた。ホスト側は何も変更していないので、Tracker（Ionic）側が何か変わった？
確かにスマホとの同期も怪しかった気はする。

# LiveDataとは
ここでLiveDataと書いているものは、Trackerがその瞬間に検出して表示しているデータ（心拍数、歩数、距離等）のこと。

# Fitbitからデータを取るには
Fitbitのデータ取得方法には二通りある。

一つは、Fitbitの[webAPI](https://dev.fitbit.com/reference/web-api/#quick-start)を使う方法。
スマホやWindows/Macの公式アプリ（Linux向けにはOSSの[galileo](https://bitbucket.org/benallard/galileo)が利用可能）と連携すると、Tracker内のデータをFitbitの公式サーバと同期し、その後webAPIを通してデータが取得可能になる。おそらく`megadump`と呼ばれるもの。
ただしアプリの同期が1回/10〜15分という頻度なのと（手動で強制同期は可能）、同期したとしてもwebAPIから取れるまでにはまた少し時間がかかるっぽい。

もう一つは、Fitbitアプリが動くスマホやPCとペアリングされたTrackerとの間では、BLEを使ってLiveDataを飛ばしているので、アプリ上でそれを表示する方法。これはTrackerとアプリに表示されるだけなのでまともな手段では再利用不可。

# やりたいこと
公式アプリを使わずに、何とかしてLiveDataをリアルタイムに取得すること。

# できたこと
公式AndroidアプリとTrackerとの間のBLE通信を解析し、LiveData送受信の手順を確立、
限定的な環境ながら、LiveDataの取得に成功。
\# ただし一般的に使うにはまだ情報が足りてない。

# BLE通信の中を覗いてみた
## 実験環境
- ホスト as BLE Central
    - macOS
    - node.jsとBLEライブラリ
        - [noble](https://github.com/sandeepmistry/noble)
        - [bleno](https://github.com/sandeepmistry/bleno)
- Tracker as BLE Peripheral
    - Fitbit Charge HR

ホストがBLE Centralだが、TrackerがPeripherarlで、一般的にCentralがClient、PeripheralがServerになることが多いが、接続手順の中でTrackerからホストへのリクエストが発生するので、双方Server/Clientになる。

## ホストとTrackerのやり取り
公式AndroidアプリとTrackerとの通信をベースに。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/90361/44489ab0-a1a2-5500-2c9c-5b09992b79fe.png)

### 認証情報取得プロセス（ホスト ⇔ Fitbit API Server）
1. ホストは、Fitbitのアカウント（ユーザ名・パスワード）、またはOAuth2 Authorization Codeを使って、FitbitのAPI ServerからOAuthアクセストークンを取得する<br><br>
2. 取得したアクセストークンを使って、アカウントに紐付いたTrackerの情報（シリアルNo.）を取得する<br><br>
3. アクセストークンとTrackerのシリアルNo.を使って、認証情報を取得する

### （ホスト ⇔ Tracker）
1. TrackerがAdvertisingする<br>
   なおTrackerとペアリング済みのスマホ／PCとBLE接続していると、<br>そちらに優先的につながってしまいAdvertisingしてくれないことが多い<br><br>
1. ホストがBLEのスキャンを開始し、対象のTrackerからのAdvertisingパケットを拾うと指定のTrackerのアドレスに対して接続を開始する<br>
   なのでTrackerのアドレスは予め知っているか、製品名や製造者を取得し「このAdvertisingはTrackerからだ」と判断する処理を事前に必要にある<br><br>----<br>この辺りまではnobleのサンプルを動かせばできる<br>----<br><br>
**~~Charge HRの場合は、つなぐ前にアドレスの照合ができたが、それ以降のモデルでは、一度つなげてみないと所望のTrackerかどうかを確認できないかもしれない~~<br>
BLE接続に使っている[noble](https://github.com/sandeepmistry/noble)のREADMEには**<br><br>
　*Note: on OS X the address will be set to 'unknown' if the device has not been connected previously.*<br>
<br>**と書かれているので、一度noble以外の手段で繋がないとアドレスからは紐付けることはできない**<br><br>

1. ホストに`notify`プロパティを持ったCharacteristic`16bcfd02-253f-c348-e831-0db3e334d580`（Service`16bcfd00-253f-c348-e831-0db3e334d580`）を立てておき、TrackerからのSubscribeを受け入れるようにしておく（ここでホストがServerになるので、blenoが必要になる）<br>
   Fitbit Charge HRの場合、これをやっておかないと、取れるLiveDataが2バイト短い現象が起こった<br><br>


1. ホストは、Tracker上のnotify用Characteristic`adabfb01-6e7d-4601-bda2-bffaa68956ba`（Serviceは`adabfb00-6e7d-4601-bda2-bffaa68956ba`）に対してSubscribeする<br><br>
1. Subscribeが成功したら、write用Characteristic`adabfb02-6e7d-4601-bda2-bffaa68956ba`（通知用Characteristicとは、8文字目だけ異なる。Serviceは同じ）に
`OPEN_SESSION`命令である`0xc00a0a00080010000000c80001`を書き込む<br>
   writeが成功すると、notify用Characteristicから何度かデータがnotifyされるが、最終的に`c014`から始まる長さ14バイトのデータがnotifyされればセッションオープン成功<br>
   データ残り部分は解析してないが、まだ特に支障はない<br><br>

1. write用Characteristicに`AUTH_TRACKER`命令（`c050`から始まり、次に乱数4バイト、その後認証用`nonce`（[認証情報取得プロセス](https://qiita.com/horihiro/items/03c4bef3e71539eddaad#%E8%AA%8D%E8%A8%BC%E6%83%85%E5%A0%B1%E5%8F%96%E5%BE%97%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E3%83%9B%E3%82%B9%E3%83%88--fitbit-api-server)で取得したもの。4バイトの計10バイト）をwriteする<br>
   writeが成功すると、notify用Characteristicから`0xc051`から始まる長さ14バイトのデータがnotifyされれば認証**開始**成功。<br>
   まだ認証プロセスが始まっただけ<br><br>
1. 認証用`authSubKey`（[認証情報取得プロセス](https://qiita.com/horihiro/items/03c4bef3e71539eddaad#%E8%AA%8D%E8%A8%BC%E6%83%85%E5%A0%B1%E5%8F%96%E5%BE%97%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E3%83%9B%E3%82%B9%E3%83%88--fitbit-api-server)で取得）と6.でnotifyを受けたデータ（`0xc051`から始まる長さ14バイトのデータ）を使って`SEND_AUTH`命令（`0xc052`から始まり長さ10バイト）を生成し、write用Characteristicにwriteする。<br>
   writeが成功し認証に成功すると、notify用Characteristicから`0xc002`がnotifyされる<br><br>
1. notify用CharacteristicのSubscribeを終了し、代わりにLiveData用Characteristic`558dfa01-4fa8-4105-9f02-4eaa93e62980`(Serviceは`558dfa00-4fa8-4105-9f02-4eaa93e62980`)に対してSubscribeする<br>
   Subscribeが成功すると、以降LiveData用CharacteristicからLiveDataがどんどん流れてくる

## LiveDataのフォーマットについて
Fitbit Charge HRの場合、LiveDataは20バイトで構成。
心拍測定機能がないTrackerの場合は、おそらく18バイトで構成。

基本的に、LittleEndian。

|開始位置|バイト長|意味|
|:-:|:-:|:-:|
| 0 | 4 |時間[sec]<br>（通知時刻なのか取得時刻なのか不明）|
| 4 | 4 |歩数|
| 8 | 4 |距離|
| 12 | 2 | 消費カロリー |
| 14 | 2 | 段数×10 |
| 16 | 2 | 活動時間<br>（表示と一致しない） |
| 18 | 1 | 心拍数 |
| 19 | 1 | （不明） |

ちなみに、Fitbit Charge HRの場合、「ホストとTrackerのやり取り」の3.を実施しないと、心拍数以降のデータが欠落し18バイトのものしか通知されない。

----