bluetooth --- 低階藍牙

本模組提供了與板載藍牙控制器互動的介面。它支援藍牙低功耗(BLE)的 Central(中央)、Peripheral(周邊)、Broadcaster(廣播者)與 Observer(觀察者)角色,並支援 GATT 伺服器與用戶端以及 L2CAP 連線導向通道。一個裝置可同時以多種角色運作。同時也支援配對(pairing)與綁定(bonding)。

本 API 旨在對應低階藍牙協定,並為更高階的抽象(例如特定裝置類型)提供基礎建構元件。

小訣竅

對於大多數應用程式,建議優先使用更高階的 aioble 函式庫,它在本模組之外提供了以 asyncio 為基礎的封裝。請參閱 aioble --- 非同步 BLE

class BLE

class bluetooth.BLE

傳回單例(singleton)BLE 物件。

組態設定

active(active: bool | None = None, /) bool

可選擇變更 BLE 無線電的啟用狀態,並傳回目前的狀態。

在使用本類別的任何其他方法之前,必須先啟用無線電。

config(param: str, /) Any
config(*, **kwargs: Any) None

取得或設定 BLE 介面的組態值。要取得某個值時,參數名稱應以字串形式加上引號,且一次只能查詢一個參數。要設定值時則使用關鍵字語法,一次可以設定一個或多個參數。

目前支援的值為:

  • 'mac':目前使用中的位址,取決於目前的位址模式。這會傳回一個 (addr_type, addr) 元組。

    關於位址類型的詳細資訊,請參閱 gap_scan

    此值只能在介面目前處於啟用狀態時查詢。

  • 'addr_mode':設定位址模式。可用的值為:

    名稱

    行為

    0x00

    PUBLIC

    使用控制器的公開位址。

    0x01

    RANDOM

    使用產生的靜態位址。

    0x02

    RPA

    使用可解析的私有位址。

    0x03

    NRPA

    使用不可解析的私有位址。

    預設情況下,介面會在可用時使用 PUBLIC 位址,否則會使用 RANDOM 位址。

  • 'gap_name':取得/設定由 Generic Access 服務(UUID 0x1800)的 Device Name 特徵(characteristic,UUID 0x2a00)所使用的 GAP 裝置名稱。此值可隨時設定並可多次變更。

  • 'rxbuf':取得/設定用於儲存傳入事件的內部緩衝區大小(以位元組為單位)。此緩衝區對整個 BLE 驅動程式是全域的,因此會處理所有事件的傳入資料,包括所有特徵的資料。增大此值可更妥善地處理突發性的傳入資料(例如掃描結果),並能接收較大的特徵值。

  • 'mtu':取得/設定在 ATT MTU 交換期間將使用的 MTU。最終的 MTU 會是此值與遠端裝置 MTU 兩者中的較小值。ATT MTU 交換不會自動發生(除非遠端裝置主動發起),必須以 gattc_exchange_mtu 手動發起。請使用 _IRQ_MTU_EXCHANGED 事件來得知某個連線的 MTU。

  • 'bond':設定配對期間是否啟用綁定。啟用後,配對請求會設定「bond」旗標,且兩個裝置都會儲存金鑰。

  • 'mitm':設定配對是否需要 MITM 防護。

  • 'io':設定本裝置的 I/O 能力。

    可用的選項有:

    常數

    能力

    _IO_CAPABILITY_DISPLAY_ONLY

    0

    僅顯示

    _IO_CAPABILITY_DISPLAY_YESNO

    1

    顯示並具有是/否輸入

    _IO_CAPABILITY_KEYBOARD_ONLY

    2

    僅鍵盤

    _IO_CAPABILITY_NO_INPUT_OUTPUT

    3

    無輸入或輸出

    _IO_CAPABILITY_KEYBOARD_DISPLAY

    4

    鍵盤與顯示

  • 'le_secure':設定是否需要「LE Secure」配對。預設為 false(亦即允許「Legacy Pairing」)。

事件處理

irq(handler: Callable[[int, Tuple], Any | None], /) None

為來自 BLE 協定堆疊的事件註冊回呼函式。handler 接受兩個引數:event(會是下列其中一個代碼)與 data(是一個特定於該事件的值元組)。

注意: 為了最佳化以避免不必要的記憶體配置,元組中的 addradv_datachar_datanotify_datauuid 項目都是唯讀的 memoryview 實例,指向 bluetooth 的內部環形緩衝區,且僅在 IRQ 處理函式的呼叫期間有效。如果你的程式需要儲存其中某個值以便在 IRQ 處理函式傳回之後存取(例如將其儲存在類別實例或全域變數中),則需要複製一份資料,可使用 bytes()bluetooth.UUID(),如下所示::

connected_addr = bytes(addr)  # equivalently: adv_data, char_data, or notify_data
matched_uuid = bluetooth.UUID(uuid)

舉例來說,掃描結果的 IRQ 處理函式可能會檢查 adv_data 以判斷是否為正確的裝置,只有在此情況下才複製位址資料以供程式他處使用。而要在 IRQ 處理函式中印出資料,則需要使用 print(bytes(addr))

處理函式通常會根據事件代碼進行分派,並解開特定於該事件的酬載元組::

def bt_irq(event, data):
    if event == _IRQ_CENTRAL_CONNECT:
        conn_handle, addr_type, addr = data
        ...
    elif event == _IRQ_SCAN_RESULT:
        addr_type, addr, adv_type, rssi, adv_data = data
        ...

下面列出每個事件代碼、它所傳遞的酬載以及簡短說明。對於有提及 status 欄位的事件,status 在成功時為 0,失敗時則為一個與實作相關的非零值。

常數

事件

酬載元組

_IRQ_CENTRAL_CONNECT

1

有一個 central 已連線至此 peripheral。

(conn_handle, addr_type, addr)

_IRQ_CENTRAL_DISCONNECT

2

有一個 central 已從此 peripheral 斷線。

(conn_handle, addr_type, addr)

_IRQ_GATTS_WRITE

3

已連線的用戶端已寫入本機的某個特徵或描述子。請使用 gatts_read 來取得新的值。

(conn_handle, attr_handle)

_IRQ_GATTS_READ_REQUEST

4

已連線的用戶端發出了一個讀取請求。從下表傳回一個非零的錯誤代碼以拒絕讀取,或傳回 0 / None 以接受。

(conn_handle, attr_handle)

_IRQ_SCAN_RESULT

5

在主動掃描期間收到了一個廣播封包。

(addr_type, addr, adv_type, rssi, adv_data)

_IRQ_SCAN_DONE

6

目前的掃描已結束,原因可能是設定的持續時間已過,或是呼叫了 gap_scan(None)

()

_IRQ_PERIPHERAL_CONNECT

7

先前發出的 gap_connect 已成功。

(conn_handle, addr_type, addr)

_IRQ_PERIPHERAL_DISCONNECT

8

已連線的 peripheral 已斷線。

(conn_handle, addr_type, addr)

_IRQ_GATTC_SERVICE_RESULT

9

gattc_discover_services 找到了一個服務。

(conn_handle, start_handle, end_handle, uuid)

_IRQ_GATTC_SERVICE_DONE

10

服務探索已完成。

(conn_handle, status)

_IRQ_GATTC_CHARACTERISTIC_RESULT

11

gattc_discover_characteristics 找到了一個特徵。

(conn_handle, end_handle, value_handle, properties, uuid)

_IRQ_GATTC_CHARACTERISTIC_DONE

12

特徵探索已完成。

(conn_handle, status)

_IRQ_GATTC_DESCRIPTOR_RESULT

13

gattc_discover_descriptors 找到了一個描述子。

(conn_handle, dsc_handle, uuid)

_IRQ_GATTC_DESCRIPTOR_DONE

14

描述子探索已完成。

(conn_handle, status)

_IRQ_GATTC_READ_RESULT

15

先前發出的 gattc_read 已傳回資料。

(conn_handle, value_handle, char_data)

_IRQ_GATTC_READ_DONE

16

先前發出的 gattc_read 已完成。

(conn_handle, value_handle, status)

_IRQ_GATTC_WRITE_DONE

17

先前發出的 gattc_write 已獲得確認。

(conn_handle, value_handle, status)

_IRQ_GATTC_NOTIFY

18

遠端伺服器已傳送一個(未確認的)通知。

(conn_handle, value_handle, notify_data)

_IRQ_GATTC_INDICATE

19

遠端伺服器已傳送一個(已確認的)指示。

(conn_handle, value_handle, notify_data)

_IRQ_GATTS_INDICATE_DONE

20

先前傳送的指示已獲得用戶端確認(或已逾時)。

(conn_handle, value_handle, status)

_IRQ_MTU_EXCHANGED

21

一次 ATT MTU 交換已完成(由任一方發起)。

(conn_handle, mtu)

_IRQ_L2CAP_ACCEPT

22

遠端裝置已在本裝置正在監聽的某個 PSM 上請求 L2CAP 連線。傳回非零整數以拒絕,或傳回 0 / None 以接受。

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_CONNECT

23

L2CAP 通道現已建立,原因可能是接受了一個傳入請求,或是完成了一個對外的 l2cap_connect

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_DISCONNECT

24

L2CAP 通道已斷線。status 在乾淨斷線時為 0,若對外連線嘗試失敗則為非零值。

(conn_handle, cid, psm, status)

_IRQ_L2CAP_RECV

25

L2CAP 通道上已有資料抵達。呼叫 l2cap_recvinto 來讀取它。

(conn_handle, cid)

_IRQ_L2CAP_SEND_READY

26

先前傳回 Falsel2cap_send 已排空,通道現已再次就緒。非零的 status 表示傳輸緩衝區發生溢位,應用程式必須重新傳送該資料。

(conn_handle, cid, status)

_IRQ_CONNECTION_UPDATE

27

遠端裝置已更新連線參數(interval、latency、supervision timeout)。

(conn_handle, conn_interval, conn_latency, supervision_timeout, status)

_IRQ_ENCRYPTION_UPDATE

28

連線的加密狀態已變更,通常是在配對或綁定完成之後。

(conn_handle, encrypted, authenticated, bonded, key_size)

_IRQ_GET_SECRET

29

協定堆疊正在請求一個已儲存的綁定密鑰。如果 keyNone,則傳回 sec_type 中第 index 個已儲存的值;否則傳回與給定的 (sec_type, key) 相關聯的值。若沒有儲存任何內容,則傳回 None

(sec_type, index, key)

_IRQ_SET_SECRET

30

協定堆疊正要求應用程式將一個綁定密鑰持久化儲存。儲存完成後傳回 True

(sec_type, key, value)

_IRQ_PASSKEY_ACTION

31

配對過程中需要一個密碼金鑰(passkey)動作。請使用 gap_passkey 回應;可能的動作請參閱下方的 passkey 動作表。

(conn_handle, action, passkey)

對於 _IRQ_GATTS_READ_REQUEST 事件,可用的傳回代碼為:

常數

意義

_GATTS_NO_ERROR

0x00

接受讀取。

_GATTS_ERROR_READ_NOT_PERMITTED

0x02

不允許讀取。

_GATTS_ERROR_WRITE_NOT_PERMITTED

0x03

不允許寫入。

_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION

0x05

用戶端未通過驗證。

_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION

0x08

用戶端未獲授權。

_GATTS_ERROR_INSUFFICIENT_ENCRYPTION

0x0f

連結未加密。

對於 _IRQ_PASSKEY_ACTION 事件,可用的動作為:

常數

意義

_PASSKEY_ACTION_NONE

0

不需要任何動作。

_PASSKEY_ACTION_INPUT

2

提示使用者輸入遠端裝置上顯示的密碼金鑰。

