ロボホンにBLE血圧計繋いでみた。

ロボホンはロボット型のスマートフォンで、Android OS(バージョン 5.0)で動いています。
ロボホン(RoBoHoN)についてはこちらのページをご覧ください。

そんなロボホンとBLE血圧計を繋ぐアプリを作ってみました!
なお、血圧計は株式会社エー・アンド・デイのUA-651BLEを使いました。

 

(1) Bluetoothの設定がONであることを確認する

まずBluetoothの機能を使うために、BluetoothAdapterインスタンスを取得します。

BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter();

その後、bluetoothAdapter.isEnabled()でBluetoothがONであるか確認します。

BluetoothがOFFの場合は以下のように暗黙的Intentを投げてBluetoothの有効化を求めます。

Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, REQUEST_ENABLE_BLUETOOTH);

REQUEST_ENABLE_BLUETOOTHはActivityに設定した定数なので適宜実装してください。

ユーザーがイベントを発生させるとonActivityResultにその結果が渡ってくるので、

以下のようにリクエストコードが一致していることを確認後、ONかOFFかで処理を分けます。

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BLUETOOTH) {
if (resultCode == RESULT_OK) {
// BluetoothがONだった時の処理
} else {
// BluetoothがOFFだった時の処理
}
}

super.onActivityResult(requestCode, resultCode, data);
}

なお、BluetoothがOFFである、という結果が返ってきた場合は2.以降の処理をキャンセルして、再度Bluetoothの有効化を求める処理が必要となります。

(2)ロボホンと接続済みのBluetooth機器を確認する

BluetoothAdapter#getBondedDevices()を呼ぶと過去に接続したことがあるBluetooth機器をリストをして取得できます。
そのリストをforループで調べて、もし血圧計が見つかればそのMACアドレスを取得します。
血圧計が見つかったかどうかは、そのデバイス名をキーとして判断しています。
MACアドレスを取得した後は(4)に進みます。
当然ながら初めて接続する場合は見つからないため(3)に進みます。

(3)血圧計を探す

血圧計を探すためにBluetoothAdapter#getBluetoothLeScanner()を呼んで、BluetoothLeScannerインスタンスを取得します。
その後、BluetoothLeScanner#startScan(ScanCallback callback)でスキャン開始します。
この2つのメソッドに渡すコールバックにスキャンした結果が渡されます。
private final ScanCallback scanCallback = new ScanCallback() {
@Override public void onScanResult(int callbackType, final ScanResult result) {
super.onScanResult(callbackType, result);

if (result != null && result.getDevice() != null && deviceAddress == null) {
BluetoothDevice device = result.getDevice();
// deviceが血圧計であれば、そのMACアドレスを取得する
}
}
};

スキャンは負荷が大きいので接続処理が完了したら、BluetoothLeScanner#stopScan(ScanCallback callback)でスキャンを中止します。また、タイムアウト時間を設定して血圧計が見つからない場合でも指定時間後にスキャンを中止すると負荷を軽減できます。

(4)Serviceを起動する

血圧計に接続したり接続状況を確認したりするために使うServiceを起動します。

Intent intent = new Intent(MainActivity.this, BluetoothLeService.class);

bindService(intent, serviceConnection, BIND_AUTO_CREATE);
BluetoothLeServiceは今回作ったServiceを継承しているクラス、serviceConnectionはServiceの接続状況を受け取るコールバックです。

private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName componentName, IBinder service) {
bluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();

// (5)で説明します
}

@Override public void onServiceDisconnected(ComponentName componentName) {
bluetoothLeService = null;
}
};

接続された時にonServiceConnectedメソッドが呼ばれるのでそこでServiceのインスタンスを取得します。またここでServiceの初期化や血圧計との接続を行います。なお、onServiceDisconnectedメソッドは異常終了した場合のみ呼ばれるので、正常にServiceが切断された場合は呼ばれません。

(5)血圧計との接続

まず、BluetoothAdapter#getRemoteDevice(String address)を呼んで、血圧計のMACアドレスからBluetoothDeviceインスタンスを取得します。
その後、BluetoothDevice#connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)メソッドで接続します。第二引数は、「利用可能になったらすぐに自動的に接続する」のであればtrue、「自らが手動で直接接続する」のであればfalseを渡します。第三引数にGATTプロファイルのイベントを受け取るコールバックを渡します。
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
// Bluetooth機器が接続or切断された
@Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
// (6)で説明します
}
// Bluetooth機器のサービスが見つかった
@Override public void onServicesDiscovered(BluetoothGatt gatt, int status) {
// (7)で説明します
}
// Bluetooth機器にCharacteristicの書き込みがあった
@Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
// (8)で説明します
}
// Bluetooth機器からCharacteristicの変更が通知された
@Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// (9)で説明します
}
};

(6)血圧計が持つサービスを探す

血圧計が接続された場合に血圧計のServiceを探します。
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt.discoverServices();
}

(7)血圧計に時刻を設定する

血圧計のServiceが見つかった場合、時刻のCharacteristicを取得してそこに現在時刻を設定(書き込み)します。
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService service = gatt.getService(UUID.fromString(“00001810-0000-1000-8000-00805f9b34fb”));
if (service != null) {
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(“00002a08-0000-1000-8000-00805f9b34fb”));
if (characteristic != null) {
// Bluetooth機器に時刻を設定する
}
}
}

(8)血圧計でIndicationを行う

血圧計に時刻を設定できた場合、血圧計のServiceから血圧測定のCharacteristicを取得して、そこにIndicationを要求します。
if (status == BluetoothGatt.GATT_SUCCESS && UUID.fromString(“00002a08-0000-1000-8000-00805f9b34fb”).equals(characteristic.getUuid())) {
BluetoothGattService service = gatt.getService(UUID.fromString(“00001810-0000-1000-8000-00805f9b34fb”));
if (service != null) {
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(“00002a35-0000-1000-8000-00805f9b34fb”));
if (characteristic != null) {
gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(“00002902-0000-1000-8000-00805f9b34fb”));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
}

(9)血圧計の測定データを取得する

血圧計の測定が完了するとデータが送られてくるので、そのデータが血圧測定のCharacteristicだった場合に、血圧計の測定データを処理します。

if (UUID.fromString(“00002a08-0000-1000-8000-00805f9b34fb”).equals(characteristic.getUuid())) {
// BluetoothGattCharacteristicから測定した情報を取得
}
以上がロボホンと血圧計を繋いでデータを取得するまでの流れです。
後半のどうやって測定したデータを受け取るか、というところが複雑なのでフローをしっかりと整理する必要があります。

今回はデータを受け取ってからの処理については扱っていませんが、ロボホンに測定結果を喋らせるとよりアプリの完成度が高まりますね!

%d人のブロガーが「いいね」をつけました。