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 デバイスを接続し、データを取得する方法でした。
勘違いをしたせいで大分長くかかってしまった…!
でも、何とか完成できたので良かったです。
大分迷走してしまいましたが、ご参考になれば幸いです。