Не удается найти пользовательскую службу GATT

#uwp #bluetooth-lowenergy

#uwp #bluetooth — низкое энергопотребление

Вопрос:

В моем приложении UWP я могу обнаружить свое приложение для Android, запущенное на устройстве, и прочитать его характеристику имени устройства

Это работает. Но в том же приложении для Android у меня есть пользовательский сервис, который я добавил в GATT с характеристикой чтения. Я могу найти свой сервис из другого приложения для Android, но не могу сделать это в своем приложении UWP. Вот мой код:

 if (ulong.TryParse(deviceAddress, out ulong address))
{
    BluetoothLEDevice bluetoothLeDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(address);

    // the name of the device of bluetoothLeDevice matches my device, so I know I have the right address

    var serviceId = new Guid(myCustomServiceId);

    GattDeviceServicesResult result = await bluetoothLeDevice.GetGattServicesForUuidAsync(serviceId);
    var q = await bluetoothLeDevice.GetGattServicesAsync();

    if (q?.Status == GattCommunicationStatus.Success)
    {
        foreach (var x in q.Services) // q.Services is empty
        {
            // never comes in here
        }
    }
}
  

Есть идеи, почему?

Комментарии:

1. У вас есть смартфон (iOS или Android) отдельно от вашего приложения для Android? Если это так, используйте приложение nRF Connect от Nordic, чтобы убедиться, что ваше приложение для Android публикует сервисы должным образом и что у вас правильные UUID.

2. Еще один совет: используйте GetGattServicesAsync вместо GetGattServicesForUuidAsync для перечисления всех сервисов и исключите, что ваш UUID / GUID неверен.

3. Я попытался использовать GetGattServicesAsync и единственный uuid, который я нашел, был 00001800-0000-1000-8000-00805f9b34fb . Я могу найти его с устройства iOS, поэтому, должно быть, я что-то делаю неправильно в своем приложении UWP.

4. Я использовал приложение nRF Connect, чтобы убедиться, что мой Android публикует сервисы, как ожидалось, и это так. Но у меня есть подключение к нему, чтобы прочитать мою характеристику. Нужно ли мне также подключаться из моего приложения UWP?

5. Я почти уверен, что мне нужно сначала подключиться к устройству, потому что я должен в своих реализациях Android и iOS. Но я все равно не могу найти подключение, я вижу только сопряжение…

Ответ №1:

Установили ли вы возможности ble в своем Package.appxmanifest?
Если вы используете visual studio, найдите Package.appxmanifest и дважды щелкните его. перейдите на вкладку «Возможности» и проверьте Bluetooth и сохранение.
Вы также можете использовать xml-редактор для изменения Package.appxmanifest. Добавить:

 <Capabilities>
    <DeviceCapability Name="bluetooth" />
</Capabilities>
  

Если вы уже установили возможности, посмотрите на мой SimpleBleExample_by_Devicename
на Github:
https://github.com/GrooverFromHolland/SimpleBleExample_by_Devicename

Нет никаких элементов управления, чтобы сделать его максимально простым. Все результаты отображаются в окне вывода отладки.

Комментарии:

1. Я добавил эту возможность. Одна вещь, которую я заметил в исходном коде примера, заключается в том, что GetGattServicesForUuidAsync вызывается OnAdvertisementReceivedAsync . В моем коде я вызываю его при нажатии кнопки, поэтому поток пользовательского интерфейса … будет ли это проблемой?

2. Если бы это было проблемой, вы бы вызвали исключение в режиме отладки. Большим преимуществом использования advertisementwacher является то, что вы знаете, что устройство доступно и доступно для подключения. Если вы делаете это с помощью нажатия кнопки, вы не знаете.

3. Устройство Android находится рядом с моим рабочим столом, на котором запущено приложение UWP, но я попытался получить свой сервис в Received обратном вызове my BluetoothLEAdvertisementWatcher и до сих пор не могу его найти. Единственное, что я делаю по-другому, это то, что весь мой код, связанный с BLE, находится в отдельном проекте от моего основного приложения; что, я думаю, тоже не будет проблемой..

4. Попробуйте запустить мой пример, он предоставит вам информацию об отладке в окне вывода для каждого шага, чтобы вы знали, что происходит. Вам потребуется несколько минут, чтобы запустить его. Просто нажмите clone или download на Github, разархивируйте загруженный файл, измените bleDevicName, MyService_GUID и MYCharacteristic_GUID в MainPage.xaml.cs, затем запустите приложение.

5. Я попробовал ваше приложение, но не смог найти в нем свои сервисы. Между прочим, это приведет к сбою в строке service = services[0]; , когда служб нет. Кроме того, eventArgs.Advertisement.LocalName для меня он всегда будет пустым, поскольку я рекламирую UUID, который занимает большую часть полезной нагрузки.

Ответ №2:

Что решило это для меня, так это то, что вместо того, чтобы пытаться найти мою службу / характеристику при обратном вызове по нажатию кнопки, я нахожу их в myBluetoothLEAdvertisementWatcher.Received обратном вызове:

 private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
    bool isMyDevice = false;

    // figure out if isMyDevice should be true by checking the advertised service uuids

    if (isMyDevice)
    {
        var bluetoothLeDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);

        var serviceId = new Guid(My_Service_UUID);

        var result = await bluetoothLeDevice.GetGattServicesForUuidAsync(serviceId);

        if (result?.Status == GattCommunicationStatus.Success)
        {
            var service = result.Services.FirstOrDefault(s => s.Uuid == serviceId);

            if (service != null)
            {
                Log?.Invoke("service found!");

                var characteristicId = new Guid(My_Characteristic_UUID);

                var characteristic = await service.GetCharacteristicsForUuidAsync(characteristicId);

                if (characteristic?.Status == GattCommunicationStatus.Success)
                {
                    var c = characteristic.Characteristics.FirstOrDefault(x => x.Uuid == characteristicId);

                    if (c != null)
                    {
                        Log?.Invoke("characteristic found");

                        var v = await c.ReadValueAsync();

                        if (v?.Status == GattCommunicationStatus.Success)
                        {
                            var reader = DataReader.FromBuffer(v.Value);
                            byte[] input = new byte[reader.UnconsumedBufferLength];
                            reader.ReadBytes(input);

                            // Utilize the data as needed
                            string str = System.Text.Encoding.Default.GetString(input);
                            Log?.Invoke(str);
                        }
                    }
                }
            }
        }
    }
}
  

Этот инструмент также очень полезен для всех, кто разрабатывает с BLE:

https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BluetoothLE

Это позволяет вам читать службы / характеристики любого ближайшего устройства BLE. Может очень помочь в тестировании. Приложение nRF Connect также хорошо подходит для тестирования.