Characteristic to fundamentalna jednostka danych w Bluetooth Low Energy, przez którą Central odbiera lub zapisuje informacje na urządzeniu peryferyjnym. Każda Characteristic należy do określonego serwisu GATT, ma unikalny UUID i zestaw właściwości (read, write, notify, indicate), które określają możliwe operacje. Według Bluetooth Core Specification 5.4 (2023), Bluetooth SIG specyfikował ponad 500 standardowych charakterystyk dla urządzeń medycznych, fitness i przemysłowych. Deweloper tworzy niestandardowe charakterystyki do przesyłania dowolnych danych użytkownika — od odczytów czujników po polecenia sterowania urządzeniem.
Najważniejsze
Characteristic to atrybut protokołu GATT, który zawiera wartość (value) i metadane. W architekturze BLE dane są przesyłane nie bezpośrednio między urządzeniami, ale przez odczyt i zapis wartości charakterystyk serwisu. Jeśli serwis to folder, to Characteristic to plik w tym folderze.
Każda Characteristic składa się z trzech komponentów: deklaracji (declaration), wartości (value) i deskryptorów (descriptors). Deklaracja zawiera UUID charakterystyki i jej właściwości. Wartość to właściwe dane przesyłane między Central a Peripheral. Deskryptory zapewniają dodatkową konfigurację.
Według Bluetooth Core Specification 5.4 (2023), wszystkie wymiany danych w BLE odbywają się przez operacje na charakterystykach. Nawet standardowe profile, takie jak Heart Rate Profile czy Battery Service, są zbudowane na zestawie charakterystyk z predefiniowanymi UUID. Zapewnia to kompatybilność urządzeń różnych producentów bez wstępnej konfiguracji.
Dla dewelopera ważne jest zrozumienie: każda Characteristic może obsługiwać różne kombinacje właściwości. Jedna charakterystyka może być tylko do odczytu, druga — do zapisu, trzecia — do powiadomień. Właściwy wybór właściwości określa scenariusz użycia i zużycie energii urządzenia.
Właściwości (properties) charakterystyki określają, jakie operacje są na niej dozwolone. Jest to maska bitowa, gdzie każdy bit włącza lub wyłącza określoną operację. Poniżej wymieniono główne właściwości.
| Właściwość | Bit | Opis | Typowe zastosowanie |
|---|---|---|---|
| Read | 0x02 | Central może odczytać bieżącą wartość | Status, poziom baterii, konfiguracja |
| Write | 0x08 | Central może zapisać nową wartość | Polecenia sterowania, ustawienia |
| Notify | 0x10 | Peripheral wysyła wartość bez potwierdzenia | Dane strumieniowe (puls, temperatura) |
| Indicate | 0x20 | Peripheral wysyła wartość z potwierdzeniem | Krytyczne dane (alarmy, statusy) |
| Write Without Response | 0x04 | Zapis bez oczekiwania na potwierdzenie z serwera | Szybka transmisja poleceń |
Uprawnienia (permissions) to poziom dostępu na poziomie serwera GATT. W przeciwieństwie do właściwości, które są deklarowane w deklaracji charakterystyki, uprawnienia są sprawdzane przy każdej operacji. Mogą obejmować wymagania dotyczące szyfrowania i uwierzytelniania.
Bluetooth SIG specyfikował ponad 500 standardowych charakterystyk, które obejmują większość powszechnych scenariuszy użycia BLE. Użycie standardowych UUID gwarantuje, że każde urządzenie odbiorcze poprawnie zinterpretuje dane bez wstępnej konfiguracji.
Oto najczęściej używane standardowe charakterystyki:
| UUID | Nazwa | Typ danych | Serwis |
|---|---|---|---|
| 0x2A19 | Battery Level | uint8 (0–100%) | Battery Service |
| 0x2A37 | Heart Rate Measurement | uint8 + flagi | Heart Rate |
| 0x2A6E | Temperature | int16 (0,01°C) | Environmental Sensing |
| 0x2A6F | Humidity | uint16 (0,01%) | Environmental Sensing |
| 0x2A00 | Device Name | UTF-8 string | Generic Access |
| 0x2A01 | Appearance | uint16 | Generic Access |
Jeśli istniejąca standardowa charakterystyka pokrywa twoje zadanie — użyj jej. To upraszcza certyfikację Bluetooth i zwiększa kompatybilność z ekosystemem. Twórz niestandardowe charakterystyki tylko dla unikalnych danych, których nie ma w rejestrze SIG.
Tworzenie charakterystyki odbywa się po stronie Peripheral — urządzenia, które dostarcza dane. Rozważmy implementację na iOS (Swift) i Android (Java).
Core Bluetooth udostępnia klasę CBMutableCharacteristic do tworzenia charakterystyki z określeniem UUID, właściwości i wartości początkowej.
import CoreBluetooth
let characteristicUUID = CBUUID("2A19") // Charakterystyka poziomu baterii
let characteristic = CBMutableCharacteristic(
type: characteristicUUID,
properties: [.read, .notify],
value: nil,
permissions: [.readable]
)
// Aktualizuj wartość przy zmianie
let batteryData = Data([batteryLevel]) // uint8
peripheralManager.updateValue(
batteryData,
for: characteristic,
onSubscribedCentrals: nil
)
Na Androidzie charakterystyka jest tworzona przez BluetoothGattCharacteristic z określeniem UUID, właściwości i uprawnień.
import android.bluetooth.*;
UUID charUuid = UUID.fromString("00002A19-0000-1000-8000-00805F9B34FB");
BluetoothGattCharacteristic characteristic =
new BluetoothGattCharacteristic(
charUuid,
BluetoothGattCharacteristic.PROPERTY_READ
| BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ
);
// Ustaw wartość
characteristic.setValue(batteryLevel, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
gattServer.notifyCharacteristicChanged(device, characteristic, false);
Operacje na Characteristic dzielą się na trzy typy: odczyt (read), zapis (write) i powiadomienia (notify/indicate). Wybór operacji zależy od scenariusza: dane na żądanie są odczytywane, polecenia zapisywane, dane strumieniowe subskrybowane przez powiadomienia.
Read — Central wysyła żądanie odczytu wartości charakterystyki. Peripheral odpowiada bieżącą wartością. Operacja jest synchroniczna i wymaga wyraźnego żądania z każdej strony. Używana do danych, które rzadko się zmieniają: wersja oprogramowania, numer seryjny, ustawienia.
Write — Central wysyła dane do Peripheral. Są dwa tryby: Write with Response (potwierdzenie od Peripheral) i Write Without Response (bez potwierdzenia). Write with Response gwarantuje dostawę — Peripheral wysyła potwierdzenie po zapisie. Write Without Response jest szybszy, ale nie gwarantuje dostawy.
Notify i Indicate — Peripheral inicjuje wysyłkę danych do Central. Przy Notify dane są wysyłane bez potwierdzenia — jeśli Central nie zdążył odebrać pakietu, zostaje on utracony. Przy Indicate Central wysyła potwierdzenie (na poziomie PDU), co gwarantuje dostawę. Indicate jest wolniejszy, ale bardziej niezawodny. Aby zasubskrybować powiadomienia, Central zapisuje wartość 0x0001 w CCCD (Client Characteristic Configuration Descriptor).
MTU (Maximum Transmission Unit) określa maksymalny rozmiar pojedynczego pakietu danych BLE. Domyślnie MTU wynosi 23 bajty, z czego 3 bajty zajmuje nagłówek — ładunek użyteczny (ATT payload) wynosi 20 bajtów. To wystarcza dla większości danych czujnikowych, ale jest niewystarczające do przesyłania plików lub dużych konfiguracji.
Bluetooth Core Specification 5.4 obsługuje MTU negotiation (negocjację MTU) — Central i Peripheral mogą uzgodnić większy rozmiar pakietu do 517 bajtów. Proces wygląda następująco: Central wysyła żądanie MTU Exchange z propozycją swojego MTU; Peripheral odpowiada swoim MTU; używana jest mniejsza z dwóch wartości.
// iOS żąda MTU przy połączeniu
// Maksymalne MTU w iOS wynosi 185 bajtów
func peripheral(
_ peripheral: CBPeripheral,
didDiscoverServices error: Error?
) {
// Żądaj MTU dla konkretnego urządzenia peryferyjnego
peripheral.maximumWriteValueLength(for: .withResponse)
}
Według Bluetooth SIG (2023), zwiększenie MTU z 23 do 185 bajtów zmniejsza narzuty na transmisję danych do 80% dzięki redukcji liczby pakietów. Dla aplikacji przesyłających odczyty z wysoką częstotliwością (np. EKG lub akcelerometr), zwiększenie MTU jest krytyczne dla stabilności strumienia.
Często zadawane pytania
Specyfikacja BLE nie ogranicza liczby charakterystyk w serwisie. W praktyce ograniczenie wynika z dostępnej pamięci serwera GATT i wymagań wydajnościowych. Dla urządzeń wbudowanych zaleca się nie więcej niż 10–15 charakterystyk na serwis.
Notify wysyła dane bez potwierdzenia — pakiet może zostać utracony bez powiadomienia nadawcy. Indicate wymaga potwierdzenia (ACK) na poziomie protokołu, co gwarantuje dostawę. Indicate jest wolniejszy, ale bardziej niezawodny. Dla krytycznych danych (alarmy, polecenia) używaj Indicate.
Tak, charakterystyka może mieć kombinację właściwości. Na przykład charakterystyka ustawień może obsługiwać Read (odczyt bieżącej wartości) i Write (zmiana ustawienia). Łącz właściwości zgodnie ze swoim scenariuszem użycia.
Użyj negocjacji MTU aby zwiększyć rozmiar pakietu do 185–517 bajtów. Jeśli dane są nadal zbyt duże — zaimplementuj fragmentację na poziomie aplikacji: podziel dane na kilka sekwencyjnych żądań z kontrolą integralności.
Jeśli twoje zadanie jest pokrywane przez standardową charakterystykę — używaj UUID z rejestru Bluetooth SIG. To upraszcza certyfikację i zapewnia kompatybilność z ekosystemem. Niestandardowe UUID twórz tylko dla unikalnych danych producentów zewnętrznych.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również