_PASSKEY_ACTION_DISPLAY

3

顯示一組 6 位數的密碼金鑰供遠端裝置輸入。

_PASSKEY_ACTION_NUMERIC_COMPARISON

4

確認密碼金鑰與遠端裝置上顯示的相符。

為了節省韌體空間,這些常數並未包含在 bluetooth 模組中。請從上方列表中將你需要的常數加入你的程式。

Broadcaster 角色(廣播者)

gap_advertise(interval_us: int | None, adv_data: bytes | None = None, *, resp_data: bytes | None = None, connectable: bool = True) None

以指定的間隔(以微秒為單位)開始廣播。此間隔會向下取整至最接近的 625us。要停止廣播,請將 interval_us 設為 None

adv_dataresp_data 可以是任何實作緩衝區協定的類型(例如 bytesbytearraystr)。adv_data 會包含在所有廣播中,而 resp_data 則會在回應主動掃描時傳送。

注意: 如果 adv_data(或 resp_data)為 None,則會重複使用上一次呼叫 gap_advertise 時傳入的資料。這讓廣播者只需以 gap_advertise(interval_us) 即可恢復廣播。要清除廣播酬載,請傳入一個空的 bytes,亦即 b''

Observer 角色(掃描者)

gap_scan(duration_ms: int | None, interval_us: int = 1280000, window_us: int = 11250, active: bool = False, /) None

執行一次掃描作業,持續指定的時間(以毫秒為單位)。

要無限期掃描,請將 duration_ms 設為 0

要停止掃描,請將 duration_ms 設為 None

使用 interval_uswindow_us 可選擇性地設定占空比(duty cycle)。掃描者會每隔 interval_us 微秒執行 window_us 微秒,總共持續 duration_ms 毫秒。預設的 interval 與 window 分別為 1.28 秒與 11.25 毫秒(背景掃描)。

對於每個掃描結果,都會引發 _IRQ_SCAN_RESULT 事件,事件資料為 (addr_type, addr, adv_type, rssi, adv_data)

addr_type 的值表示公開或隨機位址:

名稱

意義

0x00

PUBLIC

公開裝置位址。

0x01

RANDOM

隨機位址(可為靜態、RPA 或 NRPA;類型編碼於位址本身之中)。

adv_type 的值對應於藍牙規格:

名稱

意義

0x00

ADV_IND

可連線且可掃描的非定向廣播。

0x01

ADV_DIRECT_IND

可連線的定向廣播。

0x02

ADV_SCAN_IND

可掃描的非定向廣播。

0x03

ADV_NONCONN_IND

不可連線的非定向廣播。

0x04

SCAN_RSP

掃描回應。

如果你希望在結果中接收掃描回應,可將 active 設為 True

當掃描停止時(無論是因為持續時間結束或被明確停止),都會引發 _IRQ_SCAN_DONE 事件。

Central 角色

central 裝置可以連線至它使用 observer 角色(參閱 gap_scan)所探索到的 peripheral,或是連線至已知位址的 peripheral。

gap_connect(addr_type: int | None, addr: bytes | None = None, scan_duration_ms: int = 2000, min_conn_interval_us: int | None = None, max_conn_interval_us: int | None = None, /) None

連線至一個 peripheral。

關於位址類型的詳細資訊,請參閱 gap_scan

要提早取消一個進行中的連線嘗試,請呼叫 gap_connect(None)

成功時會引發 _IRQ_PERIPHERAL_CONNECT 事件。若取消連線嘗試,則會引發 _IRQ_PERIPHERAL_DISCONNECT 事件。

裝置會等待最多 scan_duration_ms 的時間以接收來自該裝置的廣播酬載。

連線間隔(connection interval)可使用 min_conn_interval_usmax_conn_interval_us 其中之一或兩者以微秒為單位設定。否則會選擇一個預設間隔,通常介於 30000 至 50000 微秒之間。較短的間隔會提高吞吐量,但代價是耗電量增加。

Peripheral 角色

peripheral 裝置應傳送可連線的廣播(參閱 gap_advertise)。它通常會作為 GATT 伺服器運作,並會先使用 gatts_register_services 註冊服務與特徵。

當一個 central 連線時,會引發 _IRQ_CENTRAL_CONNECT 事件。

Central 與 Peripheral 角色

gap_disconnect(conn_handle: int, /) bool

中斷指定連線控制代碼(connection handle)的連線。它可以是一個連線到本裝置的 central(若本裝置作為 peripheral),或是一個先前由本裝置連線的 peripheral(若本裝置作為 central)。

成功時會引發 _IRQ_PERIPHERAL_DISCONNECT_IRQ_CENTRAL_DISCONNECT 事件。

如果該連線控制代碼並未連線,則傳回 False,否則傳回 True

GATT 伺服器

GATT 伺服器擁有一組已註冊的服務。每個服務可包含特徵,而每個特徵都有一個值。特徵也可以包含描述子,描述子本身也有值。

這些值儲存在本機,並透過其在服務註冊期間產生的「value handle」來存取。它們也可由遠端的用戶端裝置讀取或寫入。此外,伺服器可透過連線控制代碼向已連線的用戶端「通知」某個特徵。

處於 central 或 peripheral 角色的裝置都可以作為 GATT 伺服器運作,不過在大多數情況下,較常見的是由 peripheral 裝置作為伺服器。

特徵與描述子的預設最大大小為 20 個位元組(預設的 ATT MTU 為 23 個位元組,減去 3 個位元組的 ATT 標頭;協商出較大的 MTU 本身並不會提高此上限)。用戶端寫入的任何內容都會被截斷至此長度。然而,任何本機寫入都會增大其最大大小,因此若你想允許用戶端對某個特徵進行較大的寫入,請在註冊後使用 gatts_write,例如 gatts_write(char_handle, bytes(100))

gatts_register_services(services_definition: Sequence[Sequence], /) Sequence[Sequence[int]]

以指定的服務設定伺服器,並取代任何現有的服務。

services_definition 是一個由 services 組成的清單,其中每個 service 都是一個兩元素的元組,包含一個 UUID 與一個 characteristics 清單。

每個 characteristic 都是一個兩元素或三元素的元組,包含一個 UUID、一個 flags 值,以及一個可選的 descriptors 清單。

每個 descriptor 都是一個兩元素的元組,包含一個 UUID 與一個 flags 值。

flags 是下面所定義旗標的位元 OR 組合。它們同時設定特徵(或描述子)的行為以及安全性與隱私需求。

傳回值是一個清單(每個服務一個元素),其元素為元組(每個元素都是一個 value handle)。特徵與描述子的控制代碼會依其定義順序被攤平到同一個元組中。

下列範例註冊了兩個服務(Heart Rate 與 Nordic UART)::

bt = bluetooth.BLE()
bt.active(True)

# Heart Rate service: one Heart Rate Measurement characteristic.
HR_SERVICE = (
    bluetooth.UUID(0x180D),
    (
        (bluetooth.UUID(0x2A37),
         bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY),
    ),
)

# Nordic UART service: a TX characteristic the client subscribes
# to for notifications, and an RX characteristic it writes to.
UART_SERVICE = (
    bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E'),
    (
        (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'),
         bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY),
        (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'),
         bluetooth.FLAG_WRITE),
    ),
)

((hr,), (tx, rx)) = bt.gatts_register_services(
    (HR_SERVICE, UART_SERVICE),
)

三個 value handle(hrtxrx)可搭配 gatts_readgatts_writegatts_notifygatts_indicate 使用。

注意: 註冊服務前必須先停止廣播。

特徵與描述子可用的旗標為:

常數

意義

_FLAG_BROADCAST

0x0001

特徵可被廣播。

_FLAG_READ

0x0002

用戶端可讀取該值。

_FLAG_WRITE_NO_RESPONSE

0x0004

用戶端可寫入而不期望回應。

_FLAG_WRITE

0x0008

用戶端可進行帶有確認回應的寫入。

_FLAG_NOTIFY

0x0010

伺服器可傳送通知(未確認)。

_FLAG_INDICATE

0x0020

伺服器可傳送指示(已確認)。

_FLAG_AUTHENTICATED_SIGNED_WRITE

0x0040

用戶端可發出簽署寫入。

_FLAG_AUX_WRITE

0x0100

擴充屬性:允許佇列式/可靠寫入。

_FLAG_READ_ENCRYPTED

0x0200

讀取需要加密連結。

_FLAG_READ_AUTHENTICATED

0x0400

讀取需要經過驗證(受 MITM 防護)的連結。

_FLAG_READ_AUTHORIZED

0x0800

讀取需要應用程式層級的授權。

_FLAG_WRITE_ENCRYPTED

0x1000

寫入需要加密連結。

_FLAG_WRITE_AUTHENTICATED

0x2000

寫入需要經過驗證(受 MITM 防護)的連結。

_FLAG_WRITE_AUTHORIZED

0x4000

寫入需要應用程式層級的授權。

如同上方的事件常數一樣,這些旗標並未由 bluetooth 模組提供;請將你需要的旗標複製到你的程式中。

gatts_read(value_handle: int, /) bytes

讀取此控制代碼的本機值(其值是由 gatts_write 寫入或由遠端用戶端寫入的)。

gatts_write(value_handle: int, data: bytes, send_update: bool = False, /) None

寫入此控制代碼的本機值,該值可由用戶端讀取。

如果 send_updateTrue,則任何已訂閱的用戶端都會收到關於此寫入的通知(或指示,取決於它們訂閱的內容以及該特徵支援哪些操作)。

gatts_notify(conn_handle: int, value_handle: int, data: bytes | None = None, /) None

向已連線的用戶端傳送一個通知請求。

如果 dataNone(預設值),則會傳送目前的本機值(即以 gatts_write 設定的值)。

否則,如果 data 不為 None,則該值會作為通知的一部分傳送給用戶端。本機值不會被修改。

注意: 無論用戶端對此特徵的訂閱狀態為何,通知都會被傳送。

gatts_indicate(conn_handle: int, value_handle: int, data: bytes | None = None, /) None

向已連線的用戶端傳送一個指示請求。

如果 dataNone(預設值),則會傳送目前的本機值(即以 gatts_write 設定的值)。

否則,如果 data 不為 None,則該值會作為指示的一部分傳送給用戶端。本機值不會被修改。

在獲得確認(或失敗,例如逾時)時,會引發 _IRQ_GATTS_INDICATE_DONE 事件。

注意: 無論用戶端對此特徵的訂閱狀態為何,指示都會被傳送。

gatts_set_buffer(value_handle: int, len: int, append: bool = False, /) None

設定某個值的內部緩衝區大小(以位元組為單位)。這會限制可接收的最大寫入量。預設為 20 個位元組(預設的 ATT MTU 為 23,減去 3 個位元組的 ATT 標頭)。

append 設為 True 會使所有遠端寫入以附加方式加入目前的值,而非取代它。以此方式最多可緩衝 len 個位元組。當你使用 gatts_read 時,讀取後該值會被清除。此功能在實作類似 Nordic UART Service 之類的東西時很有用。

GATT 用戶端

GATT 用戶端可以探索並讀取/寫入遠端 GATT 伺服器上的特徵。

較常見的是由 central 角色的裝置作為 GATT 用戶端,不過 peripheral 也可以作為用戶端,以便探索已連線到它的 central 的相關資訊(例如從裝置資訊服務讀取裝置名稱)。

gattc_discover_services(conn_handle: int, uuid: UUID | None = None, /) None

向已連線的伺服器查詢其服務。

可選擇指定一個服務 uuid 以僅查詢該服務。

對於每個探索到的服務,都會引發 _IRQ_GATTC_SERVICE_RESULT 事件,並在完成時引發 _IRQ_GATTC_SERVICE_DONE

