GATT (Generic Attribute Profile) — Bluetooth Low Energy (BLE) профил, който определя структурата на данните и правилата за обмен на информация между BLE устройства. GATT е изграден върху Attribute Protocol (ATT) и организира данните в йерархия: услуги (services), характеристики (characteristics) и дескриптори (descriptors). По данни на Bluetooth SIG (2025), GATT профилът се използва в 98% от всички BLE приложения — от фитнес тракери до умни ключалки и медицински сензори.
Основни точки
GATT (Generic Attribute Profile) — е Bluetooth Low Energy (BLE) профилът, който определя как две BLE устройства обменят данни чрез Attribute Protocol (ATT). GATT стандартизира структурата на данните: всички данни са организирани в йерархията „услуга → характеристика → дескриптор”. Профилът беше въведен в спецификацията Bluetooth 4.0 (2010) заедно с BLE и оттогава остава основният механизъм за предаване на данни за енергийно ефективни Bluetooth устройства. За разлика от класическия Bluetooth, където данните се предават чрез сериен порт (SPP), GATT предоставя структуриран достъп до данни чрез операции за четене, запис и уведомления.
BLE стекът се състои от няколко слоя: Physical Layer (радио), Link Layer (управление на връзката), L2CAP (логическо канално предаване), ATT (Attribute Protocol — достъп до атрибути) и GATT (профил, базиран на ATT). GATT е най-високият слой, с който работи разработчикът на приложения. Долният ATT предоставя основни операции: четене, запис, уведомление и индикация на атрибути. GATT добавя семантика: определя какво е услуга, характеристика, как се групират и какви правила важат при тяхното четене и запис. Според Bluetooth Core Specification 5.4 (2023), GATT поддържа до 65 535 атрибута (услуги + характеристики + дескриптори) на едно устройство.
GATT йерархията се състои от три нива. Услуга (Service) — логическа група от характеристики, решаваща една задача (например „Услуга за батерия” или „Услуга за сърдечен ритъм”). Характеристика (Characteristic) — единица данни с известен тип: текущо ниво на заряд, показания на сензор, състояние на ключ. Всяка характеристика има стойност (value) и един или повече дескриптори (Descriptors), описващи метаданни: мерни единици, настройки за уведомления, диапазон на стойностите. UUID (Universally Unique Identifier) уникално идентифицира всяка услуга и всяка характеристика.
GATT поддържа четири типа операции за взаимодействие с характеристики. Read — клиентът изисква текущата стойност на характеристиката от сървъра. Write — клиентът изпраща нова стойност към сървъра. Notify — сървърът изпраща стойността до клиента без потвърждение (по-бърз, но по-малко надежден начин). Indicate — сървърът изпраща стойността с потвърждение за получаване (по-надежден, но по-бавен). Разработчикът избира типа в зависимост от сценария: за показания на сензор за пулс е достатъчен Notify, за запис на конфигурация на умна ключалка — Write с потвърждение.
// GATT структура на данни в Android код
data class BleService(
val uuid: UUID,
val characteristics: List<BleCharacteristic>
)
data class BleCharacteristic(
val uuid: UUID,
val properties: Int, // ЧЕТЕНЕ, ЗАПИС, УВЕДОМЛЕНИЕ, ИНДИКАЦИЯ
val descriptors: List<BleDescriptor>,
var value: ByteArray?
)
В спецификацията BLE са дефинирани два основни профила: GAP (Generic Access Profile) и GATT (Generic Attribute Profile). GAP отговаря за откриване на устройства, установяване на връзка и управление на видимостта — това е „мрежовият слой” на BLE. GATT — за обмен на данни след установяване на връзката, т.е. „приложният слой”. Разработчикът използва GAP за сканиране и свързване към устройство, а GATT — за четене, запис и получаване на уведомления от свързаното устройство.
| Характеристика | GAP | GATT |
|---|---|---|
| Предназначение | Откриване и свързване | Обмен на данни |
| Роли | Central / Peripheral | Client / Server |
| Протокол | HCI, Link Layer | ATT (Attribute Protocol) |
| Етап | Преди свързване | След свързване |
| Основен клас | BluetoothAdapter | BluetoothGatt |
GATT дефинира две роли: GATT Server и GATT Client. Сървър — устройството, което предоставя данни (например фитнес тракер, предаващ показания на пулса). Клиент — устройството, което изисква данни (например смартфон, четящ измерванията). В повечето сценарии Android приложението действа като GATT Client, а BLE периферията като GATT Server. Android обаче може също да бъде GATT Server — например ако приложението емулира BLE устройство за други устройства. Ролята се определя на етапа на установяване на GATT връзката и не се променя по време на сесията.
Процесът на GATT комуникация започва след установяване на BLE връзка между устройствата. Първо, GATT Client открива услуги на GATT Server чрез операцията Service Discovery — Android я изпълнява автоматично при свързване чрез BluetoothGatt.discoverServices(). След откриването клиентът получава списък с налични услуги, характеристики и дескриптори. След това клиентът може да чете стойности на характеристики (Read), да записва нови стойности (Write) или да се абонира за уведомления (Set Notify/Indicate). GATT Server може да изпраща Notify/Indicate до клиента по всяко време след установяване на връзката.
По подразбиране размерът на един GATT пакет (MTU, Maximum Transmission Unit) в BLE е 23 байта, от които 3 байта са заглавна част на ATT и 20 байта са полезни данни. Ако приложението трябва да предаде повече данни (например OTA актуализация на фърмуера), може да поиска увеличение на MTU до 517 байта чрез requestMtu() в Android. Увеличеният MTU намалява броя на пакетите, необходими за предаване на един блок данни — вместо 50 малки пакета могат да се изпратят 2 големи, което намалява консумацията на енергия и ускорява предаването. Максималният MTU зависи от версията на BLE и възможностите на чипа — Bluetooth 5.0 поддържа до 517 байта, по-старите версии — до 247 байта.
// Абонирайте се за уведомления за характеристика
fun enableNotifications(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
gatt.setCharacteristicNotification(characteristic, true)
// Активирайте CCCD (Client Characteristic Configuration Descriptor)
val cccdUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
val descriptor = characteristic.getDescriptor(cccdUuid)
descriptor?.let {
it.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
gatt.writeDescriptor(it)
}
}
За получаване на уведомления от GATT Server в Android трябва да се имплементира обратното извикване BluetoothGattCallback.onCharacteristicChanged(). В този метод приложението получава актуализираната стойност на характеристиката всеки път, когато сървърът изпраща Notify или Indicate. За обработка на данни в реално време използвайте буфер и Kotlin корутини — това ще предотврати блокирането на UI нишката при интензивни уведомления (например 100+ показания на пулс в секунда). При индикации (Indicate) задължително извиквайте gatt.sendResponse() от страна на сървъра — в Android клиента това се обработва автоматично.
В Android работата с GATT се реализира чрез класовете на пакета android.bluetooth: BluetoothGatt (връзка), BluetoothGattService (услуга), BluetoothGattCharacteristic (характеристика) и BluetoothGattDescriptor (дескриптор). Свързването към BLE устройство започва с извикване на BluetoothDevice.connectGatt() — този метод връща BluetoothGatt, чрез който се изпълняват всички последващи операции. Всички GATT обратни извиквания идват в BluetoothGattCallback — това е асинхронен интерфейс, извикван в същата нишка, в която е създаден BluetoothGatt. Важно: всички GATT операции трябва да се изпълняват последователно — едновременното извикване на няколко операции на един и същ BluetoothGatt води до грешки.
Правилното управление на жизнения цикъл на GATT връзката е критично за стабилността на BLE приложението. След извикване на connectGatt(), приложението очаква обратното извикване onConnectionStateChange() със състояние STATE_CONNECTED. След това системата автоматично стартира Service Discovery, след чието завършване се извиква onServicesDiscovered(). Едва след това могат да се изпълнят четене, запис и абониране. След приключване на работата задължително извикайте gatt.close() в onDestroy() или onPause() — незатворените GATT връзки консумират батерия и могат да блокират повторното свързване към същото устройство в Android.
// Свържете се с BLE устройство чрез GATT
private val gattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(
gatt: BluetoothGatt, status: Int, newState: Int
) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices()
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
val service = gatt.getService(UUID.fromString("180D"))
val characteristic = service?.getCharacteristic(
UUID.fromString("2A37")
)
characteristic?.let { enableNotifications(gatt, it) }
}
}
Bluetooth SIG (Special Interest Group) дефинира десетки стандартни GATT профили и услуги с фиксирани 16-битови UUID. Най-често срещаните: услуга Battery Service (UUID 180F, характеристика Battery Level 2A19), услуга Heart Rate (UUID 180D, характеристика Heart Rate Measurement 2A37), услуга Device Information (UUID 180A, характеристики Manufacturer Name, Serial Number). Използването на стандартни услуги гарантира съвместимост между устройства от различни производители — всяка фитнес гривна с услуга Heart Rate трябва да работи с всяко Android приложение, което я поддържа.
Ако стандартните услуги не покриват задачата, разработчикът може да създаде свои GATT услуги с 128-битови UUID (персонализирани UUID). При проектиране на персонализирана услуга трябва: да се дефинира логическата група от характеристики (например „Услуга за управление на ключалка”), да се зададат на всяка характеристика правилните свойства (Read, Write, Notify), да се определят допустимите стойности и мерни единици чрез дескриптора Characteristic Presentation Format. За сложни протоколи се препоръчва включването в услугата на характеристика Command със свойство Write и характеристика Status с Notify — това съответства на модела Command/Status, приет в индустриалните BLE приложения.
// Създайте персонализирана GATT услуга (Android като GATT Server)
private fun createCustomService(): BluetoothGattService {
val serviceUuid = UUID.fromString("12345678-1234-5678-1234-56789abcdef0")
val service = BluetoothGattService(
serviceUuid, BluetoothGattService.SERVICE_TYPE_PRIMARY
)
val charUuid = UUID.fromString("12345678-1234-5678-1234-56789abcdef1")
val characteristic = BluetoothGattCharacteristic(
charUuid,
BluetoothGattCharacteristic.PROPERTY_READ or
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ
)
service.addCharacteristic(characteristic)
return service
}
Често задавани въпроси
GATT (Generic Attribute Profile) — е Bluetooth Low Energy профил, който определя структурата за обмен на данни между устройства. Той е необходим за стандартизиране на достъпа до информация: всички BLE устройства организират данните в услуги и характеристики, което позволява на всеки клиент да чете показания от сензори, да управлява устройства и да получава уведомления.
GAP отговаря за откриване и свързване на BLE устройства (сканиране, реклама, установяване на връзка). GATT — за обмен на данни след свързване (четене, запис, уведомления). GAP работи преди свързване, GATT — след това. И двата профила са задължителни за BLE, но изпълняват различни функции: GAP е „мрежовият слой”, GATT е „приложният слой”.
Стандартните услуги включват Battery Service (180F, ниво на заряд), Heart Rate (180D, пулс), Device Information (180A, данни за устройството). Всяка услуга съдържа няколко характеристики с 16-битови UUID. Разработчиците могат да създават персонализирани услуги с 128-битови UUID за специфични задачи — например управление на умна ключалка или предаване на данни от фитнес тракер.
В Android GATT се имплементира чрез BluetoothGatt (връзка), BluetoothGattService (услуга), BluetoothGattCharacteristic (характеристика) и BluetoothGattDescriptor (дескриптор). Свързването се осъществява чрез connectGatt(), след което събитията идват в обратното извикване BluetoothGattCallback: onConnectionStateChange, onServicesDiscovered, onCharacteristicChanged (за уведомления). Всички GATT операции трябва да се изпълняват последователно.
UUID (Universally Unique Identifier) — 16-битов или 128-битов идентификатор, който уникално определя услуга или характеристика в GATT. Стандартните Bluetooth SIG услуги използват 16-битови UUID (например 180D за Heart Rate). Персонализираните услуги на разработчици — 128-битови UUID (например 12345678-1234-5678-1234-56789abcdef0). UUID позволява на клиента да намери необходимите данни на GATT Server.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също