浜松のWEBシステム開発・スマートフォンアプリ開発・RTK-GNSS関連の開発はお任せください
株式会社シーポイントラボ
TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:静岡県浜松市中区富塚町1933-1 佐鳴湖パークタウンサウス2F

【Java】Android端末とBluetoothデバイスを接続してデータを取得する

3日ほど連続で似たような記事になりましたが、ようやく解決したので今回が最後です!
Android 端末と Bluetooth デバイスを接続して、データを取得する方法です。

今回参考にさせていただいた記事はこちら。

【連載】Bluetooth LE (5) Android 4.3 で Bluetooth LE 機器を使う (フェンリル | デベロッパーズブログ)
https://blog.fenrir-inc.com/jp/2013/10/bluetooth-le-android.html

04.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 が呼ばれるので、この内部で、データを取得の処理を行います。
BluetoothGattServiceBluetoothGattCharacteristicBluetoothGattDescriptor を順番に定義し、成功したら最後に 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 デバイスを接続し、データを取得する方法でした。
勘違いをしたせいで大分長くかかってしまった…!
でも、何とか完成できたので良かったです。
大分迷走してしまいましたが、ご参考になれば幸いです。

  • この記事いいね! (2)