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