GATT (Generic Attribute Profile) — het Bluetooth Low Energy (BLE)-profiel dat de gegevensstructuur en regels voor informatie-uitwisseling tussen BLE-apparaten definieert. GATT is gebouwd bovenop het Attribute Protocol (ATT) en organiseert gegevens in een hiërarchie: services, characteristics en descriptors. Volgens Bluetooth SIG (2025) wordt het GATT-profiel gebruikt in 98% van alle BLE-toepassingen — van fitnesstrackers tot slimme sloten en medische sensoren.
Belangrijkste punten
GATT (Generic Attribute Profile) — is het Bluetooth Low Energy (BLE)-profiel dat bepaalt hoe twee BLE-apparaten gegevens uitwisselen via het Attribute Protocol (ATT). GATT standaardiseert de gegevensstructuur: alle gegevens zijn georganiseerd in de hiërarchie „service → karakteristiek → descriptor”. Het profiel werd geïntroduceerd in Bluetooth 4.0 (2010) samen met BLE en is sindsdien het belangrijkste mechanisme voor gegevensoverdracht voor energiezuinige Bluetooth-apparaten. In tegenstelling tot klassieke Bluetooth, waarbij gegevens worden verzonden via een seriële poort (SPP), biedt GATT gestructureerde toegang tot gegevens via lees-, schrijf- en meldingsbewerkingen.
De BLE-stack bestaat uit verschillende lagen: Physical Layer (radio), Link Layer (verbindingsbeheer), L2CAP (logische kanaaltransmissie), ATT (Attribute Protocol — toegang tot attributen) en GATT (op ATT gebaseerd profiel). GATT is de hoogste laag waarmee de applicatieontwikkelaar werkt. De onderliggende ATT biedt basisfunctionaliteiten: lezen, schrijven, melden en aangeven van attributen. GATT voegt semantiek toe: het definieert wat een service is, wat een karakteristiek is, hoe ze worden gegroepeerd en welke regels gelden bij het lezen en schrijven ervan. Volgens Bluetooth Core Specification 5.4 (2023) ondersteunt GATT tot 65.535 attributen (services + karakteristieken + descriptoren) op één apparaat.
De GATT-hiërarchie bestaat uit drie niveaus. Service — een logische groep karakteristieken die één taak oplost (bijv. „Batterijservice” of „Hartslagservice”). Karakteristiek — een gegevenseenheid met een bekend type: huidig batterijniveau, sensoruitlezingen, schakelaarstatus. Elke karakteristiek heeft een waarde en een of meer descriptoren die metadata beschrijven: meeteenheden, meldingsinstellingen, waardebereik. UUID (Universally Unique Identifier) identificeert elke service en elke karakteristiek uniek.
GATT ondersteunt vier soorten bewerkingen voor interactie met karakteristieken. Read — de client vraagt de huidige waarde van de karakteristiek op bij de server. Write — de client stuurt een nieuwe waarde naar de server. Notify — de server stuurt de waarde naar de client zonder bevestiging (sneller maar minder betrouwbaar). Indicate — de server stuurt de waarde met ontvangstbevestiging (betrouwbaarder maar langzamer). De ontwikkelaar kiest het type afhankelijk van het scenario: voor hartslagsensoruitlezingen is Notify voldoende, voor het schrijven van configuratie van een slim slot — Write met bevestiging.
// GATT-gegevensstructuur in Android-code
data class BleService(
val uuid: UUID,
val characteristics: List<BleCharacteristic>
)
data class BleCharacteristic(
val uuid: UUID,
val properties: Int, // LEZEN, SCHRIJVEN, MELDEN, AANGEVEN
val descriptors: List<BleDescriptor>,
var value: ByteArray?
)
In de BLE-specificatie zijn twee hoofdprofielen gedefinieerd: GAP (Generic Access Profile) en GATT (Generic Attribute Profile). GAP is verantwoordelijk voor het detecteren van apparaten, het tot stand brengen van verbindingen en het beheer van zichtbaarheid — dit is de „netwerklaag” van BLE. GATT — voor gegevensuitwisseling na het tot stand brengen van de verbinding, dus de „toepassingslaag”. De ontwikkelaar gebruikt GAP voor het scannen en verbinden met een apparaat, en GATT — voor het lezen, schrijven en ontvangen van meldingen van het aangesloten apparaat.
| Kenmerk | GAP | GATT |
|---|---|---|
| Doel | Detectie en verbinding | Gegevensuitwisseling |
| Rollen | Central / Peripheral | Client / Server |
| Protocol | HCI, Link Layer | ATT (Attribute Protocol) |
| Fase | Voor verbinding | Na verbinding |
| Hoofdklasse | BluetoothAdapter | BluetoothGatt |
GATT definieert twee rollen: GATT Server en GATT Client. Server — het apparaat dat gegevens aanbiedt (bijv. een fitnesstracker die hartslaggegevens verzendt). Client — het apparaat dat gegevens opvraagt (bijv. een smartphone die metingen uitleest). In de meeste scenario's fungeert de Android-app als GATT Client en de BLE-periferie als GATT Server. Android kan echter ook GATT Server zijn — bijvoorbeeld als de app een BLE-apparaat emuleert voor andere apparaten. De rol wordt bepaald in de fase van het tot stand brengen van de GATT-verbinding en verandert niet tijdens de sessie.
Het GATT-communicatieproces begint nadat de BLE-verbinding tussen apparaten tot stand is gebracht. Eerst detecteert de GATT Client services op de GATT Server via de Service Discovery-bewerking — Android voert dit automatisch uit bij verbinding via BluetoothGatt.discoverServices(). Na detectie ontvangt de client een lijst met beschikbare services, karakteristieken en descriptoren. Vervolgens kan de client karakteristiekwaarden lezen (Read), nieuwe waarden schrijven (Write) of zich abonneren op meldingen (Set Notify/Indicate). De GATT Server kan op elk moment na het tot stand brengen van de verbinding Notify/Indicate naar de client sturen.
Standaard is de grootte van één GATT-pakket (MTU, Maximum Transmission Unit) in BLE 23 bytes, waarvan 3 bytes ATT-header en 20 bytes nuttige gegevens. Als de applicatie meer gegevens moet verzenden (bijv. OTA-firmware-update), kan MTU-verhoging tot 517 bytes worden aangevraagd via requestMtu() in Android. Een verhoogde MTU vermindert het aantal pakketten dat nodig is om één gegevensblok te verzenden — in plaats van 50 kleine pakketten kunnen 2 grote worden verzonden, wat het energieverbruik vermindert en de overdracht versnelt. De maximale MTU hangt af van de BLE-versie en de mogelijkheden van de chip — Bluetooth 5.0 ondersteunt tot 517 bytes, oudere versies tot 247 bytes.
// Abonneer op karakteristiekmeldingen
fun enableNotifications(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
gatt.setCharacteristicNotification(characteristic, true)
// Schakel CCCD in (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)
}
}
Om meldingen van GATT Server in Android te ontvangen, moet de callback BluetoothGattCallback.onCharacteristicChanged() worden geïmplementeerd. In deze methode ontvangt de applicatie de bijgewerkte waarde van de karakteristiek elke keer dat de server Notify of Indicate verzendt. Gebruik voor real-time gegevensverwerking een buffer en Kotlin-coroutines — dit voorkomt dat de UI-thread wordt geblokkeerd bij intense meldingen (bijv. 100+ hartslagmetingen per seconde). Bij indicaties (Indicate) moet u altijd gatt.sendResponse() aan de serverzijde aanroepen — in de Android-client wordt dit automatisch afgehandeld.
Op Android wordt het werken met GATT gerealiseerd via de klassen van het android.bluetooth-pakket: BluetoothGatt (verbinding), BluetoothGattService (service), BluetoothGattCharacteristic (karakteristiek) en BluetoothGattDescriptor (descriptor). Verbinding maken met een BLE-apparaat begint met het aanroepen van BluetoothDevice.connectGatt() — deze methode retourneert BluetoothGatt, waarmee alle verdere bewerkingen worden uitgevoerd. Alle GATT-callbacks komen binnen in BluetoothGattCallback — dit is een asynchrone interface die wordt aangeroepen in dezelfde thread waarin BluetoothGatt is gemaakt. Belangrijk: alle GATT-bewerkingen moeten sequentieel worden uitgevoerd — gelijktijdig meerdere bewerkingen op dezelfde BluetoothGatt aanroepen leidt tot fouten.
Correct beheer van de levenscyclus van de GATT-verbinding is cruciaal voor de stabiliteit van de BLE-applicatie. Na het aanroepen van connectGatt() wacht de applicatie op de callback onConnectionStateChange() met de status STATE_CONNECTED. Vervolgens start het systeem automatisch Service Discovery, na voltooiing waarvan onServicesDiscovered() wordt aangeroepen. Pas daarna kunnen lezen, schrijven en abonneren worden uitgevoerd. Roep bij beëindiging altijd gatt.close() aan in onDestroy() of onPause() — niet-gesloten GATT-verbindingen verbruiken batterij en kunnen het opnieuw verbinden met hetzelfde apparaat op Android blokkeren.
// Verbinding maken met BLE-apparaat via 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) definieert tientallen standaard GATT-profielen en -services met vaste 16-bits UUID's. De meest voorkomende: service Battery Service (UUID 180F, karakteristiek Battery Level 2A19), service Heart Rate (UUID 180D, karakteristiek Heart Rate Measurement 2A37), service Device Information (UUID 180A, karakteristieken Manufacturer Name, Serial Number). Het gebruik van standaard services garandeert compatibiliteit tussen apparaten van verschillende fabrikanten — elke fitnessarmband met de Heart Rate-service zou moeten werken met elke Android-app die deze ondersteunt.
Als standaard services de taak niet dekken, kan de ontwikkelaar eigen GATT-services maken met 128-bits UUID's (aangepaste UUID's). Bij het ontwerpen van een aangepaste service moet u: de logische groep karakteristieken definiëren (bijv. „Slotbeheerservice”), elke karakteristiek de juiste eigenschappen geven (Read, Write, Notify), de toegestane waarden en meeteenheden bepalen via de descriptor Characteristic Presentation Format. Voor complexe protocollen wordt aanbevolen om een Command-karakteristiek met Write-eigenschap en een Status-karakteristiek met Notify in de service op te nemen — dit komt overeen met het Command/Status-patroon dat in industriële BLE-toepassingen wordt gebruikt.
// Aangepaste GATT-service maken (Android als 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
}
Veelgestelde vragen
GATT (Generic Attribute Profile) — is het Bluetooth Low Energy-profiel dat de structuur van gegevensuitwisseling tussen apparaten definieert. Het is nodig voor standaardisatie van toegang tot informatie: alle BLE-apparaten organiseren gegevens in services en karakteristieken, waardoor elke client sensoruitlezingen kan lezen, apparaten kan bedienen en meldingen kan ontvangen.
GAP is verantwoordelijk voor het detecteren en verbinden van BLE-apparaten (scannen, adverteren, verbinding tot stand brengen). GATT — voor gegevensuitwisseling na verbinding (lezen, schrijven, meldingen). GAP werkt vóór verbinding, GATT — erna. Beide profielen zijn verplicht voor BLE, maar vervullen verschillende functies: GAP is de „netwerklaag”, GATT is de „toepassingslaag”.
Standaard services omvatten Battery Service (180F, batterijniveau), Heart Rate (180D, hartslag), Device Information (180A, apparaatgegevens). Elke service bevat meerdere karakteristieken met 16-bits UUID's. Ontwikkelaars kunnen aangepaste services maken met 128-bits UUID's voor specifieke taken — bijvoorbeeld het bedienen van een slim slot of het verzenden van fitnesstracker-gegevens.
Op Android wordt GATT geïmplementeerd via BluetoothGatt (verbinding), BluetoothGattService (service), BluetoothGattCharacteristic (karakteristiek) en BluetoothGattDescriptor (descriptor). Verbinding wordt gemaakt via connectGatt(), waarna gebeurtenissen binnenkomen in de BluetoothGattCallback: onConnectionStateChange, onServicesDiscovered, onCharacteristicChanged (voor meldingen). Alle GATT-bewerkingen moeten sequentieel worden uitgevoerd.
UUID (Universally Unique Identifier) — een 16-bits of 128-bits identificatie die een service of karakteristiek in GATT uniek identificeert. Standaard Bluetooth SIG-services gebruiken 16-bits UUID's (bijv. 180D voor Heart Rate). Aangepaste services van ontwikkelaars — 128-bits UUID's (bijv. 12345678-1234-5678-1234-56789abcdef0). UUID stelt de client in staat de benodigde gegevens op de GATT Server te vinden.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook