ubluepy — periferica e centrale Bluetooth LE

Il modulo ubluepy è la vecchia API Bluetooth LE distribuita con il port nRF di MicroPython. È modellato approssimativamente sulla libreria Python Linux bluepy e si appoggia direttamente sul SoftDevice Nordic — non esiste alcun back-end portabile, quindi il modulo è disponibile solo sui target Nordic (l’Arduino Nano 33 BLE Sense nella gamma OpenMV). Le più recenti API bluetooth / aioble non sono abilitate in questa build, quindi ubluepy è l’unico modo per pilotare la radio integrata nel chip.

L’insieme di funzionalità disponibili dipende dal SoftDevice flashato dal firmware:

  • s140 (Nano 33 BLE Sense) — entrambi i ruoli, periferica e centrale (scanner). È quanto distribuisce il firmware OpenMV.

  • s132 — sia periferica che centrale.

  • s110 — solo periferica; i metodi scanner / connect sono esclusi dalla compilazione.

Esempio di periferica

Pubblicizza il dispositivo come periferica Bluetooth LE con un singolo servizio di rilevamento ambientale e notifica una caratteristica di temperatura a ogni scrittura sul suo Client Characteristic Configuration Descriptor (CCCD):

from ubluepy import Service, Characteristic, UUID, Peripheral, constants
from machine import LED

notif_enabled = False

def event_handler(event_id, handle, data):
    global notif_enabled
    if event_id == constants.EVT_GAP_CONNECTED:
        LED("LED_GREEN").on()
    elif event_id == constants.EVT_GAP_DISCONNECTED:
        LED("LED_GREEN").off()
        periph.advertise(device_name="Nano 33", services=[svc])
    elif event_id == constants.EVT_GATTS_WRITE:
        notif_enabled = bool(data[0])

svc = Service(UUID("181A"))            # Environmental Sensing
char = Characteristic(UUID("2A6E"),
                      props=Characteristic.PROP_NOTIFY | Characteristic.PROP_READ,
                      attrs=Characteristic.ATTR_CCCD)
svc.addCharacteristic(char)

periph = Peripheral()
periph.addService(svc)
periph.setConnectionHandler(event_handler)
periph.advertise(device_name="Nano 33", services=[svc])

Esempio di centrale

Esegue la scansione dei dispositivi in advertising nelle vicinanze per 100 ms e decodifica i dati di advertising di ciascun ScanEntry

from ubluepy import Scanner, constants

s = Scanner()
for entry in s.scan(100):
    print(entry.addr(), entry.rssi(), "dBm")
    for ad_type, name, value in entry.getScanData():
        print(" ", ad_type, name, bytes(value))

Contenuto del modulo

Classi

class ubluepy.UUID(value)

Costruisce un UUID Bluetooth a 16 o 128 bit.

value

Uno tra:

  • int — un UUID numerico a 16 bit (UUID(0x180A)).

  • Stringa "0xXXXX" di 6 caratteri — un UUID a 16 bit, ad esempio UUID("0x181A").

  • Stringa "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" di 36 caratteri — un UUID completo a 128 bit. La porzione specifica del vendor viene registrata con il SoftDevice al momento della costruzione.

  • Un’altra istanza UUID — esegue una copia.

Qualsiasi altra lunghezza solleva ValueError("Invalid UUID string length").

binVal() int

Restituisce i 16 bit meno significativi dell’UUID come int. Per gli UUID a 128 bit viene restituito solo il campo a 16 bit incorporato nell’UUID specifico del vendor (il valore completo a 128 bit è accessibile solo tramite l’indice specifico del vendor del SoftDevice).

class ubluepy.Service(uuid: UUID, type: int = Service.PRIMARY)

Definisce un servizio GATT che verrà registrato con il SoftDevice quando viene aggiunto a un Peripheral.

uuid

Un’istanza UUID. Passare un oggetto non UUID solleva ValueError.

type

Uno tra Service.PRIMARY (predefinito) o Service.SECONDARY. Altri valori sollevano ValueError.

uuid() UUID

Restituisce l’istanza UUID del servizio.

addCharacteristic(characteristic: Characteristic) None

Registra una Characteristic con il servizio. L’handle GATT della caratteristica viene assegnato durante questa chiamata.

getCharacteristic(uuid: UUID) Characteristic | None

Cerca per UUID una Characteristic precedentemente aggiunta. Restituisce l’istanza della caratteristica, oppure None se non viene trovata alcuna corrispondenza.

getCharacteristics() list

Restituisce l’elenco di tutte le caratteristiche aggiunte al servizio.

PRIMARY: int

Costante di tipo servizio per i servizi primari (1).

SECONDARY: int

Costante di tipo servizio per i servizi secondari (2).

class ubluepy.Characteristic(uuid: UUID, *, props: int = PROP_READ | PROP_WRITE, attrs: int = 0)

Definisce una caratteristica GATT. Aggiungila a un Service con Service.addCharacteristic() prima che il Peripheral genitore inizi l’advertising.

uuid

Un’istanza UUID.

props (solo keyword)

Maschera di bit di uno o più valori Characteristic.PROP_* che descrivono quali operazioni la caratteristica supporta.

attrs (solo keyword)

Maschera di bit di attributi GATT aggiuntivi. Usa Characteristic.ATTR_CCCD per associare un Client Characteristic Configuration Descriptor — necessario per far funzionare le caratteristiche PROP_NOTIFY / PROP_INDICATE.

uuid() UUID

Restituisce l’istanza UUID della caratteristica.

properties() int

Restituisce la maschera di bit props impostata al momento della costruzione.

read() bytearray

Solo ruolo centrale. Legge il valore della caratteristica dal peer connesso. Restituisce un bytearray con il valore più recente. Su una periferica è un’operazione nulla e restituisce None.

write(data, *, with_response: bool = False) None

Scrive sulla caratteristica.

  • Su una periferica, se PROP_NOTIFY è impostato nelle proprietà della caratteristica, il valore viene inviato come notifica GATT alla centrale connessa; altrimenti viene aggiornato il valore dell’attributo locale.

  • Su una centrale, il valore viene scritto sul peer remoto. Imposta with_response=True per emettere una richiesta di scrittura e attendere la conferma del peer invece di un comando di scrittura.

data è qualsiasi oggetto conforme al buffer protocol (bytes, bytearray, memoryview).

PROP_BROADCAST: int

La caratteristica può trasmettere in broadcast il proprio valore (0x01).

PROP_READ: int

La caratteristica supporta le letture (0x02).

PROP_WRITE_WO_RESP: int

La caratteristica supporta le scritture senza risposta (0x04).

PROP_WRITE: int

La caratteristica supporta le scritture con risposta (0x08).

PROP_NOTIFY: int

La caratteristica può inviare notifiche a una centrale sottoscritta (0x10).

PROP_INDICATE: int

La caratteristica può inviare indicazioni (notifiche con conferma) a una centrale sottoscritta (0x20).

PROP_AUTH_SIGNED_WR: int

La caratteristica supporta scritture firmate autenticate (0x40).

ATTR_CCCD: int

Aggiunge un Client Characteristic Configuration Descriptor alla caratteristica (0x01). Necessario affinché i client possano sottoscriversi a notifiche/indicazioni.

class ubluepy.Descriptor(uuid: UUID)

Classe stub per rappresentare i descrittori GATT. L’implementazione attuale si limita a memorizzare l’UUID e non espone alcun metodo — è fornita per compatibilità futura con revisioni successive del modulo.

class ubluepy.Peripheral

Il dispositivo Bluetooth LE locale. La stessa classe viene usata sia per il ruolo di periferica che per quello di centrale; il ruolo è selezionato in base ai metodi che si chiamano (advertise() seleziona la periferica, connect() seleziona la centrale).

addService(service: Service) None

Registra un Service (e tutte le caratteristiche precedentemente aggiunte ad esso) con il server GATT locale.

getServices() list

Restituisce l’elenco dei servizi attualmente registrati con questo Peripheral.

advertise(*, device_name: str | None = None, services: list | None = None, data: bytes | None = None, connectable: bool = True) None

Avvia l’advertising nel ruolo di periferica.

device_name

Nome locale completo pubblicizzato nel payload GAP.

services

Elenco di istanze Service da pubblicizzare. L’UUID di ciascun servizio è incluso nell’advertising.

data

Payload di advertising raw opzionale (bytes / bytearray) accodato all’header generato automaticamente. Usalo per payload specifici del vendor o per beacon come Eddystone.

connectable

Quando è True (predefinito), pubblicizza il dispositivo come connettibile e registra i gestori di eventi GAP / GATTS in modo che il callback configurato con setConnectionHandler() venga invocato in caso di connessione, disconnessione e scritture CCCD. Quando è False, pubblicizza il dispositivo come beacon — non viene associato alcun gestore e il dispositivo non può essere connesso.

advertise_stop() None

Interrompe qualsiasi advertising in corso.

setConnectionHandler(func) None

Registra un callback invocato in caso di eventi GAP e GATTS. Il callback viene chiamato come func(event_id, conn_handle, data) dove event_id è uno tra i valori constants.EVT_GAP_CONNECTED, constants.EVT_GAP_DISCONNECTED o constants.EVT_GATTS_WRITE, conn_handle è l’handle di connessione del SoftDevice (o l’handle di attributo per le scritture GATTS) e data è il payload raw dell’evento come bytearray (oppure None per connessione / disconnessione).

setNotificationHandler(func) None

Registra un callback per gli eventi di notifica ricevuti nel ruolo di centrale.

withDelegate(delegate: DefaultDelegate) None

Associa un’istanza DefaultDelegate per ricevere gli eventi GATT decodificati.

disconnect() None

Chiude la connessione attiva (attualmente uno stub a operazione nulla in questa build).

connect(addr, *, addr_type: int = constants.ADDR_TYPE_PUBLIC) None

Solo ruolo centrale. Si connette al peer con l’indirizzo indicato e ne scopre in modo sincrono i servizi primari e le caratteristiche. Si blocca finché la connessione non è stabilita e la discovery non è completata; i servizi scoperti sono quindi disponibili tramite getServices().

addr

Indirizzo del peer come stringa "xx:xx:xx:xx:xx:xx" di 17 caratteri (ad esempio quella ottenuta da ScanEntry.addr()).

addr_type (solo keyword)

Uno tra constants.ADDR_TYPE_PUBLIC (predefinito) o constants.ADDR_TYPE_RANDOM_STATIC.

class ubluepy.Scanner

Observer GAP per scoprire i dispositivi in advertising nelle vicinanze. Disponibile solo quando il firmware è compilato con un SoftDevice dotato di supporto centrale (s132 / s140).

scan(timeout: int) list

Esegue una scansione passiva per timeout millisecondi e restituisce un elenco di istanze ScanEntry — una per ciascun report di advertising ricevuto durante la finestra.

class ubluepy.ScanEntry

Un singolo report di advertising catturato da Scanner.scan(). Le istanze vengono restituite dallo scanner — non esiste un costruttore pubblico.

addr() str

Restituisce l’indirizzo del peer come stringa "xx:xx:xx:xx:xx:xx" di 17 caratteri.

addr_type() int

Restituisce il tipo di indirizzo del peer (constants.ADDR_TYPE_PUBLIC o constants.ADDR_TYPE_RANDOM_STATIC).

rssi() int

Restituisce l’indicatore di intensità del segnale in dBm.

getScanData() list

Decodifica il payload di advertising in un elenco di tuple (ad_type, description, value). ad_type è il byte numerico del tipo AD (vedi constants.ad_types), description è il nome della costante corrispondente come stringa (oppure None se il tipo è sconosciuto) e value è il corpo del record AD come bytearray.

class ubluepy.DefaultDelegate

Classe base per gli oggetti passati a Peripheral.withDelegate(). Crea una sottoclasse ed esegui l’override di handleConnection() / handleNotification() per reagire agli eventi GATT.

handleConnection() None

Chiamato in caso di eventi GAP di connessione / disconnessione. L’implementazione predefinita è vuota.

handleNotification() None

Chiamato in caso di notifiche GATT in arrivo. L’implementazione predefinita è vuota.

Costanti

L’attributo constants del modulo è uno spazio dei nomi contenente gli identificatori degli eventi GAP/GATT, i valori di tipo indirizzo e lo spazio dei nomi annidato ad_types.

ubluepy.constants: type

Contenitore che espone le costanti elencate di seguito.

constants.EVT_GAP_CONNECTED: int

Valore di event_id del gestore di connessione di Peripheral per la connessione GAP (16).

constants.EVT_GAP_DISCONNECTED: int

Valore di event_id del gestore di connessione di Peripheral per la disconnessione GAP (17).

constants.EVT_GATTS_WRITE: int

Valore di event_id del gestore di connessione di Peripheral per una scrittura su un attributo GATT locale, incluse le scritture su un CCCD che abilitano/disabilitano le notifiche (80).

constants.UUID_CCCD: int

UUID Bluetooth standard per il Client Characteristic Configuration Descriptor (0x2902).

constants.ADDR_TYPE_PUBLIC: int

Indirizzo di dispositivo Bluetooth pubblico (0).

constants.ADDR_TYPE_RANDOM_STATIC: int

Indirizzo di dispositivo Bluetooth casuale statico (1).

constants.ad_types: type

Spazio dei nomi delle costanti di tipo AD per i dati di advertising tratte dal Bluetooth Core Specification Supplement. Ogni nome corrisponde al relativo tipo AD a 1 byte:

Nome

Valore

AD_TYPE_FLAGS

0x01

AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE

0x02

AD_TYPE_16BIT_SERVICE_UUID_COMPLETE

0x03

AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE

0x04

AD_TYPE_32BIT_SERVICE_UUID_COMPLETE

0x05

AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE

0x06

AD_TYPE_128BIT_SERVICE_UUID_COMPLETE

0x07

AD_TYPE_SHORT_LOCAL_NAME

0x08

AD_TYPE_COMPLETE_LOCAL_NAME

0x09

AD_TYPE_TX_POWER_LEVEL

0x0A

AD_TYPE_CLASS_OF_DEVICE

0x0D

AD_TYPE_SIMPLE_PAIRING_HASH_C

0x0E

AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R

0x0F

AD_TYPE_SECURITY_MANAGER_TK_VALUE

0x10

AD_TYPE_SECURITY_MANAGER_OOB_FLAGS

0x11

AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE

0x12

AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT

0x14

AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT

0x15

AD_TYPE_SERVICE_DATA

0x16

AD_TYPE_PUBLIC_TARGET_ADDRESS

0x17

AD_TYPE_RANDOM_TARGET_ADDRESS

0x18

AD_TYPE_APPEARANCE

0x19

AD_TYPE_ADVERTISING_INTERVAL

0x1A

AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS

0x1B

AD_TYPE_LE_ROLE

0x1C

AD_TYPE_SIMPLE_PAIRING_HASH_C256

0x1D

AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256

0x1E

AD_TYPE_SERVICE_DATA_32BIT_UUID

0x20

AD_TYPE_SERVICE_DATA_128BIT_UUID

0x21

AD_TYPE_URI

0x24

AD_TYPE_3D_INFORMATION_DATA

0x3D

AD_TYPE_MANUFACTURER_SPECIFIC_DATA

0xFF