【CoreBluetooth】Fitbitをハックしてみた

fitbitphoto by Fitbit

最近 Bluetooth 4.0 対応デバイスがけっこう世にでてきましたね。
今回買ったのは Fitbit Zip です。機能は限定されますが Fitbit One の約半額で買えます。

基本的なセットアップはこちらを参考にしてください。

H/W構成は分解してないので分かりませんが画面にタッチするとSleep状態からWakeするようです、タッチセンサなのでしょうか。歩数計機能は加速度センサだと思われます。

iOSアプリでデータを受信してみる

今回はCoreBluetoothフレームワークを使ってFitbitのデータを覗いてみます。
CoreBluetoothのリファレンスはここです。一部日本語訳したサイトもあるみたいですね。

今回はホスト機能(クライアント)を実装してみます。
大体の流れは
ペリフェラルの検索 -> サービスの検索 -> キャラクタリスティックの検索 -> Read,write,Notify,Indicate
の順になります。

Applleのサンプルコードも良いですが、他に参考にすると良いコードはここですね。

Corebluetoothの使い方

まずは準備です。
ペリフェラルを検索するホスト機能とペリフェラルに対する操作を行う機能を実装するにはCBCentralManagerDelegate, CBPeripheralDelegateが必要です。


#import 

@interface ViewController : UIViewController 

@property (strong, nonatomic) CBCentralManager *cbManager;
@property (strong, nonatomic) CBPeripheral *connectedPeripheral;

まずは、scanForPeripheralsWithServices:options:でBLEデバイスを検索します。


[self.cbManager scanForPeripheralsWithServices:uuidArray options:options];

ここでServicesを指定しますが、nilでも大丈夫です。
Aplleはユーザに時間的なストレスを与えないためにServicesにnilを指定することは推奨していませんが、私の確認したところUUIDを指定すると接続が上手くいかないことがありました。

ペリフェラルが見つかるとcentralManager:didDiscoverPeripheral:advertisementData:RSSI:が呼ばれます。
取得できるのはデバイスネームや受信強度のRSSI,接続状況などです。


次にペリフェラルに接続します。


[self.cbManager connectPeripheral:peripheral options:nil];

接続された場合はdelegateMethodのcentralManager:didConnectPeripheral:が呼ばれます。

ペリフェラルが持っているサービスを検索します。(ここもnil指定は非推奨)


[peripheral discoverServices:nil];

見つかったサービスはperipheral:didDiscoverServices:で通知されます。

サービスが持っているキャラクタリスティックを検索します。


[peripheral discoverCharacteristics:nil forService:service];

キャラクタの検索結果はperipheral:didDiscoverCharacteristicsForService:error:で通知されます。
ここで任意のキャラクタに対して、2つのCBPeripheral Classのメソッドを使います。


- (void)setNotifyValue:(BOOL)enabled forCharacteristic:(CBCharacteristic *)characteristic
- (void)readValueForCharacteristic:(CBCharacteristic *)characteristic

[peripheral setNotifyValue:YES forCharacteristic:characteristic];
[peripheral readValueForCharacteristic:characteristic];

setNotifyValueが完了した場合に、peripheral:didUpdateNotificationStateForCharacteristic:error:が呼ばれペリフェラルからのデータを受信すると、


- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error

で受信できます。
characteristicにはvalueというプロパティがあるのでこれにアクセスすることでデータを読み取れます。
ちなみにキャラクタリスティックとサービスはバックポインタで繋がっています。


NSLog(@"characteristic.value 0x%x"); //ex) characteristic.value 0x02

ペリフェラルが通信断されるとcentralManager:didDisconnectPeripheral:error:で通知されます。

基本的な手順は以上です。
ちなみに、deviceInfomationサービスのmanufacturerNameStringキャラクタリスティックは fitbit になっていますね。

CoreBluetoothとハック

CoreBluetoothは慣れれば使いやすいフレームワークだと思いますが、当然Androidより制限があります。

注意点として,indication/notificationを受け取るにはキャラクタリスティックに対してはconnectPeripheral前でプロパティにセットしなければいけません。


self.connectedShield = peripheral;
[self.cbManager connectPeripheral:self.peripheral options:nil];

これはiOSのカーネルからコンテキストが始めるためだと思います。
read/writeはiOSアプリのコンテキストから始めるのでプロパティ設定はconnectPeripheralより後で大丈夫なようです。

実際のDelegateの実装は隠蔽されているのでわからない所がきついですね。

色んなBLEデバイスを検索してみると、意外なサービスを持っていたり面白い発見があるかもしれません。