gattc_discover_characteristics(conn_handle: int, start_handle: int, end_handle: int, uuid: UUID | None = None, /) None

向已連線的伺服器查詢指定範圍內的特徵。

可選擇指定一個特徵 uuid 以僅查詢該特徵。

傳入 start_handle=1end_handle=0xffff 可涵蓋完整的 GATT 屬性控制代碼範圍,因此此組合實際上會搜尋遠端裝置上的每個服務。

對於每個探索到的特徵,都會引發 _IRQ_GATTC_CHARACTERISTIC_RESULT 事件,並在完成時引發 _IRQ_GATTC_CHARACTERISTIC_DONE

gattc_discover_descriptors(conn_handle: int, start_handle: int, end_handle: int, /) None

向已連線的伺服器查詢指定範圍內的描述子。

對於每個探索到的描述子,都會引發 _IRQ_GATTC_DESCRIPTOR_RESULT 事件,並在完成時引發 _IRQ_GATTC_DESCRIPTOR_DONE

gattc_read(conn_handle: int, value_handle: int, /) None

向已連線的伺服器發出對指定特徵或描述子控制代碼的遠端讀取。

當有值可用時,會引發 _IRQ_GATTC_READ_RESULT 事件,並在完成時引發 _IRQ_GATTC_READ_DONE

gattc_write(conn_handle: int, value_handle: int, data: bytes, mode: int = 0, /) None

向已連線的伺服器發出對指定特徵或描述子控制代碼的遠端寫入。

引數 mode 指定寫入行為,目前支援的值為:

  • mode=0(預設)是不帶回應的寫入:寫入會傳送至遠端伺服器,但不會傳回任何確認,也不會引發任何事件。

  • mode=1 是帶回應的寫入:會要求遠端伺服器傳送一個回應/確認,表示它已收到資料。

如果收到來自遠端伺服器的回應,會引發 _IRQ_GATTC_WRITE_DONE 事件。

gattc_exchange_mtu(conn_handle: int, /) None

與已連線的伺服器發起 MTU 交換,使用以 BLE.config(mtu=value) 設定的偏好 MTU。

當 MTU 交換完成時,會引發 _IRQ_MTU_EXCHANGED 事件。

MTU 交換通常由 central 發起;NimBLE 支援兩種角色。

L2CAP 連線導向通道

此功能允許兩個 BLE 裝置之間進行類似 socket 的資料交換。一旦裝置透過 GAP 連線後,任一裝置都可以在一個數值型 PSM(Protocol/Service Multiplexer,協定/服務多工器)上監聽另一個裝置的連線。

同一時間只能有一個 L2CAP 通道處於啟用狀態(亦即你無法在監聽的同時進行連線)。

啟用中的 L2CAP 通道是以其建立所在的連線控制代碼以及一個 CID(通道 ID)來識別。

連線導向通道具有內建的信用額度式(credit-based)流量控制。與 ATT 不同(裝置在 ATT 中會協商一個共用的 MTU),監聽端與連線端裝置各自設定一個獨立的 MTU,用以限制在 l2cap_recvinto 完全消耗之前,遠端裝置最多可傳送的未處理資料量。

l2cap_listen(psm: int, mtu: int, /) None

開始在指定的 psm 上監聽傳入的 L2CAP 通道請求,並將本機 MTU 設為 mtu

當遠端裝置發起連線時,會引發 _IRQ_L2CAP_ACCEPT 事件,這讓監聽伺服器有機會拒絕該傳入連線(透過傳回一個非零整數)。

一旦連線被接受,會引發 _IRQ_L2CAP_CONNECT 事件,讓伺服器能取得通道 ID(CID)以及本機與遠端的 MTU。

注意: 目前無法停止監聽。

l2cap_connect(conn_handle: int, psm: int, mtu: int, /) None

在指定的 psm 上連線至一個正在監聽的對等端(peer),並將本機 MTU 設為 mtu

