【问题标题】:BLE GATT onCharacteristicChanged not called after subscribing to notification订阅通知后未调用 BLE GATT onCharacteristicChanged
【发布时间】:2015-07-17 07:16:20
【问题描述】:

这是我在 SO 上的第一篇文章。

我在 android 5.0.2 上订阅 GATT 通知时遇到一些问题。

我的目标是将带有 BLE Shield 的 Arduino 连接到我的 Android 手机。我有一个连接到 Arduino 的传感器,并希望使用 BLE 屏蔽将数据从 Arduino 发送到我的手机。 盾上有一个nRF8001是服务器,我的手机/应用程序是客户端。

我所做的到目前为止是创建一个扫描 BLE 设备的 Android 应用程序。它可以连接到设备并读取或写入特征。所以,我可以通过调用gatt.readCharacteristic(mCharacteristic);“手动”读取特征。这使我可以从 Arduino 获取传感器值。 我还使用 nRFGo Studio 创建了一个自定义服务。我知道这部分正在工作,因为我能够通过使用 Google Play 上提供的 BLE Scanner 应用程序来发现、连接甚至收到有关特性更改的通知。 但是在我自己的应用程序中订阅通知是行不通的。好吧,至少订阅有效,但永远不会调用 onCharacteristicChanged(...)。有趣的是,如果我在我的应用程序中订阅了该特性,然后之后 使用 BLE 扫描仪应用程序订阅它,就会突然调用onCharacteristicChanged(...),直到我再次通过 BLE 扫描仪应用程序取消订阅。 (我可以通过日志看到这一点)

我的安卓代码如下: 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 指南中演示的内容,我还尝试了 this solution(没有成功)。在 Google 上搜索、阅读 SO 上已经提出的问题(例如 this one )或查看北欧开发者专区在这种情况下都没有多大帮助。

最后,我的问题是:我做错了什么?我错过了什么吗? 我只是想不通,这让我发疯了两天。我不知道我还能在哪里寻找解决方案,所以我希望你能帮助我..

编辑全局类:

// 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 应用程序允许我订阅通知或读取特征。当我订阅时,值会不断更新。

【问题讨论】:

  • 你能发布你的Globals吗?
  • 另外,您能否发布您在 BLE 扫描仪中所做的工作以使其正常工作?
  • 是的,我主要想知道您是否确定您的 UUID 与您在 BLE 扫描仪中选择的匹配。
  • 感谢您的链接,但我已经找到了这个:因为我没有多个特征,所以我没有创建队列。目前,我没有修改或编写任何特征,但这样做是为了测试目的。不过,当我测试阅读时,我确保之前调用了 onDescriptorWrite()。重新启动我的设备也没有帮助。描述符的写法与第一个答案中的相似。我还重新检查了 UUID,但它们都与 BLE 扫描仪中的 UUID 和我在 nRFGo Studio 中设置的一致。

标签: android arduino bluetooth-lowenergy gatt


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    所以,我终于发现了我的错误 :) 正如您在上面看到的,我使用的 UUID 与我的描述符的基数与我的特征相同(以 3f54XXXX-.... 开头)

    我将其更改为public static final UUID X_ACCEL_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");,现在一切正常。

    我以前没有这样做,因为我认为每个特征都应该有一个描述符。但其实根据Client Characteristic Configuration...

    [...] 描述符应在绑定设备的连接中保持不变。客户端特征配置描述符对于每个客户端都是唯一的。

    所以我检查了 RedBearLab Android App 示例,发现描述符的 UUID 等于发布在其他 SO 答案上的 UUID。

    这也解释了为什么我的应用程序在 BLE 扫描仪应用程序中启用它们后收到通知:由于描述符应在绑定设备的连接中保持不变,因此 BLE 扫描仪应用程序也将此 UUID 用于描述符,因此为客户(= 我的手机)。

    【讨论】:

      猜你喜欢
      • 2015-01-20
      • 2017-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-28
      • 2015-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多