ubluepy --- Bluetooth LE 周邊與中央

ubluepy 模組是隨 MicroPython nRF 移植版一同提供的傳統 Bluetooth LE API。它大致仿照 Linux bluepy Python 函式庫,並直接架構於 Nordic SoftDevice 之上——它沒有可移植的後端,因此本模組僅在 Nordic 目標裝置上可用(在 OpenMV 產品線中即 Arduino Nano 33 BLE Sense)。較新的 bluetooth / aioble API 在此建置中並未啟用,因此 ubluepy 是驅動晶片內無線電的唯一方式。

可用的功能集取決於韌體所燒錄的 SoftDevice:

  • s140(Nano 33 BLE Sense)——同時支援周邊中央(掃描器)角色。這正是 OpenMV 韌體所提供的版本。

  • s132——同時支援周邊與中央。

  • s110——僅支援周邊;掃描器/連線方法已被編譯排除。

周邊範例

作為 Bluetooth LE 周邊進行廣播,提供單一環境感測服務,並在每次寫入其用戶端特徵組態描述子(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])

中央範例

掃描附近正在廣播的裝置 100 ms,並解碼每個 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))

模組內容

類別

class ubluepy.UUID(value)

建構一個 16 位元或 128 位元的 Bluetooth UUID。

value

下列其中之一:

  • int —— 16 位元數值 UUID(UUID(0x180A))。

  • 6 字元的 "0xXXXX" 字串 —— 16 位元 UUID,例如 UUID("0x181A")

  • 36 字元的 "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 字串 —— 完整的 128 位元 UUID。供應商特定部分會在建構時向 SoftDevice 註冊。

  • 另一個 UUID 實例 —— 執行複製。

其他任何長度都會引發 ValueError("Invalid UUID string length")

binVal() int

int 形式傳回 UUID 的低 16 位元。對於 128 位元 UUID,只會傳回嵌入在供應商特定 UUID 內的 16 位元欄位(完整的 128 位元值只能透過 SoftDevice 的供應商特定索引取得)。

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

定義一個 GATT 服務,當其加入 Peripheral 時會向 SoftDevice 註冊。

uuid

一個 UUID 實例。傳入非 UUID 物件會引發 ValueError

type

可為 Service.PRIMARY(預設)或 Service.SECONDARY。其他值會引發 ValueError

uuid() UUID

傳回該服務的 UUID 實例。

addCharacteristic(characteristic: Characteristic) None

向服務註冊一個 Characteristic。該特徵的 GATT 控制代碼會在此呼叫期間指派。

getCharacteristic(uuid: UUID) Characteristic | None

依 UUID 查詢先前已加入的 Characteristic。傳回該特徵實例,若找不到相符項目則傳回 None

getCharacteristics() list

傳回已加入該服務的所有特徵的清單。

PRIMARY: int

主要服務的服務類型常數(1)。

SECONDARY: int

次要服務的服務類型常數(2)。

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

定義一個 GATT 特徵。請先以 Service.addCharacteristic() 將它加入 Service,再讓父 Peripheral 開始廣播。

uuid

一個 UUID 實例。

props(僅限關鍵字)

由一個或多個 Characteristic.PROP_* 值組成的位元遮罩,描述該特徵支援哪些操作。

attrs(僅限關鍵字)

額外 GATT 屬性的位元遮罩。使用 Characteristic.ATTR_CCCD 來附加用戶端特徵組態描述子——這是讓 PROP_NOTIFY / PROP_INDICATE 特徵運作的必要條件。

uuid() UUID

傳回該特徵的 UUID 實例。

properties() int

傳回建構時設定的 props 位元遮罩。

read() bytearray

僅限中央角色。 從已連線的對端讀取該特徵的值。傳回包含最新值的 bytearray。在周邊上此為無操作並傳回 None

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

寫入該特徵。

  • 周邊上,若特徵屬性中設定了 PROP_NOTIFY,則該值會以 GATT 通知的形式傳送給已連線的中央;否則只會更新本機屬性值。

  • 中央上,該值會寫入遠端對端。設定 with_response=True 可發出寫入請求並等待對端的確認,而非寫入命令。

data 為任何符合緩衝協定的物件(bytesbytearraymemoryview)。

PROP_BROADCAST: int

特徵可廣播其值(0x01)。

PROP_READ: int

特徵支援讀取(0x02)。

PROP_WRITE_WO_RESP: int

特徵支援無回應的寫入(0x04)。

PROP_WRITE: int

特徵支援有回應的寫入(0x08)。

PROP_NOTIFY: int

特徵可向已訂閱的中央推送通知(0x10)。

PROP_INDICATE: int

特徵可向已訂閱的中央推送指示(需確認的通知)(0x20)。

PROP_AUTH_SIGNED_WR: int

特徵支援經過身分驗證的簽署寫入(0x40)。

ATTR_CCCD: int

為特徵加入用戶端特徵組態描述子(0x01)。用戶端要能訂閱通知/指示時為必要。

class ubluepy.Descriptor(uuid: UUID)

用於表示 GATT 描述子的存根類別。目前的實作只儲存 UUID 並且不公開任何方法——提供它是為了與本模組未來版本的向前相容性。

class ubluepy.Peripheral

本機 Bluetooth LE 裝置。同一個類別同時用於周邊與中央角色;角色由您呼叫的方法決定(advertise() 選擇周邊,connect() 選擇中央)。

addService(service: Service) None

向本機 GATT 伺服器註冊一個 Service(以及其先前加入的所有特徵)。

getServices() list

傳回目前已向此 Peripheral 註冊的服務清單。

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

以周邊角色開始廣播。

device_name

在 GAP 酬載中廣播的完整本機名稱。

services

要廣播的 Service 實例清單。每個服務的 UUID 都會包含在廣播中。

data

選用的原始廣播酬載(bytes / bytearray),會附加在自動產生的標頭之後。可用於供應商特定或信標酬載,例如 Eddystone。

connectable

當為 True(預設)時,作為可連線的裝置進行廣播,並註冊 GAP / GATTS 事件處理常式,使所設定的 setConnectionHandler() 回呼函式在連線、中斷連線及 CCCD 寫入時觸發。當為 False 時,作為信標廣播——不附加任何處理常式,且該裝置無法被連線。

advertise_stop() None

停止任何進行中的廣播。

setConnectionHandler(func) None

註冊一個在 GAP 與 GATTS 事件上被呼叫的回呼函式。該回呼函式以 func(event_id, conn_handle, data) 的形式被呼叫,其中 event_idconstants.EVT_GAP_CONNECTEDconstants.EVT_GAP_DISCONNECTEDconstants.EVT_GATTS_WRITE 其中之一,conn_handle 為 SoftDevice 連線控制代碼(GATTS 寫入時則為屬性控制代碼),而 data 為以 bytearray 形式呈現的原始事件酬載(連線/中斷連線時則為 None)。

setNotificationHandler(func) None

註冊一個用於在中央角色下接收通知事件的回呼函式。

withDelegate(delegate: DefaultDelegate) None

附加一個 DefaultDelegate 實例以接收已解碼的 GATT 事件。

disconnect() None

中斷使用中的連線(在此建置中目前為無操作存根)。

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

僅限中央角色。 連線至具有給定位址的對端,並同步探索其主要服務與特徵。會封鎖直到連線建立且探索完成;探索到的服務隨後可透過 getServices() 取得。

addr

對端位址,為 17 字元的 "xx:xx:xx:xx:xx:xx" 字串(例如取自 ScanEntry.addr())。

addr_type(僅限關鍵字)

可為 constants.ADDR_TYPE_PUBLIC(預設)或 constants.ADDR_TYPE_RANDOM_STATIC

class ubluepy.Scanner

用於探索附近正在廣播裝置的 GAP 觀察者。僅在韌體針對具有中央支援的 SoftDevice(s132 / s140)建置時可用。

scan(timeout: int) list

進行被動掃描 timeout 毫秒,並傳回一個 ScanEntry 實例清單——在掃描時間窗內每收到一個廣播報告就對應一個實例。

class ubluepy.ScanEntry

Scanner.scan() 擷取的單一廣播報告。實例由掃描器傳回——沒有公開的建構函式。

addr() str

以 17 字元的 "xx:xx:xx:xx:xx:xx" 字串傳回對端位址。

addr_type() int

傳回對端位址類型(constants.ADDR_TYPE_PUBLICconstants.ADDR_TYPE_RANDOM_STATIC)。

rssi() int

以 dBm 為單位傳回訊號強度指示值。

getScanData() list

將廣播酬載解碼為一個 (ad_type, description, value) 元組清單。ad_type 為數值 AD 類型位元組(請參閱 constants.ad_types),description 為相符常數名稱的字串(若類型未知則為 None),而 value 為 AD 紀錄主體,以 bytearray 形式呈現。

class ubluepy.DefaultDelegate

傳遞給 Peripheral.withDelegate() 的物件的基底類別。請將它子類別化並覆寫 handleConnection() / handleNotification() 以對 GATT 事件做出反應。

handleConnection() None

在 GAP 連線/中斷連線事件時被呼叫。預設實作為空。

handleNotification() None

在收到 GATT 通知時被呼叫。預設實作為空。

常數

本模組的 constants 屬性是一個命名空間,包含 GAP/GATT 事件識別碼、位址類型值,以及巢狀的 ad_types 命名空間。

ubluepy.constants: type

公開下列常數的容器。

constants.EVT_GAP_CONNECTED: int

GAP 連線時 Peripheral 連線處理常式的 event_id 值(16)。

constants.EVT_GAP_DISCONNECTED: int

GAP 中斷連線時 Peripheral 連線處理常式的 event_id 值(17)。

constants.EVT_GATTS_WRITE: int

寫入本機 GATT 屬性(包括啟用/停用通知的 CCCD 寫入)時 Peripheral 連線處理常式的 event_id 值(80)。

constants.UUID_CCCD: int

用戶端特徵組態描述子的標準 Bluetooth UUID(0x2902)。

constants.ADDR_TYPE_PUBLIC: int

公開 Bluetooth 裝置位址(0)。

constants.ADDR_TYPE_RANDOM_STATIC: int

靜態隨機 Bluetooth 裝置位址(1)。

constants.ad_types: type

來自 Bluetooth Core Specification Supplement 的廣播資料 AD 類型常數命名空間。每個名稱對應到相應的 1 位元組 AD 類型:

名稱

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