Bluetooth Low Energy и Windows 8.1. Краткое введение для разработчиков приложений Windows Store

Перевод и адаптация статьи BLE for developers in Windows 8.1 Part I, автор — Dan Ardelean.

Для тех, кто не знает, устройства Bluetooth Smart / Bluetooth Low Energy (это одна и та же технология) — это класс беспроводных устройств, оптимизированных с целью низкого энергопотребления. Такие устройства работают как GATT-серверы, GATT-клиенты или как GATT-клиент-серверы. В режиме сервера устройство предоставляет одну или несколько служб (services). Каждая служба имеет одну или несколько характеристик с прикрепленными к ней свойствами (чтение, запись, оповещение, широковещательная передача и т.д.). GATT-клиент подключается к данному серверу и работает с его службами.

BLE и приложения Windows Store

В Windows 8.1 добавлена поддержка Bluetooth для приложений Windows Store, что открывает для разработчиков новые горизонты, в том числе и работу с устройствами Bluetooth Low Energy. Windows 8.1 поддерживает только режим GATT-клиента. Это только первая итерация API Bluetooth и, согласно некоторым мнениям, данное API выпушено на скорую руку — вот несколько фич, которые не были реализованы:

  1. Очень плохая поддержка пользователя в плане подсоединения к Bluetooth устройствам. Обычный сценарий для работы с такими устройствами должен быть следующим: «Купил девайс -> установил приложение для данного девайса из Windows Store -> пользуешься девайсом». Но «все не так однозначно»  — из приложения в первый запуск вы не можете подсоединиться к устройству, которое ранее не было спарено с вашим компьютером (через PC Settings / Devices / Bluetooth). Поэтому сценарий будет следующим: «Купил девайс -> установил приложение из Windows Store -> спарил девайс с компьютером -> пользуешься девайсом». Кроме того, нет возможности запускать настройку Bluetooth из самого приложения, как в случае с Windows Phone.
  2. Для BLE-устройств основной идеей является низкое энергопотребление, но необходимо поддерживать соединение между устройством (сервером) и приложением (клиентом). Очень плохо то, что нет возможности запустить приложение в фоне или принимать оповещения от устройства, когда приложение приостановлено. Отсутствие этих фич «убивает» принципы BLE и без них данный протокол со стороны приложения ничем не лучше, чем классический SPP (Serial Port Profile). Приложение должно иметь возможность подсоединиться к устройству; принимать оповещения в фоновом режиме; быть в курсе, когда устройство отключилось и иметь возможность подсоединится снова, когда устройство вновь будет доступно.
  3. Без возможности подключения к устройствам, которые ранее не были спарены с компьютером, нет возможности реализации сценариев, где устройство выступает маячком.
  4. Отсутствие реализации обнаружения служб и их характеристик для любых BLE-устройств.

Отладочный набор TI SensorTag

Но не смотря на это, давайте взглянем, как это API работает. Для этого нам необходимо BLE-устройство — на мой взгляд, лучшим выбором будет Texas Instruments CC2541 SensorTag.

SensorTAG

Данный отладочный набор построен на основе SoC CC2541, которая является одной из самых популярных при разработке BLE-устройств. Цена на набор от производителя — 25$ (в России на момент написания статьи цена составляла 3309 руб). Данный отладочный набор несет в себе:

  • Инфракрасный температурный датчик;
  • Датчик влажности;
  • Акселерометр;
  • Гироскоп;
  • Магнитометр;
  • Две кнопки.

С таким богатым набором периферии вы можете моделировать различные сценарии работы проектируемой системы.

Подготовка к написанию приложения

Сперва необходимо убедиться, что ваш компьютер поддерживает BLE устройства.

Само собой разумеется, ваш компьютер (ноутбук, планшет) должет иметь либо встроенный Bluetooth, либо донгл с установленными драйверами

Для этого необходимо открыть Device Manager -> Bluetooth и посмотреть наличие «Microsoft Bluetooth LE enumerator»; если он присутствует, то вы можете работать с устройствами Bluetooth Smart.

Capture

Далее необходимо спарить SensorTag с вашим компьютером. Включите SensorTag нажатием кнопки на его «боку». При обнаружении вашего устройства Windows 8.1, оно появится в списке — нажмите на него него и спарьте с вашим компьютером, используя пин-код 0000 (четыре нуля).

Devices

После спаривания система сама определит и установит GATT-сервисы. Если до спаривания у нас были Bluetooth устройства примерно как на картинке ниже

Before

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

After

Определение GATT-сервисов и их характеристик

При использовании GATT API вы должны знать, к какой службе вы хотите подключиться и какими характеристиками данная служба обладает. Есть два пути:

  1. Воспользоваться официальной документацией к устройству и узнать все предоставляемые службы и их характеристики. Для SensorTag есть соответствующий документ;
  2. Узнать службы и их UUID с помощью Диспетчера устройств (Device Manager) и надеяться, что данные сервисы являются одними из стандартных профилей BLE.

HID

На рисунке выше UUID GATT-службы равен f000aa40-0451-4000-b000-000000000000 и он не является стандартным. Стандартные профили имеют паттерн 0000XXXX-0000-1000-8000-00805f9b34fb, где XXXX — это ID профиля (например, 0x1800 — это Generic Access Profile).

Кроме этого, есть GATT-службы, которые не отображаются в Диспетчере устройств — по крайней мере следующие:

  1. 0x1800 — Generic Access;
  2. 0x1801 — Generic Attribute;
  3. 0x180A — Device Information.

Вы можете всегда пытаться добавлять данные сервисы в список подключения для получения более полной информации об устройстве.

Согласно документации, SensorTag имеет следующие интересующие нас GATT-службы:

  • Кастомные:
    • Датчик температуры: f000aa00-0451-4000-b000-000000000000
    • Датчик влажности: f000aa20-0451-4000-b000-000000000000
    • Акселерометр: f000aa10-0451-4000-b000-000000000000
    • Магнетометр: f000aa30-0451-4000-b000-000000000000
    • Барометр: f000aa40-0451-4000-b000-000000000000
    • Гироскоп: f000aa50-0451-4000-b000-000000000000
  • Стандартные:
    • Key Service: 0000ffe0-0000-1000-8000-00805f9b34fb
    • Genetic Access: 00001800-0000-1000-8000-00805f9b34fb
    • Generic Attribute: 00001801-0000-1000-8000-00805f9b34fb
    • Device Information: 0000180A-0000-1000-8000-00805f9b34fb

Создаем приложение для Windows Store

После того, как мы определили необходимые GATT-службы, можно приступать к созданию приложения Windows Store и добавлять в него возможности подключения к устройству.

Запустите Visual Studio и создайте приложение Windows Store. После создания приложения отредактируйте Package.appxmanifest, добавив вручную следующие capabilities:

<Capabilities>
   <Capability Name="internetClient" />
   <m2:DeviceCapability Name="bluetooth.genericAttributeProfile">
    <m2:Device Id="any">
     <m2:Function Type="serviceId:f000aa00-0451-4000-b000-000000000000"/>
     <m2:Function Type="serviceId:F000AA10-0451-4000-B000-000000000000"/>
     <m2:Function Type="serviceId:F000AA20-0451-4000-B000-000000000000"/>
     <m2:Function Type="serviceId:F000AA30-0451-4000-B000-000000000000"/>
     <m2:Function Type="serviceId:F000AA40-0451-4000-B000-000000000000"/>
     <m2:Function Type="serviceId:F000AA50-0451-4000-B000-000000000000"/>
     <m2:Function Type="serviceId:0000ffe0-0000-1000-8000-00805f9b34fb"/>
     <m2:Function Type="serviceId:00001800-0000-1000-8000-00805f9b34fb"/>
     <m2:Function Type="serviceId:00001801-0000-1000-8000-00805f9b34fb"/>
     <m2:Function Type="serviceId:0000180A-0000-1000-8000-00805f9b34fb"/>
    </m2:Device>
   </m2:DeviceCapability>