連線成功時,會引發 _IRQ_L2CAP_CONNECT 事件,讓用戶端能取得 CID 以及本機與遠端(對等端)的 MTU。

連線失敗時,會引發帶有非零 status 的 _IRQ_L2CAP_DISCONNECT 事件。

l2cap_disconnect(conn_handle: int, cid: int, /) None

中斷具有指定 conn_handlecid 的啟用中 L2CAP 通道。

l2cap_send(conn_handle: int, cid: int, buf: bytes, /) bool

在以 conn_handlecid 識別的 L2CAP 通道上傳送指定的 buf(其必須支援緩衝區協定)。

緩衝區必須同時滿足兩項限制:它不得超過遠端(對等端)MTU,且不得超過本機 MTU 的兩倍。

如果通道現已「停滯(stalled)」,這會傳回 False,意思是在收到 _IRQ_L2CAP_SEND_READY 事件之前不得再次呼叫 l2cap_send(該事件會在遠端裝置授予更多信用額度時發生,通常是在它接收並處理完資料之後)。

l2cap_recvinto(conn_handle: int, cid: int, buf: Any | None, /) int

從指定的 conn_handlecid 接收資料到所提供的 buf(其必須支援緩衝區協定,例如 bytearray 或 memoryview)中。

傳回從通道讀取的位元組數。

如果 bufNone,則傳回可用的位元組數。

注意: 在收到 _IRQ_L2CAP_RECV 事件後,應用程式應持續呼叫 l2cap_recvinto,直到接收緩衝區中沒有更多可用的位元組為止(通常最多為遠端(對等端)MTU 的大小)。

在接收緩衝區清空之前,遠端裝置不會獲得更多通道信用額度,因而無法再傳送任何資料。

配對與綁定

配對讓連線能夠透過交換密鑰而被加密與驗證(可選擇透過密碼金鑰驗證來提供 MITM 防護)。

綁定是將那些密鑰儲存到非揮發性儲存空間的過程。綁定後,裝置便能根據已儲存的識別解析金鑰(IRK)解析來自另一裝置的可解析私有位址(RPA)。為了支援綁定,應用程式必須實作 _IRQ_GET_SECRET_IRQ_SET_SECRET 事件。

gap_pair(conn_handle: int, /) None

與遠端裝置發起配對。

在呼叫此方法之前,請確保已設定 iomitmle_securebond 組態選項(透過 config)。

配對成功時,會引發 _IRQ_ENCRYPTION_UPDATE 事件。

gap_passkey(conn_handle: int, action: int, passkey: int, /) None

針對指定的 conn_handleaction 回應一個 _IRQ_PASSKEY_ACTION 事件。passkey 的意義取決於 action(而 action 又取決於所設定的 I/O 能力):

動作

所需的 passkey 回應

_PASSKEY_ACTION_INPUT

使用者從遠端裝置讀取到的密碼金鑰。

_PASSKEY_ACTION_DISPLAY

在本機產生並顯示給使用者的隨機 6 位數密碼金鑰。

_PASSKEY_ACTION_NUMERIC_COMPARISON

傳回 1 以接受 _IRQ_PASSKEY_ACTION 事件中顯示的密碼金鑰,或傳回 0 以取消配對。

class UUID

class bluetooth.UUID(value: int | bytes | str, /)

以指定的 value 建立一個 UUID 實例。藍牙使用三種 UUID 寬度;UUID 接受其中任何一種:

UUID 寬度

可接受的 value 類型

範例

16 位元

int 或一個 2 位元組緩衝區(小端序)

UUID(0x2908)UUID(b'\x08\x29')

32 位元

4 位元組緩衝區(小端序)

UUID(b'\x08\x29\x00\x00')

128 位元

16 位元組緩衝區或一個帶連字號的字串

UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')

16 位元與 32 位元 UUID 通常是 SIG 分配的識別碼(參閱 Bluetooth 分配編號);128 位元 UUID 通常由廠商自行定義。