web-dev-qa-db-ja.com

通知をサブスクライブした後、BLE GATTonCharacteristicChangedが呼び出されない

これはSOに関する私の最初の投稿です。

Android 5.0.2でGATT通知を購読する際に問題が発生しました。

私が目指していることは、BLEシールドを備えたArduinoを私のAndroid電話に接続することです。センサーを持っていますArduinoに接続していて、BLEシールドを使用してArduinoから私の電話にデータを送信したい。サーバーであるシールドにnRF8001があり、私の電話/アプリがクライアントです。

これまで私がしたことは、BLEデバイスをスキャンするAndroidアプリを作成することでした。デバイスに接続できますgatt.readCharacteristic(mCharacteristic);を呼び出すことで、特性を「手動で」読み取ることができます。これにより、Arduinoからセンサー値を取得できます。また、nRFGoStudioを使用してカスタムサービスを作成しました。I Google Playで利用できるBLEスキャナーアプリを使用して、特性の変更を検出、接続、さらには通知を受け取ることができるため、この部分が機能していることを知っています。しかし、自分のアプリで通知をサブスクライブすることはできません。 。まあ、少なくともサブスクリプションは機能しますが、onCharacteristicChanged(...)が呼び出されることはありません。面白いのは、アプリの特性をサブスクライブすると、後でという事実です。 BLEスキャナーアプリでサブスクライブするBLEスキャナーアプリで再度サブスクライブを解除するまで、突然onCharacteristicChanged(...)が呼び出されます(これはログで確認できます)

My Android codeは次のとおりです:GATTコールバック:

private final BluetoothGattCallback mGattCallback =
        new BluetoothGattCallback() {
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                                int newState) {
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    sendBroadcastConnected();

                    Log.i("BLE", "Connected to GATT server.");
                    Log.i("BLE", "Attempting to start service discovery:" + bleManager.startServiceDiscovery());

                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    sendBroadcastDisconnected();
                    Log.i("BLE", "Disconnected from GATT server.");
                }
            }

            @Override
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    Log.w("BLE", "onServicesDiscovered ");
                    setNotifySensor(gatt);     
                }
            }

            private void setNotifySensor(BluetoothGatt gatt) {
                BluetoothGattCharacteristic characteristic = gatt.getService(Globals.MPU_SERVICE_UUID).getCharacteristic(Globals.X_ACCEL_CHARACTERISTICS_UUID);
                gatt.setCharacteristicNotification(characteristic, true);

                BluetoothGattDescriptor desc = characteristic.getDescriptor(Globals.X_ACCEL_DESCRIPTOR_UUID);
                Log.i("BLE", "Descriptor is " + desc); // this is not null
                desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                Log.i("BLE", "Descriptor write: " + gatt.writeDescriptor(desc)); // returns true

            }

            @Override
            public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                               if(Globals.X_ACCEL_CHARACTERISTICS_UUID.equals(characteristic.getUuid())){
                    Log.w("BLE", "CharacteristicRead - xaccel service uuid: " + characteristic.getService().getUuid());
                    Log.w("BLE", "CharacteristicRead - xaccel value: " + characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8,0));
                }
            }

            @Override
            public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                Log.i("BLE", "Received characteristics changed event : "+characteristic.getUuid());
                if(Globals.X_ACCEL_CHARACTERISTICS_UUID.equals(characteristic.getUuid())){
                    Log.i("BLE", "Received new value for xAccel.");
                }


            }

            @Override
            public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            }

            @Override
            public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            }

            @Override
            public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            }
        };

これが私がGATTに接続する方法です:

        bt_device = createBluetoothDevice(DEVICE_ADRESS);
        BluetoothGatt mBluetoothGatt = bt_device.connectGatt(context, false, mGattCallback);

このコードはすべて、BLEデバイスが選択された後に開始されるバックグラウンドサービスで実行されます。

私が試したのは、Google Dev APIガイドに示されているようなものを実装することでした。また、 このソリューション (なし成功)。この場合、Googleで検索したり、SO(たとえば、 これ ))で既に尋ねられた質問を読んだり、北欧の開発者ゾーンを調べたりすることはあまり役に立ちませんでした。

最後に、私の質問は次のとおりです:私は何を間違えましたか?私は何かが足りないのですか?私はそれを理解することができず、それは私を2日間夢中にさせています。他にどこで解決策を探すことができるかわからないので、あなたが私を助けてくれることを願っています。

グローバルクラスの編集:

// BLE Services
public static final UUID MPU_SERVICE_UUID = UUID.fromString("3f540001-1ee0-4245-a7ef-35885ccae141");
// BLE Characteristics
public static final UUID X_ACCEL_CHARACTERISTICS_UUID = UUID.fromString("3f540002-1ee0-4245-a7ef-35885ccae141");
// BLE Descriptors
public static final UUID X_ACCEL_DESCRIPTOR_UUID = UUID.fromString("3f542902-1ee0-4245-a7ef-35885ccae141");

編集BLEスキャナーで行うこと:BLEデバイスをスキャンするだけです。デバイスが検出され、タップすると、Arduinoボードに設定したすべてのサービスが表示されます。サービスを選択すると、このサービスに指定したすべてのチャット機能が表示されます。特性をタップすると、そのUUIDとサービスのUUIDが表示されます。また、BLE Scannerアプリを使用すると、通知をサブスクライブしたり、特性を読み取ったりすることができます。サブスクライブすると、値は継続的に更新されます。

9
ordsen

だから、私は最終的に私の間違いを理解しました:)上記のように、私は私の特性と同じベースの記述子を持つUUIDを使用しています(_3f54XXXX-...._で始まります)

public static final UUID X_ACCEL_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");に変更しましたが、すべてが期待どおりに機能しています。

各特性に記述子があるべきだと思ったので、以前はこれをしませんでした。しかし実際には、 クライアント特性構成 によると...

[...]記述子は、結合されたデバイスの接続間で永続的でなければなりません。クライアント特性構成記述子は、クライアントごとに一意です。

そこで、RedBearLab Androidアプリの例を確認したところ、記述子のUUIDが他のSO回答に投稿されたものと等しいことがわかりました。

これは、BLE Scannerアプリで通知を有効にした後にアプリが通知を受信した理由も説明しています。記述子はボンディングされたデバイスの接続間で永続的であるため、BLE Scannerアプリは記述子にこのUUIDも使用し、クライアントの通知を有効にしました(=私の電話)。

9
ordsen

customBluetoothGatt.setCharacteristicNotification(characteristic、enabled);

    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
    boolean success = customBluetoothGatt.writeDescriptor(descriptor);

次に、記述子プロパティENABLE_INDICATION_VALUEを設定します