Die Generic Attribute Profile (GATT)-Schicht definiert, wie Bluetooth Low Energy-Geräte Daten für Clients bereitstellen. Für Ingenieure, die Bluetooth-Module in Produkte integrieren, bestimmt die GATT-Service-Architektur direkt die Anwendungsperformance, den Energieverbrauch und die Interoperabilität. Dieser Artikel behandelt praktische GATT-Designentscheidungen für modulbasierte Produkte.
GATT-Hierarchie
GATT organisiert Daten in einer vierstufigen Hierarchie:
| Ebene | Beschreibung | Beispiel |
|---|---|---|
| Profile | Service-Sammlung für einen Use-Case | Heart Rate Profile |
| Service | Gruppe verwandter Characteristics | Heart Rate Service (0x180D) |
| Characteristic | Benannter Wert mit Properties | Heart Rate Measurement (0x2A37) |
| Descriptor | Metadaten einer Characteristic | Client Characteristic Configuration (0x2902) |
Ein Modul implementiert typischerweise einen oder mehrere Primary Services. Secondary Services sind nur sinnvoll, wenn ein anderer Service sie referenziert — praktisch vermeiden die meisten Moduldesigns sie.
Service-Design
Primary Service-Registrierung
Jeder Service wird durch eine 128-bit UUID identifiziert. Zwei Zuweisungsstrategien:
- 16-bit UUIDs (0x1800–0x26FF): Von Bluetooth SIG für standardisierte Services zugewiesen. Verwenden, wenn das Modul ein Standardprofil implementiert (z.B.: Battery Service 0x180F).
- 128-bit Custom UUIDs: Für proprietäre Services. Basis-UUID generieren und die unteren Bytes für jeden Service und Characteristic inkrementieren.
Häufiges Basis-UUID-Pattern:
Base: 6E40XXXX-B5A3-F393-E0A9-E50E24DCCA9E Service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E Char 1: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E Char 2: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E
Dieser Ansatz, vom Nordic UART-Service verwendet, vereinfacht das UUID-Management über eine Produktlinie.
Characteristic-Properties
Jede Characteristic deklariert Properties, die die Client-Interaktion steuern:
| Property | Opcode | Richtung | Use-Case |
|---|---|---|---|
| Read | 0x0A | Client → Server | Konfigurationswerte |
| Write | 0x12 | Client → Server | Steuerkommandos |
| Write Without Response | 0x52 | Client → Server | Hochfrequenz-Kommandos |
| Notify | — | Server → Client | Sensor-Daten-Streaming |
| Indicate | — | Server → Client | Kritische Alarme |
| Broadcast | — | Server → All | Beacon-Advertising |
Notification vs Indication
Beide senden Daten vom Server zum Client, aber mit unterschiedlichen Zuverlässigkeitsgarantien:
- Notify (ATT_HANDLE_VALUE_NOTIFICATION): Keine Bestätigung. Latenz: ~3 ms/Paket bei 1 Mbps PHY. Throughput: bis 270 kbps mit 23-byte MTU, ~800 kbps mit 247-byte MTU.
- Indicate (ATT_HANDLE_VALUE_INDICATION): Erfordert ATT-Bestätigung vom Client. Ein zusätzlicher Round-Trip (~6–10 ms). Für Daten mit obligatorischer Lieferbestätigung.
Bei einem Modul, das Sensordaten mit 10 Hz streamt, ist Notify die klare Wahl — die nächste Probe ersetzt jedes verlorene Paket. Für Alarmereignisse gewährleistet Indicate, dass der Client die Warnung erhielt.
Descriptor-Design
Jede Characteristic mit Notify oder Indicate-Support muss einen Client Characteristic Configuration Descriptor (CCCD, UUID 0x2902) enthalten. Schreiben von 0x0001 aktiviert Notify; 0x0002 aktiviert Indicate; 0x0000 deaktiviert beide.
Empfohlene optionale Descriptors:
| Descriptor | UUID | Zweck |
|---|---|---|
| Characteristic User Description | 0x2901 | Lesbarer Name |
| Characteristic Presentation Format | 0x2904 | Einheit, Exponent, Datentyp |
| Characteristic Extended Properties | 0x2900 | Reliable Write-Support |
Der Presentation Format Descriptor ist besonders wertvoll für Module mit mehreren Sensortypen — er ermöglicht der Client-Anwendung zu erkennen, ob ein Wert Temperatur (0x07, Einheiten 0x272F = Celsius) oder Feuchtigkeit (0x06, Einheiten 0x272F = Prozent) repräsentiert.
MTU und Throughput-Optimierung
Der Standard-ATT-MTU ist 23 Bytes (20 Bytes Payload). Moderne Smartphones unterstützen MTU 247 oder höher. Das Modul sollte MTU-Exchange während der Verbindung anfordern:
// Pseudocode für MTU-Negotiation ble_att_exchange_mtu_request(247); // Nach Exchange: effektiver MTU = min(lokal, remote) // Payload pro Notification = MTU - 3 Bytes ATT-Header
Throughput-Vergleich bei verschiedenen MTU-Werten (Verbindungsintervall 30 ms, 1 Mbps PHY):
| MTU | Payload/Paket | Pakete/Intervall | Throughput |
|---|---|---|---|
| 23 | 20 B | 4 | 21 kbps |
| 185 | 182 B | 1 | 48 kbps |
| 247 | 244 B | 1 | 65 kbps |
Für Module mit Data Length Extension (DLE) (Bluetooth 4.2+) kann DLE plus großer MTU den Throughput auf über 800 kbps bei 1 Mbps PHY steigern.
Praxisbeispiel: Multi-Sensor-Service
Flat-Design für ein Modul mit Temperatur-, Feuchtigkeits- und Accelerometer-Sensoren:
Service: 6E400001-... (Custom Sensor Service) ├── Char: 6E400002-... (Temperature, Read|Notify) │ └── CCCD: 0x2902 │ └── Presentation Format: 0x2904 (int16, 0.01°C, unit Celsius) ├── Char: 6E400003-... (Humidity, Read|Notify) │ └── CCCD: 0x2902 │ └── Presentation Format: 0x2904 (uint16, 0.01%, unit percentage) ├── Char: 6E400004-... (Acceleration XYZ, Notify) │ └── CCCD: 0x2902 └── Char: 6E400005-... (Sampling Rate, Read|Write)
Die Sampling Rate Characteristic ermöglicht dem Client die Konfiguration der Notifikationsfrequenz — 10 setzen 10 Hz, 0 deaktiviert alle Notifications.
Energieeffizienz
Jede Notification verbraucht ~1.2 ms Radio-Aktivzeit bei 1 Mbps. Bei 10 Hz mit 20-Byte Payloads:
- Radio-Aktivanteil: ~12 ms / 1000 ms = 1.2% Duty Cycle
- Estimativer Strom: 0.012 × 8 mA (TX) + 0.988 × 5 µA (Sleep) ≈ 100 µA average
- CR2032 Batterielebensdauer (220 mAh): ~2200 Stunden ≈ 91 Tage
Reduktion auf 1 Hz: average Strom sinkt auf ~13 µA, Batterielebensdauer verlängert auf ~1.9 Jahre.
Häufige Design-Fehler
- Übersegmentierte Services: Verwandte Daten über mehrere Services verteilen erfordert mehrere Service-Discovery-Operationen. Verwandte Characteristics in einem Service zusammenfassen.
- Fehlender CCCD: Eine Characteristic mit Notify ohne CCCD führt dazu, dass einige Stacks den Service ablehnen. CCCD für notifiable Characteristics immer einfügen.
- UUID-Kollisionen: Random 128-bit UUIDs ohne systematisches Basis-Pattern riskieren Kollisionen zwischen Produktvarianten. Basis-UUID mit sequenziellen unteren Bytes verwenden.
- Übermäßige Indications: Indicate für hochfrequente Daten (z.B.: 50 Hz IMU) verschwendet Bandbreite für Bestätigungen. Indicate auf niederfrequente, hochzuverlässige Events beschränken.
- Presentation Format ignoriert: Ohne 0x2904 Descriptor müssen Client-Anwendungen Dateninterpretation hard-codieren, was Interoperabilität mit generischen GATT-Browsers wie nRF Connect zerstört.
Fazit
GATT-Service-Architektur ist der Application-Layer-Vertrag zwischen einem Bluetooth-Modul und seinem Host. Durchdachte Service-Organisation, passende Characteristic-Property-Auswahl und korrekter Descriptor-Einsatz bestimmen, ob ein Modul sauber in Drittanbieter-Ecosystems integriert wird oder ein Debugging-Burden wird. Die obigen Prinzipien — Flat-Service-Design, Notify für Streaming, systematische UUID-Zuweisung und MTU-Optimierung — bilden eine verlässliche Grundlage für modulbasierte Produktentwicklung.