X

Bluetooth Health Deviceと通信する

Android 4.0(IceCreamSandwich)からBluetoothのHealthデバイスのサポートが追加されました。
ヘルスデバイスとは医療、フィットネス、健康器具などヘルス分野の製品のことで、Bluetooth Health Device Profile(HDP)としてBluetoothでは通信を規格化しています。
4.0での対応により、AndroidからもHDP対応ヘルスデバイスを使えることになりました。Health Device Profile対応により、血圧計、歩数計や体重計など健康器具とのデータ交換が容易に行えます。

今回は、Bluetooth Health Deviceとの通信方法を紹介します。
android.bluetoothパッケージにBluetooth Health関連クラスが追加されています。

追加されたクラス名説明
BluetoothHealthクラスBluetoothHealthデバイスを管理する
BluetoothHealthAppConfigurationクラスBluetoothHealthデバイスへの接続設定を保持する
BluetoothHealthCallbackクラス BluetoothHealthデバイスの状態変更通知を受け取る

application configurationとは、ヘルスデバイスとの接続に利用されるアプリケーション設定で、サードパーティ、開発者がヘルスデバイスとBluetoothで通信するための状態通知コールバック設定、設定名などが格納されています。

接続するためのサンプルコードは以下のとおりです。
※Android 4.0およびヘルスデバイスを入手できていないため、本記事でのサンプルコードは、概要を理解するためのコードスニペットとお考えください。実際に試すには修正が必要です。

ヘルスデバイスの検出処理

以下はヘルスデバイスの検出と切断に合わせて、ヘルスデバイスを管理するためのBluetoothHealthインスタンスを取得するサンプルコードです。
ここでは、BluetoothAdapter(Bluetooth接続のためのアダプタ)からヘルスデバイス接続通知を受け取り、BluetoothHealthインスタンスを取得します。

サンプルコード

BluetoothHealth mBluetoothHealth;
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

// デフォルトアダプタからヘルスデバイスへの接続権を取得する
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEALTH);

private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
        if (profile == BluetoothProfile.HEALTH) {
            //ヘルスデバイスが検出された
            mBluetoothHealth = (BluetoothHealth) proxy;
        }
    }
    public void onServiceDisconnected(int profile) {
        if (profile == BluetoothProfile.HEALTH) {
            //ヘルスデバイスが切断された
            mBluetoothHealth = null;
        }
    }
};

5行目:デフォルトアダプタのgetProfileProxyメソッドをつかって、ヘルスデバイスの接続状態が変化した際に、通知するリスナーを登録します。
7行目:BluetoothProfile.ServiceListener(mProfileListenerインスタンス)を作成します。
9行目:接続されたprofileの種類がヘルスデバイスであれば、ヘルスデバイスが接続されたと判断します。
11行目:受け取ったproxyはBluetoothProfileクラスなので、BluetoothHealthクラスにキャストして利用します。
17行目:もし、ヘルスデバイスが切断された場合は、インスタンスは失われるため、null代入して処理を終了します。

ヘルスデバイスとの接続

接続するためのアプリケーション設定

Bluetooth Health Device Profile(HDP)では、ヘルスデバイスと通信するためのDataTypeが定められています。

データタイプ説明
BluetoothHealth.SOURCE_ROLEデータを提供する(ヘルスデバイス)側
BluetoothHealth.SINK_ROLEデータを受信する(受け取る機器)側

これらデータタイプは表の通り、動作に制約があります。SINKタイプであれば複数のSOURCE(ヘルスデバイス側)から情報を受け取ることができますが、その反対は出来ません。SOURCE側はあくまでデータを送出するためのデータタイプです。
実際に接続対象(例えば血圧計、歩数計など複数のデバイスが接続済みの際に血圧計を探す、など特定の)ヘルスデバイスと接続する際は、BluetoothHealthクラスのregisterSinkAppConfigurationメソッドを使って通信するための準備を行います。このメソッドでは接続状態など通信処理に必要なコールバックを受けるための設定を行います。
以下のサンプルコードをみて実際の処理を確認しましょう。

