Hello World для получения данных с Bluetooth (BLE) устройства через C#

от автора

Добрый день.
Пару недель назад я столкнулся с проблемой, что нормальной и современной статьи по первому получению данных с Bluetooth просто нет. И пришлось повозиться чтобы понять с чего начать и как это вообще осуществить. И чтобы люди не повторяли мои ошибки, вот краткое эссе о том как это можно сделать.

Но для начала пару пафосных слов, для чего это вообще нужно. Современный мир все больше погружается в идеологию интернет вещей. Сейчас всё друг с другом взаимодействует, холодильник с плитой, утюг с пылесосом и т.д. Много шума подняли из-за ЭКГ в Apple Watch, но современные тонометры, пульсометры, термометры уже давно умеют предавать данные через Bluetooth. И вот это всё нужно как-то соединить в единую сеть. И ключевым элементом в этой сети является, как ни крути, компьютер. В связи с этим возникла задача получать данные с определённого устройства через Bluetooth.

Начну с того, что уже у нас было и что усугубило поиск решения. А у нас было приложение написанное на .Net Core. В чем суть приложения неважно, для простоты будем считать, что у нас просто консоль на .Net Core. Ну а устройство буду называть литерой N

Первые попытки найти что-то работающее с Bluetooth через C# приведут к библиотеке 32feet.
В NuGet пакетах она звучит так 32feet.NET

И она, кстати, в своей последней продуктовой редакции, даже находит устройства Bluetooth, но не стандарта BLE [как выяснилось гораздо позже]. Например тот же OnePlus 5T стабильно отыскивался, но необходимое устройство N нет. Параллельно с этим удалось отыскать и официальный ответ автора, что его библиотека с BLE не взаимодействует в принципе, и даже нет смысла пробовать. Хотя на Github и есть предварительная версия InTheHand.Devices.Bluetooth, которая должна поддерживать BLE, но в ней так много все подменено, а документации вовсе никакой нет, что даже скомпилировать проект с идеями взятыми с 32feet.NET не сложилось.

Новые изыскания привели меня к более стандартным решениям, а именно к Universal Windows Platform (UWP). При разработке данной платформы, Microsoft, охваченная идеей универсальности и единым приложением для компьютера и телефона, постаралась и сделала взаимодействие с Bluetooth. И вот здесь как раз всё хорошо работает, но… У нас проект на .Net Core… И этим уже ничего не поделаешь.

Сразу скажу, что решения по взаимодействию библиотек UWP с .Net Core отыскать не удалось и проект пришлось переключать на EF 4.7.1., благо это не сложно. Хотя были мысли как оставить проект на .Net Core и например сделать отдельный Windows сервис с передачей данных по именованный каналам (named pipe) или поднять WCF сервис и с ним уже наладить взаимодействие, но в нашем случае это не имело практического смысла.


Так что в итоге мы имеем перед стартом:

  • Проект на EF 4.7.1.
  • Win10 обновлен до версии Version 10.0.17134 Build 17134.

Для начала нужно подключить пару библиотек ручками, а именно

  • «Windows от Universal Windows Platform»
    C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.17134.0\Windows.winmd
  • «System.Runtime.WindowsRuntime»
    C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll

И собственно всё, далее сама работа с устройством идет по документация без проблем.
Взаимодействовать с BLE осуществляется через класс BluetoothLEAdvertisementWatcher
Но нужно не забывать, что не имея API самого устройства что-то толковое сделать не получиться.
Вот мой пример кода, как получить данные с устройства.
Данный код рассчитан на то, что устройство уже добавлено (соединено).

public class BluetoothObserver     {         BluetoothLEAdvertisementWatcher Watcher { get; set; }         public void Start()         {             Watcher = new BluetoothLEAdvertisementWatcher()             {                 ScanningMode = BluetoothLEScanningMode.Active             };             Watcher.Received += Watcher_Received;             Watcher.Stopped += Watcher_Stopped;             Watcher.Start();         }         private bool isFindDevice { get; set; } = false;         private async void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)         {             if (isFindDevice)                 return;             if (args.Advertisement.LocalName.Contains("deviceName"))             {                 isFindDevice = true;                 BluetoothLEDevice bluetoothLeDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);                 GattDeviceServicesResult result = await bluetoothLeDevice.GetGattServicesAsync();                 if (result.Status == GattCommunicationStatus.Success)                 {                     var services = result.Services;                     foreach (var service in services)                     {                         if (!service.Uuid.ToString().StartsWith("serviceName"))                         {                             continue;                         }                         GattCharacteristicsResult characteristicsResult = await service.GetCharacteristicsAsync();                         if (characteristicsResult.Status == GattCommunicationStatus.Success)                         {                             var characteristics = characteristicsResult.Characteristics;                             foreach (var characteristic in characteristics)                             {                                 if (!characteristic.Uuid.ToString().StartsWith("characteristicName"))                                 {                                     continue;                                 }                                 GattCharacteristicProperties properties = characteristic.CharacteristicProperties;                                 if (properties.HasFlag(GattCharacteristicProperties.Indicate))                                 {                                     characteristic.ValueChanged += Characteristic_ValueChanged;                                     GattWriteResult status = await characteristic.WriteClientCharacteristicConfigurationDescriptorWithResultAsync(GattClientCharacteristicConfigurationDescriptorValue.Indicate);                                     return;                                 }                                 if (properties.HasFlag(GattCharacteristicProperties.Read))                                 {                                     GattReadResult gattResult = await characteristic.ReadValueAsync();                                     if (gattResult.Status == GattCommunicationStatus.Success)                                     {                                         var reader = DataReader.FromBuffer(gattResult.Value);                                         byte[] input = new byte[reader.UnconsumedBufferLength];                                         reader.ReadBytes(input);                                         //Читаем input                                     }                                 }                             }                         }                     }                 }             }         }         private void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)         {             var reader = DataReader.FromBuffer(args.CharacteristicValue);             byte[] input = new byte[reader.UnconsumedBufferLength];             reader.ReadBytes(input);             //Читаем input         }         private void Watcher_Stopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args)         {             ;         }     }

Спасибо за внимание.


ссылка на оригинал статьи https://habr.com/post/423893/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *