11.6. Сервіси та характеристики¶
Після того як GAP встановив відкрите з’єднання між двома пристроями, шар над ним – Generic Attribute Profile, GATT – має надати значення байтам, що передаються через це з’єднання. Вибір BLE тут незвичний. Там де TCP надає необроблений потік байтів і залишає застосунку вигадувати власне кадрування, GATT надає невелику базу даних ключ/значення, яку одна сторона розміщує, а інша читає, записує або підписується на неї.
Саме ця база даних займає більшу частину часу розробників BLE-застосунків. Що камера публікує на телефон, що вона відстежує на віддаленому датчику, як Bluetooth-клавіатура повідомляє хосту про натиснуту клавішу – все це значення характеристик у певній базі даних GATT.
11.6.1. Два виміри ролей, а не один¶
Поширене джерело плутанини: peripheral / central і server / client – це два незалежні виміри, а не синоніми.
Peripheral і central – це ролі GAP, що встановлюються під час з’єднання. Peripheral анонсує себе і приймає підключення; central сканує і ініціює з’єднання. Це визначається в момент встановлення зв’язку і не змінюється.
Server і client – це ролі GATT, що встановлюються для кожної операції з характеристикою. Server розміщує характеристику; client читає, записує або підписується на неї.
Два виміри роз’єднані специфікацією. Peripheral є зазвичай server (монітор серцевого ритму публікує свої показники), а central є зазвичай client (телефон їх читає), але BLE допускає будь-яку комбінацію – peripheral може виявити характеристику на central, до якого щойно підключився, або одне з’єднання може розміщувати сервіси з обох боків одночасно.
Більшість застосунків для камер дотримуються стандартного поєднання (peripheral + server або central + client), тому решта цього розділу розглядає їх як один вимір, коли йдеться про стандартний випадок. Коли різниця важлива, обидва терміни вказуються явно.
11.6.2. Всередині бази даних¶
База даних GATT – це дерево. Листки містять власне байти. Гілки групують пов’язані листки у логічно зрозумілі одиниці.
База даних GATT. Сервіси групують характеристики; характеристики несуть байти застосунку; дескриптори несуть метадані про характеристику.¶
Є три види вузлів:
Service – логічна група пов’язаних значень. Bluetooth SIG публікує стандартні визначення сервісів для поширених випадків використання – Battery Service для рівня заряду, Environmental Sensing для температури / вологості / тиску, Heart Rate для моніторів серцевого ритму – тому звичайний застосунок на телефоні може розпізнати сервіс, якого він ніколи раніше не бачив. Застосунок також може визначати власні сервіси для речей, які SIG не стандартизував.
Characteristic – одне іменоване значення всередині сервісу. Battery service має одну характеристику – Battery Level, однобайтовий відсоток. Environmental Sensing має окремі характеристики для температури, вологості, тиску тощо. Характеристика є одиницею операцій GATT – ви читаєте характеристику, записуєте характеристику, підписуєтеся на характеристику.
Descriptor – метадані, прикріплені до характеристики. Деякі дескриптори стандартизовані – Client Characteristic Configuration Descriptor (CCCD) є найвідомішим, оскільки запис до нього – це спосіб, яким client повідомляє server «надсилайте мені сповіщення про цю характеристику». Інші визначаються користувачем і містять такі речі, як формат представлення або розширені властивості.
GATT server (зазвичай peripheral) оголошує свою базу даних один раз під час запуску, і вона не змінюється під час роботи. GATT client (зазвичай central) виявляє вміст бази даних після підключення – обходячи дерево, читаючи UUID сервісів, а потім характеристики всередині кожного.
11.6.3. UUID¶
Кожен сервіс, характеристика та дескриптор має UUID (Universally Unique IDentifier), що ідентифікує що це таке за видом. UUID бувають трьох розмірів:
16-бітні. Зарезервовані для стандартів, визначених Bluetooth SIG. Battery Service –
0x180F. Battery Level (характеристика) –0x2A19. Повний список опублікований на сайті assigned-numbers Bluetooth SIG за адресою https://www.bluetooth.com/specifications/assigned-numbers/.32-бітні. Рідко використовуваний проміжний варіант.
128-бітні. Те, що використовують усі інші – постачальник або застосунок генерує один випадково і використовує для свого власного сервісу або характеристики. Камери, що визначають власний протокол, знаходяться тут.
Клас bluetooth.UUID приймає будь-який з трьох розмірів:
import bluetooth
BATTERY_SERVICE = bluetooth.UUID(0x180F)
CUSTOM_SERVICE = bluetooth.UUID("12345678-1234-5678-9abc-def012345678")
16-бітний UUID кодується в невеликий рекламний пакет, що є однією з причин переваги стандартних сервісів, коли такий існує – монітор серцевого ритму, що анонсує 0x180D (Heart Rate), коштує два байти; власний UUID коштує шістнадцять. Для застосунків, яким не потрібна стандартна сумісність, згенерований 128-бітний UUID є правильною відповіддю.
11.6.4. Що дають стандартизовані SIG сервіси¶
Аргумент на користь використання стандартного сервісу простий: існуючі застосунки вже знають, як з ним спілкуватися. Пристрій, що анонсує Heart Rate service (0x180D) і надає характеристику Heart Rate Measurement (0x2A37), працює з кожним фітнес-застосунком на планеті без написання нового коду. Пристрій, що повторно реалізує ті самі дані з власними UUID, потребує власного застосунку-компаньйона та власного документа протоколу.
Стандарти мають свою ціну. Розкладка байтів всередині кожної характеристики визначена – SIG вирішив, що Heart Rate Measurement – це однобайтове поле прапорів, за яким іде або 8-бітне, або 16-бітне значення серцевого ритму, після якого необов’язково йдуть R-R інтервали – і відповідний пристрій повинен дотримуватися цього розкладання. Власні сервіси вільні від цього обмеження.
Практична відповідь для камер: використовуйте стандартний сервіс, коли він існує для типу даних, які ви маєте (Battery Service, Environmental Sensing), і визначайте власний з 128-бітним UUID для всього, що специфічно для вашого застосунку.
11.6.5. Об’єкти на стороні server та client¶
Для однакових концептуальних будівельних блоків (service, characteristic, descriptor) кожна бібліотека GATT надає два паралельних набори об’єктів:
Об’єкти на стороні server – те, що peripheral оголошує, що він розміщує. У
aioble:aioble.Service,aioble.Characteristic,aioble.Descriptor. Вони конструюються до початку реклами і реєструються за допомогоюaioble.register_services().Об’єкти на стороні client – те, що central виявляє на peer після підключення. У
aioble:aioble.ClientService,aioble.ClientCharacteristic,aioble.ClientDescriptor. Вони обходяться черезaioble.DeviceConnection.service()/services()після підключення.