BLE GATT entwerfen: UUIDs, Datenformate, Notifications und Versionskompatibilität
Eine BLE-Verbindung kann funktionieren, obwohl die Produktintegration scheitert. Die App findet möglicherweise die falsche Characteristic, dekodiert einen vorzeichenbehafteten Messwert falsch oder empfängt nach einem Firmware-Update keine Aktualisierungen mehr. Eine nutzbare GATT-Schnittstelle braucht eine schriftliche Vereinbarung über Identität, Bytes, Zustellungssemantik, Sicherheit und Versionsänderungen. Dieser Leitfaden entwickelt eine solche Vereinbarung für eine eigene Sensor- und Steuerschnittstelle.
Die Schnittstelle vor der App definieren
Dokumentieren Sie für jeden Service und jede Characteristic UUID, Eigenschaften, Berechtigungen, maximale Länge und Fehlerantworten. Verwenden Sie einen Bluetooth-SIG-Service nur dann, wenn dessen definierte Bedeutung und Format zum Produkt passen. Vergeben Sie für proprietäre Semantik eine stabile 128-Bit-UUID, statt eine nicht zugewiesene Kurz-UUID zu erfinden. Die Datentypenspezifikation der SIG beschränkt kurze Service-UUIDs auf von der SIG zugewiesene Werte.
Pflegen Sie die UUIDs in einem versionskontrollierten Register, das Firmware, App und Testwerkzeuge gemeinsam nutzen. Verwenden Sie den Gerätenamen nicht als einziges Identitätsmerkmal: Namen können sich ändern, und mehrere Geräte können denselben Namen aussenden. Ebenso sollten Attribut-Handles nicht über Firmware-Versionen hinweg fest einprogrammiert werden. Ermitteln Sie den Service, wählen Sie die gewünschte Instanz und lösen Sie die Characteristics innerhalb dieses Services auf.
| Characteristic | Empfohlene Operation | Zu dokumentierende Vereinbarung |
|---|---|---|
| Protokollinformationen | Lesen | Haupt- und Nebenversion des Formats, Fähigkeiten und maximaler Anwendungsrahmen |
| Messdatenstrom | Notification | Einheiten, Sequenzzähler, Zeitbezug und Überlaufstrategie |
| Konfiguration | Lesen und Schreiben mit Antwort | Bereiche, Autorisierung, Validierung und Zeitpunkt der dauerhaften Speicherung |
| Befehlsresultat | Indication oder Notification mit Anwendungsbestätigung | Transaktions-ID, Ergebniscode und Bedeutung des Abschlusses |
Ein testbares Byteformat festlegen
Das folgende Beispiel ist ein 12-Byte-Messrahmen und kein standardisiertes Bluetooth-Profil. Alle Mehrbytefelder verwenden Little Endian. Die Festkommadarstellung der Temperatur vermeidet Abhängigkeiten von der Gleitkommaserialisierung einer Programmiersprache. Ein separater Lesezugriff auf die Protokollinformationen liefert die Nebenversion und die unterstützten Fähigkeiten.
| Offset | Feld | Definition |
|---|---|---|
| 0 | major | Vorzeichenlose 8-Bit-Hauptversion, anfangs 1 |
| 1 | flags | Bit 0 bedeutet gültige Temperatur; übrige Bits reserviert und null |
| 2–3 | sequence | Vorzeichenloser 16-Bit-Zähler, modulo 65536 |
| 4–7 | uptime_ms | Vorzeichenlose 32-Bit-Abtastzeit seit dem Start; Überlauf modulo 2³² |
| 8–9 | temperature | Vorzeichenbehaftet, 16 Bit, 0,01 °C pro Schritt; bei Ungültigkeit ignorieren |
| 10–11 | battery_mV | Vorzeichenlose 16-Bit-Millivolt; 65535 bedeutet nicht verfügbar |
In diesem Beispiel werden Sequenznummer und Laufzeit beim Neustart zurückgesetzt. Eine beim Sitzungsaufbau gelesene Startkennung unterscheidet Neustarts vom Zählerüberlauf. Negative Temperaturen, ungültige Flags, abgeschnittene Rahmen und Zählerüberläufe gehören in gemeinsam verwendete Referenz-Testvektoren. Dieser Python-Decoder zeigt die explizite Validierung:
import struct
def decode_v1(payload):
if len(payload) != 12:
raise ValueError("expected 12 bytes")
major, flags, seq, ms, temp, mv = struct.unpack("<BBHIhH", payload)
if major != 1 or flags & 0xFE:
raise ValueError("unsupported schema or flags")
return {
"sequence": seq, "uptime_ms": ms,
"temperature_C": temp / 100 if flags & 1 else None,
"battery_mV": None if mv == 65535 else mv,
}
Ein Referenzvektor lautet 01 01 2A 00 E8 03 00 00 2E FB E4 0C: Hauptversion 1, gültige Temperatur, Sequenznummer 42, Laufzeit 1000 ms, −12,34 °C und 3300 mV. Dekodieren Sie ihn auf beiden Seiten, bevor Sie reale Hardware verbinden.
Die strenge Prüfung reservierter Bits bedeutet, dass dieser Decoder neue Flag-Bedeutungen nicht stillschweigend akzeptieren kann. Behalten Sie den v1-Rahmen bei, handeln Sie eine unterstützte Erweiterung aus oder führen Sie ein neues Hauptformat ein. Das Anhängen von Bytes ist nur abwärtskompatibel, wenn der vorhandene Parser ausdrücklich dafür ausgelegt wurde.

