Hello World to receive data from a Bluetooth (BLE) device via C #

    Good day.

    A couple of weeks ago I ran into the problem that there is simply no normal and modern article on the first receipt of data from Bluetooth . And I had to tinker to understand where to start and how to do it in general. And so that people do not repeat my mistakes, here is a brief essay about how this can be done.



    But first, a couple of pretentious words, for which it is generally needed. The modern world is increasingly immersed in the ideology of the Internet of Things. Now everything interacts with each other, a refrigerator with a stove, an iron with a vacuum cleaner, etc. A lot of noise was raised because of the ECG in Apple Watch, but modern tonometers, heart rate monitors, thermometers have long been able to transmit data via Bluetooth. And this is all you need to somehow connect into a single network. And the key element in this network is, whatever one may say, a computer. In this regard, the task arose to receive data from a specific device via Bluetooth.

    To begin with, what we already had and what aggravated the search for a solution. And we had an application written on .Net Core . What is the essence of the application is not important, for simplicity, we assume that we just have a console on .Net Core. Well, the device will call the letter of N .

    The first attempts to find something working with Bluetooth via C # will lead to the 32feet library .

    In NuGet packages, it sounds like 32feet.NET .

    And she, by the way, in her latest grocery edition, even finds Bluetooth devices, but not the BLE standard [as it turned out much later]. For example, the same OnePlus 5T was stably searched, but the required device N is not. At the same time, the author’s official response was found that his library does not interact with BLE in principle, and there’s no point in trying. Although there is a preliminary version of InTheHand.Devices.Bluetooth on Github, which should support BLE, but so much is changed in it, and there is no documentation at all, that even compiling a project with ideas taken from 32feet.NET did not work out.

    New research has led me to more standard solutions, namely the Universal Windows Platform ( UWP ). When developing this platform, Microsoft , embraced by the idea of ​​universality and a single application for computer and phone, tried and made interaction with Bluetooth. And here everything works just fine, but ... We have a project on .Net Core ... And there's nothing you can do about it.

    I’ll say right away that solutions for the interaction of UWP libraries with .Net Coreit was not possible to find and the project had to be switched to 4.7.1. , the benefit is not difficult. Although there were thoughts about how to leave the project on .Net Core and, for example, make a separate Windows service with transferring data through a named pipe or pick up a WCF service and establish interaction with it, but in our case it didn’t make any practical sense.



    So in the end we have before the start:

    • Project on 4.7.1.
    • Win10 updated to Version 10.0.17134 Build 17134.

    First you need to connect a couple of libraries with handles, namely

    • "Windows from 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

    And actually everything, further work with the device goes on documentation without problems.
    Interact with BLE through the BluetoothLEAddressWatcher class.
    But you need to remember that without having the API of the device itself, something sensible cannot be done.

    Here is my sample code for how to get data from the device.

    This code is designed for the fact that the device has already been added (connected).

    publicclassBluetoothObserver
      {
        BluetoothLEAdvertisementWatcher Watcher { get; set; }
        publicvoidStart()
        {
          Watcher = new BluetoothLEAdvertisementWatcher()
          {
            ScanningMode = BluetoothLEScanningMode.Active
          };
          Watcher.Received += Watcher_Received;
          Watcher.Stopped += Watcher_Stopped;
          Watcher.Start();
        }
        privatebool isFindDevice { get; set; } = false;
        privateasyncvoidWatcher_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 = newbyte[reader.UnconsumedBufferLength];
                        reader.ReadBytes(input);
                        //Читаем input
                      }
                    }
                  }
                }
              }
            }
          }
        }
        privatevoidCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
        {
          var reader = DataReader.FromBuffer(args.CharacteristicValue);
          byte[] input = newbyte[reader.UnconsumedBufferLength];
          reader.ReadBytes(input);
          //Читаем input
        }
        privatevoidWatcher_Stopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args)
        {
          ;
        }
      }

    Thanks for attention.

    Also popular now: