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

ord*_*sen 9 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扫描仪应用程序取消订阅.(我可以通过Log看到这个)

我的android代码如下: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) {
            }
        };
Run Code Online (Sandbox Code Playgroud)

这就是我连接GATT的方式:

        bt_device = createBluetoothDevice(DEVICE_ADRESS);
        BluetoothGatt mBluetoothGatt = bt_device.connectGatt(context, false, mGattCallback);
Run Code Online (Sandbox Code Playgroud)

所有这些代码都在后台服务中运行,后台服务在选择BLE设备后启动.

我尝试的是实现Google Dev API指南中演示的内容,我也试过这个解决方案(没有成功).既没有在谷歌上搜索,也没有在SO(例如这个)上阅读问题或者看过北欧开发者专区,这在这种情况下确实有很大帮助.

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

编辑全球类:

// 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");
Run Code Online (Sandbox Code Playgroud)

编辑我在BLE扫描仪中做的事情: 我只是扫描BLE设备.它找到了我的设备并在点击它之后向我展示了我在Arduino板上设置的所有服务.选择服务后,它会显示我为此服务指定的所有聊天功能.当我点击一个特征时,它会显示它的UUID及其服务的UUID.此外,BLE扫描仪应用程序允许我订阅通知或阅读特征.订阅时,该值会不断更新.

ord*_*sen 9

所以,我最终弄清楚了我的错误:)正如你在上面看到的那样,我使用的UUID具有与我的描述符相同的基础作为我的特征(从开始3f54XXXX-....)

我把它改成了public static final UUID X_ACCEL_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");,现在一切都按预期工作了.

之前我没有这样做,因为我认为应该有每个特征的描述符.但实际上,根据客户端特性配置 ...

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

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

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