</Capabilities>  

Или можно добавить возможность взаимодействовать с любыми службами:


<m2:DeviceCapability Name="bluetooth.genericAttributeProfile">

<m2:Device Id="model:xxxx;xxxx"|"any">

   <m2:Function Type="name:any"/>

</m2:Device>

</m2:DeviceCapability>

Тем самым в дальнейшем вы сможете обнаруживать устройства, предоставляющие указанные службы и подсоединяться к ним. Для этого используется метод Enumeration.DeviceInformation.FindAllAsync принимающий в качестве параметра AQS для фильтрации устройств. Например, мы хотим подключится к стандартной службе Generic Access Service. Мы можем сгенерировать AQS для данной службы 3 разными путями:

  1. Используя стандартные UUID, реализованные в GattServiceUuids посредством GetDeviceSelectorFromUuid(GattServiceUuids.GenericAccess)
  2. Сгенерировав стандартный UUID из shortID — GetDeviceSelectorFromShortId(0x1800) — данный метод добавит «-0000-1000-8000-00805f9b34fb» к ID
  3. В случае, если служба кастомная (не стандартная), вы должны использовать GetDeviceSelectorFromUuid(new Guid(serviceGuid)) и передавать GUID полностью. Например, serviceGuid=»00001800-0000-1000-8000-00805f9b34fb»

Код ниже показывает, как считать имя устройства, используя Generic Access Service нашего SensorTag, согласно документации на Generic Access Service:

//Находим устройства, предоставляющие нужную службу
var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(GattServiceUuids.GenericAccess));
if (devices.Count==0)
    return;
//Коннектимся к устройству
var service = await GattDeviceService.FromIdAsync(devices[0].Id);
if (service == null)
    return;
//Получаем характеристики, с которыми хотим взаимодействовать
var characteristic = service.GetCharacteristics(GattCharacteristic.ConvertShortIdToUuid(0x2A00))[0];
//Считываем значение
var deviceNameBytes=(await characteristic.ReadValueAsync()).Value.ToArray();
//Конвертируем в строку
var deviceName=Encoding.UTF8.GetString(deviceNameBytes,0,deviceNameBytes.Length);

Похожим образом мы можем взаимодействовать со службами и характеристиками, которые оповещают о своем изменении. Например, акселерометр SensorTag:

//Находим устройства, предоставляющие нужную службу
var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(new Guid("F000AA10-0451-4000-B000-000000000000")));
if (devices.Count==0)
    return;
//Подключаемся к службе
var accService = await GattDeviceService.FromIdAsync(devices[0].Id);
if (accService == null)
    return;
//Получаем характеристики данных акселерометра
var accData = accService.GetCharacteristics(new Guid("F000AA11-0451-4000-B000-000000000000"))[0];
//Подписываемся на изменения значений
accData.ValueChanged += accData_ValueChanged;
//Устанавливаем конфигурацию для оповещения
await accData.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
//Получаем характеристику конфигурации акселерометра
var accConfig = accService.GetCharacteristics(new Guid("F000AA12-0451-4000-B000-000000000000"))[0];
//Пишем 1 для начала работы акселерометра
await accConfig.WriteValueAsync((new byte[]{1}).AsBuffer());

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

async void accData_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
   var values = (await sender.ReadValueAsync()).Value.ToArray();
   var x = values[0];
   var y = values[1];
   var z = values[2];
}

Можно сделать то же самое и для других служб, которые предоставляет SensorTag.

Полезные ссылки

  1. Texas Instruments CC2541 SensorTAG
  2. Купить  Sensor на elitan.ru
  3. Описание GATT-сервера и служб TI Development KIT SensorTAG
  4. Стандартные профили BLE
  5. GattServiceUuids
  6. Generic Access Service
  7. Using Advanced Query Syntax Programmatically

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