Characteristic è un’unità fondamentale di dati in Bluetooth Low Energy, attraverso la quale un Central legge o scrive informazioni su un dispositivo periferico. Ogni Characteristic appartiene a un servizio GATT specifico, ha un UUID unico e un insieme di proprietà (read, write, notify, indicate) che definiscono le operazioni possibili. Secondo la Bluetooth Core Specification 5.4 (2023), Bluetooth SIG ha specificato oltre 500 caratteristiche standard per dispositivi medici, fitness e industriali. Gli sviluppatori creano caratteristiche personalizzate per trasmettere qualsiasi dato utente — dalle letture dei sensori ai comandi di controllo del dispositivo.
Punti chiave
Una Characteristic è un attributo del protocollo GATT che contiene un valore e metadati. Nell’architettura BLE, i dati non vengono trasferiti direttamente tra dispositivi, ma attraverso la lettura e scrittura dei valori delle caratteristiche del servizio. Se un servizio è una cartella, allora una Characteristic è un file all’interno di quella cartella.
Ogni Characteristic è composta da tre componenti: dichiarazione (declaration), valore (value) e descrittori (descriptors). La dichiarazione contiene l’UUID della caratteristica e le sue proprietà. Il valore sono i dati effettivi trasferiti tra Central e Peripheral. I descrittori forniscono configurazione aggiuntiva.
Secondo la Bluetooth Core Specification 5.4 (2023), tutti gli scambi di dati in BLE avvengono attraverso operazioni sulle caratteristiche. Anche i profili standard come Heart Rate Profile o Battery Service sono costruiti su un insieme di caratteristiche con UUID predefiniti. Questo garantisce la compatibilità dei dispositivi di diversi produttori senza configurazione preliminare.
È importante che lo sviluppatore capisca: ogni Characteristic può supportare diverse combinazioni di proprietà. Una caratteristica può essere solo lettura, un’altra per scrittura, una terza per notifiche. La scelta corretta delle proprietà determina lo scenario d’uso e il consumo energetico del dispositivo.
Le proprietà (properties) di una caratteristica definiscono quali operazioni sono consentite su di essa. È una maschera di byte dove ogni bit abilita o disabilita un’operazione specifica. Di seguito sono elencate le proprietà principali.
| Proprietà | Bit | Descrizione | Utilizzo tipico |
|---|---|---|---|
| Read | 0x02 | Central può leggere il valore corrente | Stato, livello batteria, configurazione |
| Write | 0x08 | Central può scrivere un nuovo valore | Comandi di controllo, impostazioni |
| Notify | 0x10 | Peripheral invia il valore senza conferma | Dati in flusso (polso, temperatura) |
| Indicate | 0x20 | Peripheral invia il valore con conferma | Dati critici (avvisi, stati) |
| Write Without Response | 0x04 | Scrittura senza attendere conferma dal server | Trasmissione comandi ad alta velocità |
I permessi (permissions) sono il livello di accesso a livello del server GATT. A differenza delle proprietà, che sono dichiarate nella dichiarazione della caratteristica, i permessi vengono verificati in ogni operazione. Possono includere requisiti di crittografia e autenticazione.
Bluetooth SIG ha specificato oltre 500 caratteristiche standard che coprono la maggior parte dei casi d’uso comuni del BLE. L’uso di UUID standard garantisce che qualsiasi dispositivo ricevente interpreti correttamente i dati senza configurazione preliminare.
Ecco le caratteristiche standard più utilizzate:
| UUID | Nome | Tipo di dato | Servizio |
|---|---|---|---|
| 0x2A19 | Battery Level | uint8 (0–100%) | Battery Service |
| 0x2A37 | Heart Rate Measurement | uint8 + flag | Heart Rate |
| 0x2A6E | Temperature | int16 (0.01°C) | Environmental Sensing |
| 0x2A6F | Humidity | uint16 (0.01%) | Environmental Sensing |
| 0x2A00 | Device Name | Stringa UTF-8 | Generic Access |
| 0x2A01 | Appearance | uint16 | Generic Access |
Se una caratteristica standard esistente copre il tuo compito, usala. Questo semplifica la certificazione Bluetooth e migliora la compatibilità con l’ecosistema. Crea caratteristiche personalizzate solo per dati unici non presenti nel registro SIG.
La creazione di una caratteristica viene eseguita sul lato Peripheral — il dispositivo che fornisce i dati. Vediamo le implementazioni su iOS (Swift) e Android (Java).
Core Bluetooth fornisce la classe CBMutableCharacteristic per creare una caratteristica con UUID, proprietà e valore iniziale.
import CoreBluetooth
let characteristicUUID = CBUUID("2A19") // Caratteristica del livello della batteria
let characteristic = CBMutableCharacteristic(
type: characteristicUUID,
properties: [.read, .notify],
value: nil,
permissions: [.readable]
)
// Aggiorna valore al cambiamento
let batteryData = Data([batteryLevel]) // uint8
peripheralManager.updateValue(
batteryData,
for: characteristic,
onSubscribedCentrals: nil
)
Su Android, una caratteristica viene creata usando BluetoothGattCharacteristic con UUID, proprietà e permessi.
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
);
// Imposta il valore
characteristic.setValue(batteryLevel, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
gattServer.notifyCharacteristicChanged(device, characteristic, false);
Le operazioni su una Characteristic si dividono in tre tipi: lettura (read), scrittura (write) e notifiche (notify/indicate). La scelta dipende dallo scenario: i dati su richiesta vengono letti, i comandi vengono scritti, i dati in flusso si iscrivono alle notifiche.
Read: Central invia una richiesta per leggere il valore della caratteristica. Peripheral risponde con il valore corrente. L’operazione è sincrona e richiede una richiesta esplicita da ciascun lato. Utilizzata per dati che cambiano raramente: versione del firmware, numero di serie, impostazioni.
Write: Central invia dati a Peripheral. Esistono due modalità: Write with Response (conferma da Peripheral) e Write Without Response (senza conferma). Write with Response garantisce la consegna — Peripheral invia una conferma dopo la scrittura. Write Without Response è più veloce ma non garantisce la consegna.
Notify e Indicate: Peripheral avvia la trasmissione dei dati a Central. Con Notify, i dati vengono inviati senza conferma — se Central non riceve il pacchetto, viene perso. Con Indicate, Central invia una conferma (livello PDU), garantendo la consegna. Indicate è più lento ma più affidabile. Per iscriversi alle notifiche, Central scrive il valore 0x0001 nel CCCD (Client Characteristic Configuration Descriptor).
MTU (Maximum Transmission Unit) definisce la dimensione massima di un singolo pacchetto di dati BLE. Per impostazione predefinita, l’MTU è di 23 byte, di cui 3 byte sono l’intestazione — il carico utile (ATT payload) è di 20 byte. Questo è sufficiente per la maggior parte dei dati dei sensori, ma non per il trasferimento di file o grandi configurazioni.
Bluetooth Core Specification 5.4 supporta la negoziazione dell’MTU — Central e Peripheral possono concordare una dimensione del pacchetto maggiore fino a 517 byte. Il processo funziona così: Central invia una richiesta MTU Exchange con il suo MTU proposto; Peripheral risponde con il suo MTU; viene utilizzato il minore dei due valori.
// iOS richiede MTU alla connessione
// Il MTU massimo in iOS è 185 byte
func peripheral(
_ peripheral: CBPeripheral,
didDiscoverServices error: Error?
) {
// Richiedi MTU per un periferico specifico
peripheral.maximumWriteValueLength(for: .withResponse)
}
Secondo Bluetooth SIG (2023), l’aumento dell’MTU da 23 a 185 byte riduce l’overhead di trasmissione dei dati fino all’80% grazie alla riduzione del numero di pacchetti. Per le applicazioni che trasmettono letture ad alta frequenza (ad esempio, ECG o accelerometro), l’aumento dell’MTU è critico per la stabilità del flusso.
Domande frequenti
La specifica BLE non limita il numero di caratteristiche in un servizio. In pratica, il limite è determinato dalla memoria disponibile del server GATT e dai requisiti di prestazioni. Per i dispositivi embedded, si consiglia di non superare 10–15 caratteristiche per servizio.
Notify invia dati senza conferma — il pacchetto può essere perso senza avvisare il mittente. Indicate richiede una conferma (ACK) a livello di protocollo, garantendo la consegna. Indicate è più lento ma più affidabile. Per dati critici (avvisi, comandi), usa Indicate.
Sì, una caratteristica può avere una combinazione di proprietà. Ad esempio, una caratteristica di impostazioni può supportare Read (lettura del valore corrente) e Write (modifica dell’impostazione). Combina le proprietà in base al tuo caso d’uso.
Utilizza la negoziazione dell’MTU per aumentare la dimensione del pacchetto a 185–517 byte. Se i dati sono ancora più grandi, implementa la frammentazione a livello di applicazione: suddividi i dati in più richieste sequenziali con controllo di integrità.
Se il tuo compito è coperto da una caratteristica standard, usa UUID dal registro Bluetooth SIG. Questo semplifica la certificazione e garantisce la compatibilità con l’ecosistema. Crea UUID personalizzati solo per dati unici di terze parti.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche