Descriptor — це допоміжний атрибут BLE-характеристики, який надає метадані або конфігурацію для її значення. Bluetooth Core Specification 5.4 визначає дескриптори як невід'ємну частину GATT-профілю: вони описують одиниці вимірювання, діапазони значень, текстові імена та керують підпискою на сповіщення. Найвідоміший дескриптор — Client Characteristic Configuration Descriptor (CCCD, 0x2902), який дозволяє Central підписуватися на сповіщення від характеристики. За даними Bluetooth SIG, специфіковано 8 стандартних дескрипторів, а кастомні дескриптори можуть створюватися розробником для будь-яких додаткових метаданих.
Головне
Descriptor — це атрибут GATT-протоколу, який прикріплюється до Characteristic та надає додаткову інформацію про її значення або спосіб використання. У термінології GATT, характеристика — це дані, а дескриптор — це метадані цих даних.
Кожна Characteristic може мати нуль або більше дескрипторів. Дескриптори визначаються як окремі атрибути в GATT-таблиці та мають власні 16-бітні UUID у просторі Bluetooth SIG. Дескриптори не можуть існувати самостійно — вони завжди прив'язані до конкретної характеристики.
За даними Bluetooth Core Specification 5.4 (2023), дескриптори поділяються на дві категорії: стандартні (визначені Bluetooth SIG) та кастомні (визначені розробником). Стандартні дескриптори мають UUID у діапазоні 0x2900–0x2908 та виконують строго визначені функції. Кастомні дескриптори використовують 128-бітні UUID, аналогічно кастомним сервісам та характеристикам.
Дескриптори — це ключовий механізм для конфігурації поведінки BLE-з'єднання. Без CCCD (0x2902) неможливо підписатися на сповіщення, без Presentation Format (0x2904) Central не дізнається, як інтерпретувати сирі байти характеристики.
CCCD з UUID 0x2902 — найважливіший і широко використовуваний дескриптор у BLE. Він керує підпискою Central на сповіщення (Notify) та підтверджені сповіщення (Indicate) від характеристики. Без запису в CCCD характеристика не надсилатиме сповіщення, навіть якщо в неї є властивість Notify.
CCCD — це 16-бітне значення, в якому молодший біт (0x0001) вмикає Notify, а другий біт (0x0002) вмикає Indicate. Central записує потрібне значення в CCCD, тим самим підписуючись на сповіщення. Якщо Central записує 0x0000 — підписка скасовується.
Механізм роботи CCCD виглядає так: коли Central виявляє характеристику з підтримкою Notify, він знаходить її CCCD-дескриптор і записує 0x0001. Після цього, щоразу коли Peripheral оновлює значення характеристики, воно автоматично надсилається підписаному Central через Handle Value Notification (без запиту від Central).
За даними Apple Core Bluetooth Programming Guide, CCCD автоматично керується системою під час виклику setNotifyValue для характеристики. Розробнику не потрібно вручну шукати та записувати CCCD — Core Bluetooth робить це автоматично при активації сповіщень.
У iOS підписка виконується через метод setNotifyValue на об'єкті CBPeripheral.
import CoreBluetooth
// Підписатися на сповіщення характеристики
peripheral.setNotifyValue(true, for: characteristic)
// Делегат отримує оновлені значення
func peripheral(
_ peripheral: CBPeripheral,
didUpdateValueFor characteristic: CBCharacteristic,
error: Error?
) {
// characteristic.value має нові дані
guard let data = characteristic.value else { return }
}
На Android підписка на сповіщення виконується через BluetoothGatt.setCharacteristicNotification. Розробник також повинен записати значення 0x0001 в CCCD вручну.
import android.bluetooth.*;
// Увімкнути сповіщення
bluetoothGatt.setCharacteristicNotification(characteristic, true);
// Записати 0x0001 в CCCD
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
Bluetooth SIG визначив 8 стандартних дескрипторів для поширених завдань конфігурації характеристик. Кожен дескриптор має строго визначений UUID та формат значення.
| UUID | Ім'я дескриптора | Призначення | Тип значення |
|---|---|---|---|
| 0x2900 | Characteristic Extended Properties | Додаткові властивості характеристики | uint16 (бітова маска) |
| 0x2901 | Characteristic User Description | Текстове ім'я характеристики | Рядок UTF-8 |
| 0x2902 | Client Characteristic Configuration | Керування сповіщеннями | uint16 |
| 0x2903 | Server Characteristic Configuration | Конфігурація сервера для broadcast | uint16 |
| 0x2904 | Characteristic Presentation Format | Формат представлення даних | Структура (7 байт) |
| 0x2905 | Characteristic Aggregate Format | Об'єднання кількох характеристик | Список UUID |
| 0x2906 | Valid Range | Діапазон допустимих значень | uint16 × 2 (мін, макс) |
| 0x2907 | External Report Reference | Посилання на зовнішній звіт | uint16 |
| 0x2908 | Report Reference | Посилання на внутрішній звіт | uint8 + uint16 |
Characteristic User Description (0x2901) особливо корисний для UI: він містить людиночитане ім'я характеристики, яке можна відображати в інтерфейсі додатка. Наприклад, характеристика Battery Level може мати дескриптор User Description зі значенням «Рівень заряду батареї».
Characteristic Presentation Format (0x2904) містить інформацію про те, як інтерпретувати значення характеристики: формат (uint8, uint16, float), експонента, одиниця вимірювання (через UUID з реєстру Bluetooth SIG), простір імен та опис. Наприклад, температура може бути int16 з експонентою -2 (ціна поділу 0.01°C) та одиницею вимірювання «градус Цельсія».
Доступ до дескрипторів відрізняється на iOS та Android. Core Bluetooth автоматично керує CCCD при ввімкненні сповіщень, а Android вимагає ручного запису значення в дескриптор. Розглянемо обидва підходи.
У iOS розробник зазвичай не взаємодіє з дескрипторами безпосередньо. Core Bluetooth автоматично знаходить CCCD і записує в нього потрібне значення при виклику setNotifyValue. Для читання дескрипторів використовується метод discoverDescriptors.
// Виявити дескриптори
peripheral.discoverDescriptors(for: characteristic)
// Прочитати значення User Description
func peripheral(
_ peripheral: CBPeripheral,
didDiscoverDescriptorsFor characteristic: CBCharacteristic,
error: Error?
) {
for descriptor in characteristic.descriptors ?? [] {
if descriptor.uuid == CBUUID("2901") {
peripheral.readValue(for: descriptor)
}
}
}
На Android розробник повинен сам знайти CCCD-дескриптор характеристики та записати в нього значення для ввімкнення сповіщень. Це додатковий крок порівняно з iOS.
// Прочитати значення дескриптора User Description
BluetoothGattDescriptor userDesc = characteristic
.getDescriptor(
UUID.fromString("00002901-0000-1000-8000-00805F9B34FB")
);
if (userDesc != null) {
bluetoothGatt.readDescriptor(userDesc);
}
Кастомні дескриптори використовуються, коли стандартних дескрипторів Bluetooth SIG недостатньо. Наприклад, виробник медичного датчика може додати дескриптор з інформацією про калібрування сенсора або дескриптор з логом помилок.
Кастомний дескриптор створюється з 128-бітним UUID, як і кастомна характеристика. На стороні Peripheral розробник додає його до характеристики через відповідний API. На стороні Central дескриптор виявляється автоматично при виклику discoverDescriptors.
При створенні кастомного дескриптора дотримуйтеся правил: довжина значення повинна відповідати очікуваному типу даних, права доступу (читання/запис) мають бути явно вказані. Не використовуйте UUID з діапазону стандартних дескрипторів Bluetooth SIG (0x2900–0x2908) для кастомних цілей.
Характеристика та дескриптор — це різні рівні GATT-атрибутів. Характеристика — це точка даних, а дескриптор — її метадані або конфігурація. Різниця проявляється в кількох аспектах: призначенні, UUID та правилах доступу.
Характеристика має обов'язкове оголошення, яке завжди знаходиться в GATT-таблиці. Дескриптор опціональний — характеристика може не мати дескрипторів. Характеристика може бути прочитана, записана або надсилати сповіщення незалежно. Дескриптор завжди прив'язаний до характеристики та не існує окремо.
За даними Bluetooth Core Specification 5.4, у GATT-таблиці порядок атрибутів наступний: оголошення сервісу, оголошення характеристики, значення характеристики, дескриптори характеристики (якщо є), потім наступний сервіс. Цей порядок обов'язковий для коректної роботи GATT-клієнтів.
Часті запитання
CCCD потрібен для керування підпискою: властивість Notify лише говорить, що характеристика може надсилати сповіщення, але не вмикає їх. Central повинен явно підписатися, записавши 0x0001 в CCCD. Це запобігає небажаному надсиланню даних на непідготовлений Central.
Специфікація не обмежує кількість дескрипторів. На практиці кожна характеристика зазвичай має 1–3 дескриптори: CCCD (для характеристик з Notify/Indicate), опціонально User Description та Presentation Format. Занадто багато дескрипторів збільшує розмір GATT-таблиці.
У більшості випадків не потрібно. Core Bluetooth на iOS та Android автоматично додають CCCD до характеристик, у яких є властивості Notify або Indicate. Кастомні дескриптори створюються вручну лише для специфічних метаданих.
Ні, CCCD має строго визначений формат (uint16) та призначення — керування сповіщеннями. Запис інших значень порушує специфікацію Bluetooth і може призвести до непрацездатності підписки. Для кастомних даних використовуйте кастомні дескриптори з 128-бітним UUID.
User Description містить людиночитане ім'я характеристики — наприклад, «Температура корпусу» замість UUID 0x2A6E. Додаток може відображати це ім'я в інтерфейсі, роблячи взаємодію з BLE-пристроєм зрозумілою для користувача без жорстко закодованих рядків.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також