3日ほど連続で似たような記事になりましたが、ようやく解決したので今回が最後です!
Android 端末と Bluetooth デバイスを接続して、データを取得する方法です。
今回参考にさせていただいた記事はこちら。
【連載】Bluetooth LE (5) Android 4.3 で Bluetooth LE 機器を使う (フェンリル | デベロッパーズブログ)
https://blog.fenrir-inc.com/jp/2013/10/bluetooth-le-android.html04.BLEデバイスから値を読み込む処理を作る
https://www.hiramine.com/programming/blecommunicator/04_read_characteristic.html
特に 2つ目の記事は、ひとつ前の「03.BLEデバイスとの接続・切断の処理を作る」という記事からお世話になってます。
さて、実装の方法ですが、今まで使おうとしていた BluetoothSocket クラスではなく、BluetoothGatt クラスを使うとうまくいきました。
サンプルコードはこちらです。
// デバイスと接続する
BluetoothDevice connectDevice = mBtAdapter.getRemoteDevice([デバイスのアドレス]);
connectDevice.connectGatt(getBaseContext(), true, bluetoothGattCallback);
// コールバック処理
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange (BluetoothGatt gatt, int status, int newState) {
// デバイス接続のステータスが変化したら呼ばれる
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices();
} else {
Log.d(TAG, "onConnectionStateChange() failed");
gatt.disconnect();
}
}
@Override
public void onServicesDiscovered (BluetoothGatt gatt, int status) {
// サービスを検索後呼ばれる
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService service = gatt.getService(UUID.fromString(DEVICE_BUTTON_SENSOR_SERVICE_UUID));
if (service != null) {
// サービスを見つけた
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(DEVICE_BUTTON_SENSOR_CHARACTERISTIC_UUID));
if (characteristic != null) {
// キャラクタリスティックを見つけた
// Notification を要求する
boolean registered = gatt.setCharacteristicNotification(characteristic, true);
if (registered) {
// Characteristic の Notification 有効化
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(CLIENT_CHARACTERISTIC_CONFIG));
if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.readDescriptor(descriptor);
} else {
Log.d(TAG, "descriptor null");
}
} else {
// Characteristics 通知設定が失敗
Log.d(TAG, "Characteristics 通知設定が失敗");
}
} else {
Log.d(TAG, "characteristic null");
}
} else {
Log.d(TAG,"service null");
gatt.disconnect();
}
} else {
Log.d(TAG, "onServicesDiscovered() failed");
}
}
@Override
public void onCharacteristicChanged( BluetoothGatt gatt, BluetoothGattCharacteristic characteristic ) {
// Characteristic が変化したら呼ばれる
byte[] data = characteristic.getValue();
StringBuilder sb = new StringBuilder();
for (byte data1 : data) {
sb.append(String.format("%02X ", data1));
}
String result = sb.toString();
Log.d(TAG, result);
}
};
デバイスの接続には、BluetoothDevice のメソッドの .connectGatt を使っています。
で、これが実行されて、デバイス接続のステータスが変わると、コールバック内の onConnectionStateChange が呼ばれます。
2個目の引数の int status で成功したかどうかを、3つ目の引数 int newState で変更後のステータスが返されますので、それぞれの値で、接続が成功したかを判断します。
で、成功していたら、gatt.discoverServices() を呼び出します。
こちらが呼ばれ、処理が完了すると、onServicesDiscovered が呼ばれるので、この内部で、データを取得の処理を行います。
BluetoothGattService、BluetoothGattCharacteristic、BluetoothGattDescriptor を順番に定義し、成功したら最後に gatt.readDescriptor(descriptor) を呼び出してデータを取得します。
なお、この時に使う UUID は、最後の CLIENT_CHARACTERISTIC_CONFIG 以外、それぞれの環境にあったものにしてください。
私はどれが正しい値化が分からなかったため、gatt.getServices()、service.getCharacteristics() で UUID の一覧を取得し、1つずつ実際に実行して試すというアナログな方法を使いました。
ちなみに、CLIENT_CHARACTERISTIC_CONFIG の値は 00002902-0000-1000-8000-00805f9b34fb です。
正しく設定ができたら、データを取得します。
データを取得するたびに onCharacteristicChanged が呼び出されますので、characteristic.getValue() を使って都度データを取得します。
私の場合、取得した byte の配列を 半角スペース区切りの16進数に変換したかったので、その様な処理になっています。
なお、最終的な結果は Log.d() で吐き出しているだけなので、こちらは適宜変更してください。
以上、Android 端末と Bluetooth デバイスを接続し、データを取得する方法でした。
勘違いをしたせいで大分長くかかってしまった…!
でも、何とか完成できたので良かったです。
大分迷走してしまいましたが、ご参考になれば幸いです。