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) — логичка група карактеристика која решава један задатак (на пример, „Сервис батерије” или „Сервис Heart Rate”). Карактеристика (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. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође