BLE GATT onCharacteristicChanged在订阅通知后没有调用

时间:2015-05-06 22:30:46

标签: android arduino bluetooth-lowenergy gatt

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

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

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

到目前为止

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

我的Android代码如下: 关贸总协定回调:

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)上阅读已经问过的问题,或者在北欧开发者专区看一下这些都对这种情况有所帮助。

最后,我的问题是:我做错了什么?我错过了什么吗? 我无法弄清楚它现在让我疯了两天。我不知道我还能在哪里寻找解决方案,所以我希望你能帮助我......

EDIT Globals Class:

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

2 个答案:

答案 0 :(得分:9)

所以,我最终弄明白了我的错误:) 正如您在上面所看到的,我使用的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作为描述符,因此启用了通知客户(=我的电话)。

答案 1 :(得分:1)

customBluetoothGatt.setCharacteristicNotification(特征,已启用);

    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