サンプルコード

    private void registerHealthDevices(){

    	MyBluetoothHealthCallback mCallback = new MyBluetoothHealthCallback();
    	mBluetoothHealth.registerSinkAppConfiguration("HEALTH_DEVICES",BluetoothHealth.SINK_ROLE, mCallback);

    }

	class MyBluetoothHealthCallback extends BluetoothHealthCallback {

		@Override
		public void onHealthAppConfigurationStatusChange(
				BluetoothHealthAppConfiguration config, int status) {
			super.onHealthAppConfigurationStatusChange(config, status);

			// TODO : 接続したいヘルスデバイス(3rdパーティ製品など)のconfigを覚える
			mHealthConfig = config;
		}

		@Override
		public void onHealthChannelStateChange(
				BluetoothHealthAppConfiguration config, BluetoothDevice device,
				int prevState, int newState, ParcelFileDescriptor fd, int channelId) {

			super.onHealthChannelStateChange(config, device, prevState,
					newState, fd, channelId);

			// TODO: ヘルスデバイスの状態変更通知
			mChannelId = channelId;
		}
	};

	private void unregisterHealthDevices(){
		mBluetoothHealth.unregisterAppConfiguration(mHealthConfig);
	}

4行目:BluetoothHealthクラスのregisterSinkAppConfigurationメソッドを使って、ヘルスデバイスに接続するための設定を行います。
11行目:BluetoothHealthCallbackクラスのonHealthAppConfigurationStatusChangeメソッドは、ヘルスデバイスとのアプリケーション設定情報の状態通知です。変更がある度、呼び出されることになります。statusは BluetoothHealth.APP_CONFIG_REGISTRATION_SUCCESS もしくは BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE が返却されます。
20行目:BluetoothHealthCallbackクラスのonHealthChannelStateChangeメソッドは、ヘルスデバイスとの接続状態通知です。ヘルスデバイスとの接続状況が変化すると呼び出されます。
prevState、newStateの値は以下の表に従います。

BluetoothHealthのフィールド名該当チャンネルの状態
STATE_CHANNEL_CONNECTED接続完了
STATE_CHANNEL_CONNECTING接続中
STATE_CHANNEL_DISCONNECTED切断完了
STATE_CHANNEL_DISCONNECTING切断中

32行目:BluetoothHealthクラスのunregisterAppConfigurationメソッドを使ってアプリケーション設定mHealthConfigを破棄します。

ヘルスデバイスとの接続

ここまでくると、あとは今までに取得したBluetoothDevice情報、アプリケーション設定(mHealthConfig)を利用してヘルスデバイスとの接続・切断を行うだけです。

サンプルコード

	private void connect(){
		//Bluetoothデバイスに、コンフィグを使って接続する
		mBluetoothHealth.connectChannelToSource(mBluetoothDevice, mHealthConfig);
	}

	private void disconnect(){
		//ヘルスデバイスと切断
		mBluetoothHealth.disconnectChannel(mBluetoothDevice, mHealthConfig, mChannelId);
	}

3行目:BluetoothHealthクラスのconnectChannelToSourceメソッドを使って、ヘルスデバイスに接続します。
ヘルスデバイスと接続できると、前述のBluetoothHealthCallbackクラスのonHealthChannelStateChangeメソッドが呼ばれます。onHealthChannelStateChangeメソッドの引数にチャンネルIDが渡されますので、覚えておき、データ取得時、切断時に利用します。
8行目:disconnectChannelメソッドで接続を終了します。終了後に再接続したい場合は改めて、connectChannelToSourceメソッドを呼びだしてください。

すこし長くなりましたが、ヘルスデバイスに接続するまでをサンプルコード(コードスニペット)を利用して紹介しました。実際に利用する際はヘルスデバイスに応じてサンプルコードの修正が必要となりますので、十分注意してください。
以上、おつかれさまでした!

mhidaka: Software Engineerだよ。DroidKaigi Organizer / Androidと組込とRe:VIEW。techbooster主宰。mhidaka's writings http://booklog.jp/users/mhidaka 技術書典! http://techbookfest.org