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