Abonnement und zuverlässige Anwendungszustellung trennen
Notifications besitzen keine ATT-Bestätigung, Indications dagegen schon. Beides beweist weder die Speicherung eines Messwerts in einer Cloud-Datenbank noch die erfolgreiche Ausführung eines Motorbefehls. Die verbundene BLE-Strecke besitzt eigene Wiederholungsmechanismen; Verbindungsabbrüche, volle Softwarewarteschlangen und App-Neustarts benötigen trotzdem eine Ende-zu-Ende-Regelung. Verwenden Sie Sequenznummern zur Erkennung fehlender Messwerte und Transaktions-IDs zur Zuordnung von Befehlsresultaten. Die zugrunde liegenden Abläufe definiert die ATT-Spezifikation.
Abonnieren Sie über die Plattform-API und prüfen Sie den Abschluss, bevor Sie den Datenstrom als bereit melden. Auf GATT-Ebene aktiviert der Client Characteristic Configuration Descriptor mit UUID 0x2902 Notifications durch 0x0001 beziehungsweise Indications durch 0x0002. Der Abonnementstatus gilt pro Client. Die Persistenz unterscheidet sich bei gebundenen und nicht gebundenen Geräten. Deshalb muss die Wiederverbindung den lokalen Callback wiederherstellen und sicherstellen, dass das Abonnement aktiv ist. Siehe GATT-Spezifikation.
Definieren Sie eine begrenzte Warteschlange und ein dokumentiertes Überlastverhalten: älteste Messwerte verwerfen, nur den neuesten Wert behalten oder die Erfassung pausieren, sofern das Produkt dies erlaubt. Stellen Sie einen Zähler verworfener Messwerte bereit. Unterscheiden Sie bei Befehlen zwischen „angenommen“, „in Ausführung“ und „abgeschlossen“. Die Wiederholung derselben Transaktion nach einem Verbindungsabbruch darf einen Aktor nicht versehentlich zweimal auslösen.
MTU und Plattformunterschiede sichtbar machen
Bei einer herkömmlichen Notification mit einem Handle muss der Wert in ATT_MTU minus 3 Byte passen; zusätzlich beträgt die Obergrenze für einen Attributwert 512 Byte. Die standardmäßige LE-ATT-MTU von 23 lässt somit 20 Byte für diese Notification übrig. Größere Werte erfordern eine vereinbarte Fragmentierung auf Anwendungsebene oder ein anderes geeignetes Übertragungsverfahren. Eine größere MTU wählt weder automatisch einen schnelleren PHY noch erhöht sie die Link-Layer-Datenlänge. Siehe ATT-Paketformate.
Ab Android 14 veranlasst die erste MTU-Anforderung eines GATT-Clients den Stack, 517 anzufordern; spätere Anforderungen werden ignoriert. Bemessen Sie Rahmen anhand des ausgehandelten Callback-Ergebnisses, niemals anhand des angeforderten Werts. Fragen Sie auf Apple-Plattformen maximumWriteValueLength(for:) für die gewählte Schreibart ab, statt Android-Annahmen zu übernehmen. Beachten Sie die Android-Referenz zu BluetoothGatt und die Apple-Referenz zur Schreiblänge.
Führen Sie asynchrone Einrichtungsschritte nacheinander aus, sofern der gewählte Stack die gewünschte Parallelität nicht ausdrücklich unterstützt. Ein erfolgreicher Aufruf bedeutet häufig nur, dass die Anforderung eingereiht wurde; das Ergebnis liefert der Callback. Protokollieren Sie ausgehandelte MTU, ausgewählte Characteristic-UUID, Sicherheitszustand, Abonnementergebnis und Parser-Version gemeinsam.
Kompatibilität zwischen Firmware- und App-Versionen planen
Protokollformatversion, Firmware-Version und Aufbau der GATT-Datenbank sind getrennte Aspekte. Halten Sie innerhalb eines unterstützten Formats die Bedeutung vorhandener Felder stabil. Stellen Sie Fähigkeiten explizit bereit, statt Clients Funktionen aus einer Firmware-Zeichenfolge ableiten zu lassen. Lehnen Sie eine nicht unterstützte Hauptversion mit einer hilfreichen Diagnose ab, bevor Steuerbefehle gesendet werden.
Ändert ein Update die Service-Datenbank, implementieren Sie das zutreffende Service-Changed- und Cache-Verhalten. Database Hash ermöglicht dort, wo verfügbar, die Änderungserkennung. Diese Mechanismen übersetzen keine geänderten Anwendungsdatenformate. Testen Sie Updates und Rollbacks sowohl mit zuvor gebundenen Clients als auch mit Neuinstallationen. Die GATT-Cache-Regeln erläutern die Anforderungen auf Datenbankebene.
Fehler mit einer Freigabematrix aufdecken
| Test | Zu provozierender Fehler | Aufzubewahrender Nachweis |
|---|---|---|
| Alte App mit neuer Firmware; neue App mit alter Firmware | Unbekannte Hauptversion, fehlendes optionales Feld oder geänderter Aufbau | Fähigkeitsabfrage und ausdrückliche Annahme oder Ablehnung |
| MTU 23 und größere ausgehandelte MTU | Zu große Nutzlast, falsche Fragmentlänge oder Abschneiden | Empfangene Länge und dekodierter Referenzvektor |
| Abbruch während Befehl und Abonnement | Doppelte Betätigung oder ausbleibender Datenstrom | Transaktions-ID, Abonnementabschluss und erster gültiger Messwert |
| Update und Rollback mit erhaltenen Bindungen | Veralteter Handle-Cache oder Zugriff auf falsche Characteristic | Discovery-/Cache-Übergang und UUID-Zuordnung |
| Langsamer Verbraucher und volle Warteschlange | Speicherwachstum oder unerklärlicher Verlust | Maximaler Warteschlangenfüllstand und Verlustzählung |
| Nicht authentifizierter oder nicht autorisierter Client | Konfiguration bei falscher Sicherheitsstufe angenommen | Erwarteter Fehler und unveränderte Konfiguration |
Bleibt der Datenstrom aus, prüfen Sie nacheinander Notify-Eigenschaft, Abonnementabschluss, Berechtigungen und Aktivität der Datenquelle. Sind Werte unplausibel, vergleichen Sie zuerst Rohbytes mit Vorzeichen, Skalierung und Byte-Reihenfolge, bevor Sie Funkparameter anpassen. Scheitern nur aktualisierte Geräte, untersuchen Sie zunächst Datenbank-Cache und Formatverhandlung.
Eine prüfbare Integrationsbeschreibung vorbereiten
Bringen Sie UUID-Register, Paketspezifikation, Referenzvektoren, Liste unterstützter Telefone und Betriebssysteme sowie die Kompatibilitätsmatrix zur Firmware-Prüfung mit. Obeitas Service für Firmware- und BSP-Diagnose bietet einen passenden Einstieg. Die Fallbeschreibung des ausgelieferten WS63-Funkmodulprojekts zeigt den Kontext für die Festlegung von Hardware und Funkbetriebsart; sie belegt nicht, dass dieser beispielhafte GATT-Vertrag auf dem Modul implementiert oder validiert wurde.