Понадобилась мне программа на windows, которая поддерживает работу с BLE. Конечно же бесплатная. Работа с BLE должна быть следующей:
- Поиск BLE устройств;
- Подключение к выбранному устройству;
- Чтение/запись характеристик устройства;
Написать решил свою программу на языке C# с использованием библиотеки Windows. Сразу оговорюсь, программу писал под свои цели, она не является универсальной. В статье расскажу и покажу, какие методы и свойства использовал для программирование BLE.
Работа с BLE: поиск устройств BLE
Для программирования BLE использую библиотеку Windows. Devices.Bluetooth. Для корректной работы необходимо в using подключить библиотеку следующим образом:
using Windows.Devices.Bluetooth using Windows.Devices.Bluetooth.Advertisement
Теперь мы можем приступить к написанию кода для поиска BLE устройств. Предварительно установим несколько ограничений для поиска.
private void btnSearchBLE_Click(object sender, EventArgs e)
{
listDevice.Items.Clear();
AdressBLE.Clear();
_devices.Clear();
// Переменная _watcher объявлена глобальной типа BluetoothLEAdvertisementWather
if (_watcher == null)
_watcher = new BluetoothLEAdvertisementWatcher();
_watcher.Stop();
// отсеиваем устройства по качеству сигнала
_watcher.SignalStrengthFilter.InRangeThresholdInDBm = -110;
_watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -110;
// Устанавливаем активный режим поиска
_watcher.ScanningMode = BluetoothLEScanningMode.Active;
// переопределяем свойство Resived (Что происходит когда устройство обнаружено)
_watcher.Received += Wather_Recived;
_watcher.Start();
}
private async void Wather_Recived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
if (dev != null)
{
if (!_devices.ContainsKey(args.BluetoothAddress))
{
_devices.Add(args.BluetoothAddress, dev);
listDevice.Invoke(new Action(() =>
{
String Name = "";
String Addrr = dev.BluetoothAddress.ToString();
AdressBLE.Add(Addrr);
if (dev.Name == null)
Name = "None";
else
Name = dev.Name;
int item = listDevice.Items.IndexOf(Addrr + " " + Name);
if (item == -1)
listDevice.Items.Add(dev.BluetoothAddress + " " + Name);
}));
}
}
}
Собственно. здесь все просто, запускаем поиск устройств BLE в активном режиме и добавляем найденное устройство в Dictionary с ключём в виде мак адреса устройства.

Подключение, чтение служб и характеристик BLE
После того как мы нашли нужное нам устройство, необходимо подключиться и прочитать какие у него есть службы. А так же какие характеристики содержат эти службы.
private async void btnConnectBLE_Click(object sender, EventArgs e)
{
trView.Nodes.Clear();
dev = await BluetoothLEDevice.FromBluetoothAddressAsync(Convert.ToUInt64(AdressBLE.ElementAt(IndexBLENow)));
if (dev != null)
{
var servisesResult = await dev.GetGattServicesAsync();
if (servisesResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
{
var services = servisesResult.Services;
for (int j = 0; j < services.Count;j++)
{
var service = services[j];
trView.Nodes.Add($"Служба - {service.Uuid}");
var characteristicsResult = await service.GetCharacteristicsAsync();
if (characteristicsResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
{
var characteristics = characteristicsResult.Characteristics;
var characteristic = characteristics[0];
for (int i = 0; i < characteristics.Count; i++)
{
characteristic = characteristics[i];
trView.Nodes[trView.Nodes.Count - 1].Nodes.Add($"Характеристика - {characteristic.Uuid}");
}
characteristic.Service.Dispose();
}
service.Session.Dispose();
}
}
}else MessageBox.Show("Не могу подключить устройство!");
}
Демонстрация кода на рисунке ниже.

Из работы программы мы видим, что наше устройство имеет 3 службы. Меня интересовала третья служба с 4 характеристиками. Последняя характеристика была сделана на чтение и запись, остальные только на чтение.
Чтение-запись характеристики
На по следок рассмотрим как читать и записывать характеристики в устройстве BLE.
private async void btnSendtxt_Click(object sender, EventArgs e)
{
if (value != "")
{
String guu = value;
if (guu.Contains("Характеристика"))
{
guu = guu.Replace("Характеристика - ", "");
String GuuiServis = "000000ff-0000-1000-8000-00805f9b34fb";
if (dev != null)
dev.Dispose();
dev = await BluetoothLEDevice.FromBluetoothAddressAsync(Convert.ToUInt64(AdressBLE.ElementAt(IndexBLENow)));
if (dev != null)
{
var servisesResult = await dev.GetGattServicesForUuidAsync(Guid.Parse(GuuiServis));
if (servisesResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
{
var services = servisesResult.Services;
var service = services[0];
try
{
var characteristicsResult = await service.GetCharacteristicsForUuidAsync(Guid.Parse(guu));
if (characteristicsResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
{
var characteristics = characteristicsResult.Characteristics;
for (int i = 0; i < characteristics.Count; i++)
{
var characteristic = characteristics[i];
if (characteristic.Uuid == Guid.Parse(guu))
{
var property = characteristic.CharacteristicProperties;
String Data = tbSendTxt.Text;
byte[] input = new byte[Data.Length];
input = Encoding.Default.GetBytes(Data);
var writer = new DataWriter();
writer.WriteBytes(input);
var result = await characteristic.WriteValueAsync(writer.DetachBuffer());
}
}
}
service.Dispose();
}
catch
{
}
}
}
}
}
}
Вышеприведенный код демонстрирует запись в характеристику. Что бы записать значение в характеристику у нее должно быть свойство записи. Иначе ничего не произойдет.
private async void trView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
value = e.Node.Text;
if (value != null)
{
String guu = value;
if (guu.Contains("Характеристика"))
{
String rootNode = e.Node.Parent.Text;
guu = guu.Replace("Характеристика - ", "");
GuuiServis = rootNode.Replace("Служба - ", "");//"000000ff-0000-1000-8000-00805f9b34fb";
if (dev != null)
{
var servisesResult = await dev.GetGattServicesForUuidAsync(Guid.Parse(GuuiServis));
if (servisesResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
{
var services = servisesResult.Services;
var service = services[0];
try
{
var characteristicsResult = await service.GetCharacteristicsAsync();
if (characteristicsResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
{
var characteristics = characteristicsResult.Characteristics;
for (int i = 0; i < characteristics.Count; i++)
{
var characteristic = characteristics[i];
if (characteristic.Uuid == Guid.Parse(guu))
{
var result = await characteristic.ReadValueAsync(BluetoothCacheMode.Uncached);
if (result.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
{
var val = DataReader.FromBuffer(result.Value);
byte[] input = new byte[val.UnconsumedBufferLength];
val.ReadBytes(input);
label1.Text = "Значение характеристики: " + System.Text.Encoding.ASCII.GetString(input);
}
characteristic.Service.Dispose();
}
}
}
service.Session.Dispose();
characteristicsResult = null;
servisesResult = null;
}
catch
{
}
}
}
}
}
}
Представленный выше код реализует следующую логику:
Нажав на характеристику мы получаем ее ID и подключаемся к ней. Затем пытаемся считать то что записано в этой этой характеристике.
Работа с BLE: Закрытие соединения с устройством BLE
private void btnDiscon_Click(object sender, EventArgs e)
{
if (dev != null)
{
dev.Dispose();
dev = null;
listDevice.Items.Clear();
trView.Nodes.Clear();
AdressBLE.Clear();
_devices.Clear();
GC.Collect();
}
}
Что бы закрыть соединение BLE необходимо вызвать метод Dispose, а также отдельно запустить сборщик мусора GC.Collect(). Иначе соединение не будет закрыто.
Скачать весь проект можно по ссылке.
Внимание! Проект проверен на windows 10. В других операционных системах работоспособность не гарантируется.



