bluetooth — 저수준 Bluetooth

이 모듈은 온보드 Bluetooth 컨트롤러에 대한 인터페이스를 제공합니다. Central, Peripheral, Broadcaster, Observer 역할의 Bluetooth Low Energy(BLE)와 함께 GATT Server 및 Client, 그리고 L2CAP 연결 지향 채널을 지원합니다. 하나의 장치가 여러 역할로 동시에 동작할 수 있습니다. 페어링(pairing)과 본딩(bonding)도 지원됩니다.

이 API는 저수준 Bluetooth 프로토콜에 맞추어, 특정 장치 유형과 같은 상위 수준 추상화를 위한 빌딩 블록을 제공하기 위한 것입니다.

대부분의 애플리케이션에서는 이 모듈을 asyncio 기반으로 감싼 상위 수준 라이브러리인 aioble를 사용하는 것이 좋습니다. aioble — 비동기 BLE을 참고하세요.

class BLE

class bluetooth.BLE

싱글톤 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

    컨트롤러의 public 주소를 사용합니다.

    0x01

    RANDOM

    생성된 정적(static) 주소를 사용합니다.

    0x02

    RPA

    확인 가능한 비공개 주소(resolvable private address)를 사용합니다.

    0x03

    NRPA

    확인 불가능한 비공개 주소(non-resolvable private address)를 사용합니다.

    기본적으로 인터페이스는 가능한 경우 PUBLIC 주소를 사용하며, 그렇지 않으면 RANDOM 주소를 사용합니다.

  • 'gap_name': Generic Access 서비스(UUID 0x1800)의 Device Name 특성(UUID 0x2a00)에서 사용하는 GAP 장치 이름을 가져오거나 설정합니다. 이 값은 언제든지 설정할 수 있으며 여러 번 변경할 수 있습니다.

  • 'rxbuf': 들어오는 이벤트를 저장하는 데 사용되는 내부 버퍼의 크기를 바이트 단위로 가져오거나 설정합니다. 이 버퍼는 전체 BLE 드라이버에 대해 전역적이므로 모든 특성을 포함한 모든 이벤트의 수신 데이터를 처리합니다. 이를 늘리면 버스트성 수신 데이터(예: 스캔 결과)를 더 잘 처리할 수 있고 더 큰 특성 값을 받을 수 있게 됩니다.

  • 'mtu': ATT MTU 교환 중에 사용될 MTU를 가져오거나 설정합니다. 결과 MTU는 이 값과 원격 장치의 MTU 중 더 작은 값이 됩니다. ATT MTU 교환은 (원격 장치가 시작하지 않는 한) 자동으로 일어나지 않으며, gattc_exchange_mtu를 사용해 수동으로 시작해야 합니다. 주어진 연결에 대한 MTU를 알아내려면 _IRQ_MTU_EXCHANGED 이벤트를 사용하세요.

  • '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 (이벤트별 값으로 이루어진 튜플) 입니다.

참고: 불필요한 할당을 방지하는 최적화로서, 튜플의 addr, adv_data, char_data, notify_data, uuid 항목은 bluetooth의 내부 링 버퍼를 가리키는 읽기 전용 memoryview 인스턴스이며, 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이고 실패 시 구현별 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이 아닌 오류 코드를 반환하고, 수락하려면 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가 확인(acknowledge)되었습니다.

(conn_handle, value_handle, status)

_IRQ_GATTC_NOTIFY

18

원격 서버가 (확인되지 않은) 알림(notification)을 보냈습니다.

(conn_handle, value_handle, notify_data)

_IRQ_GATTC_INDICATE

19

원격 서버가 (확인된) 표시(indication)를 보냈습니다.

(conn_handle, value_handle, notify_data)

_IRQ_GATTS_INDICATE_DONE

20

이전에 보낸 표시(indication)가 클라이언트에 의해 확인되었습니다(또는 시간 초과되었습니다).

(conn_handle, value_handle, status)

_IRQ_MTU_EXCHANGED

21

ATT MTU 교환이 완료되었습니다(양쪽 중 어느 한쪽이 시작).

(conn_handle, mtu)

_IRQ_L2CAP_ACCEPT

22

원격 장치가 이 장치가 수신 대기 중인 PSM에 L2CAP 연결을 요청했습니다. 거부하려면 0이 아닌 정수를 반환하고, 수락하려면 0 / None을 반환하세요.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_CONNECT

23

들어오는 요청을 수락하거나 나가는 l2cap_connect를 완료하여 L2CAP 채널이 이제 설정되었습니다.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_DISCONNECT

24

L2CAP 채널이 연결 해제되었습니다. status는 정상적인 연결 해제의 경우 0이고, 나가는 연결 시도가 실패한 경우 0이 아닙니다.

(conn_handle, cid, psm, status)

_IRQ_L2CAP_RECV

25

L2CAP 채널에 데이터가 도착했습니다. 이를 읽으려면 l2cap_recvinto를 호출하세요.

(conn_handle, cid)

_IRQ_L2CAP_SEND_READY

26

False를 반환했던 이전 l2cap_send가 비워지고 채널이 다시 준비되었습니다. 0이 아닌 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

스택이 저장된 본딩 비밀(secret)을 요청하고 있습니다. keyNone이면 sec_typeindex번째 저장된 값을 반환하고, 그렇지 않으면 주어진 (sec_type, key)와 연관된 값을 반환하세요. 저장된 것이 없으면 None을 반환하세요.

(sec_type, index, key)

_IRQ_SET_SECRET

30

스택이 애플리케이션에 본딩 비밀(secret)을 영구 저장하도록 요청하고 있습니다. 저장이 완료되면 True를 반환하세요.

(sec_type, key, value)

_IRQ_PASSKEY_ACTION

31

페어링의 일부로 패스키(passkey) 작업이 필요합니다. gap_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_usNone으로 설정하세요.

adv_dataresp_data는 버퍼 프로토콜을 구현하는 모든 유형(예: bytes, bytearray, str)이 될 수 있습니다. 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_ms0으로 설정하세요.

스캔을 중지하려면 duration_msNone으로 설정하세요.

interval_uswindow_us를 사용하여 듀티 사이클을 선택적으로 설정할 수 있습니다. 스캐너는 총 duration_ms 밀리초 동안 interval_us 마이크로초마다 window_us 마이크로초씩 실행됩니다. 기본 interval과 window는 각각 1.28초와 11.25밀리초입니다(백그라운드 스캔).

각 스캔 결과에 대해 이벤트 데이터 (addr_type, addr, adv_type, rssi, adv_data)와 함께 _IRQ_SCAN_RESULT 이벤트가 발생합니다.

addr_type 값은 public 또는 random 주소를 나타냅니다:

이름

의미

0x00

PUBLIC

Public 장치 주소.

0x01

RANDOM

Random 주소(static, RPA 또는 NRPA 중 하나이며, 유형은 주소 자체에 인코딩되어 있습니다).

adv_type 값은 Bluetooth 사양에 해당합니다:

이름

의미

0x00

ADV_IND

연결 가능하고 스캔 가능한 비지향성 광고.

0x01

ADV_DIRECT_IND

연결 가능한 지향성 광고.

0x02

ADV_SCAN_IND

스캔 가능한 비지향성 광고.

0x03

ADV_NONCONN_IND

연결 불가능한 비지향성 광고.

0x04

SCAN_RSP

스캔 응답.

결과에서 스캔 응답을 받으려면 activeTrue로 설정할 수 있습니다.

스캔이 중지되면(지속 시간이 끝나거나 명시적으로 중지될 때), _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 동안 대기합니다.

연결 interval은 min_conn_interval_usmax_conn_interval_us 중 하나 또는 둘 다를 사용하여 마이크로초 단위로 설정할 수 있습니다. 그렇지 않으면 일반적으로 30000에서 50000마이크로초 사이의 기본 interval이 선택됩니다. interval이 짧을수록 전력 사용량을 희생하여 처리량이 증가합니다.

Peripheral 역할

peripheral 장치는 연결 가능한 광고를 보내야 합니다(gap_advertise 참고). 일반적으로 먼저 gatts_register_services를 사용하여 서비스와 특성을 등록한 후 GATT 서버로 동작합니다.

central이 연결되면 _IRQ_CENTRAL_CONNECT 이벤트가 발생합니다.

Central 및 Peripheral 역할

gap_disconnect(conn_handle: int, /) bool

지정된 연결 핸들을 연결 해제합니다. 이는 이 장치에 연결된 central(peripheral로 동작하는 경우)이거나 이전에 이 장치가 연결한 peripheral(central로 동작하는 경우)일 수 있습니다.

성공하면 _IRQ_PERIPHERAL_DISCONNECT 또는 _IRQ_CENTRAL_DISCONNECT 이벤트가 발생합니다.

연결 핸들이 연결되어 있지 않으면 False를, 그렇지 않으면 True를 반환합니다.

GATT 서버

GATT 서버에는 등록된 서비스 집합이 있습니다. 각 서비스에는 특성이 포함될 수 있으며, 각 특성에는 값이 있습니다. 특성에는 디스크립터도 포함될 수 있으며, 디스크립터 자체에도 값이 있습니다.

이러한 값은 로컬에 저장되며, 서비스 등록 중에 생성되는 “value handle”을 통해 접근됩니다. 또한 원격 클라이언트 장치에서 읽거나 쓸 수 있습니다. 추가로, 서버는 연결 핸들을 통해 연결된 클라이언트에게 특성을 “알림(notify)”할 수 있습니다.

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서비스의 리스트이며, 각 서비스는 UUID와 특성 리스트를 포함하는 2요소 튜플입니다.

특성은 UUID, flags 값, 그리고 선택적으로 descriptors 리스트를 포함하는 2요소 또는 3요소 튜플입니다.

descriptor는 UUID와 flags 값을 포함하는 2요소 튜플입니다.

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(hr, tx, rx)은 gatts_read, gatts_write, gatts_notify, gatts_indicate와 함께 사용할 수 있습니다.

참고: 서비스를 등록하기 전에 광고를 중지해야 합니다.

특성과 디스크립터에 사용할 수 있는 플래그는 다음과 같습니다:

상수

의미

_FLAG_BROADCAST

0x0001

특성을 브로드캐스트할 수 있습니다.

_FLAG_READ

0x0002

클라이언트가 값을 읽을 수 있습니다.

_FLAG_WRITE_NO_RESPONSE

0x0004

클라이언트가 응답을 기대하지 않고 쓸 수 있습니다.

_FLAG_WRITE

0x0008

클라이언트가 확인 응답과 함께 쓸 수 있습니다.

_FLAG_NOTIFY

0x0010

서버가 알림(notification, 확인되지 않음)을 보낼 수 있습니다.

_FLAG_INDICATE

0x0020

서버가 표시(indication, 확인됨)를 보낼 수 있습니다.

_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 로 설정된) 현재 로컬 값이 전송됩니다.

그렇지 않고 dataNone이 아니면 해당 값이 알림의 일부로 클라이언트에 전송됩니다. 로컬 값은 수정되지 않습니다.

참고: 이 특성에 대한 클라이언트의 구독 상태와 관계없이 알림이 전송됩니다.

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

연결된 클라이언트에게 표시(indication) 요청을 보냅니다.

dataNone (기본값) 이면, (gatts_write 로 설정된) 현재 로컬 값이 전송됩니다.

그렇지 않고 dataNone이 아니면 해당 값이 표시의 일부로 클라이언트에 전송됩니다. 로컬 값은 수정되지 않습니다.

확인(또는 시간 초과 등의 실패) 시 _IRQ_GATTS_INDICATE_DONE 이벤트가 발생합니다.

참고: 이 특성에 대한 클라이언트의 구독 상태와 관계없이 표시가 전송됩니다.

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

값에 대한 내부 버퍼 크기를 바이트 단위로 설정합니다. 이는 수신할 수 있는 가장 큰 쓰기를 제한합니다. 기본값은 20바이트입니다(기본 ATT MTU 23에서 3바이트 ATT 헤더를 뺀 값).

appendTrue로 설정하면 모든 원격 쓰기가 현재 값을 대체하는 대신 추가됩니다. 이 방식으로 최대 len 바이트까지 버퍼링할 수 있습니다. gatts_read를 사용하면 읽은 후 값이 지워집니다. 이 기능은 Nordic UART Service와 같은 것을 구현할 때 유용합니다.

GATT 클라이언트

GATT 클라이언트는 원격 GATT 서버의 특성을 검색하고 읽거나 쓸 수 있습니다.

central 역할 장치가 GATT 클라이언트로 동작하는 것이 더 일반적이지만, peripheral이 연결된 central에 대한 정보를 검색하기 위해(예: device information service에서 장치 이름을 읽기 위해) 클라이언트로 동작하는 것도 가능합니다.

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

BLE.config(mtu=value)로 설정한 선호 MTU를 사용하여 연결된 서버와 MTU 교환을 시작합니다.

MTU 교환이 완료되면 _IRQ_MTU_EXCHANGED 이벤트가 발생합니다.

MTU 교환은 일반적으로 central이 시작하지만, NimBLE는 두 역할을 모두 지원합니다.

L2CAP 연결 지향 채널

이 기능은 두 BLE 장치 간의 소켓과 유사한 데이터 교환을 가능하게 합니다. 장치가 GAP를 통해 연결되면, 어느 한 장치든 다른 장치가 숫자 PSM(Protocol/Service Multiplexer)으로 연결하기를 수신 대기할 수 있습니다.

한 번에 하나의 L2CAP 채널만 활성화될 수 있습니다(즉, 수신 대기 중에는 연결할 수 없습니다).

활성 L2CAP 채널은 설정된 연결 핸들과 CID(channel ID)로 식별됩니다.

연결 지향 채널에는 크레딧 기반 흐름 제어가 내장되어 있습니다. 장치가 공유 MTU를 협상하는 ATT와 달리, 수신 대기 장치와 연결 장치는 각각 독립적인 MTU를 설정하며, 이는 원격 장치가 l2cap_recvinto에서 완전히 소비되기 전에 보낼 수 있는 미처리 데이터의 최대량을 제한합니다.

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

로컬 MTU를 mtu로 설정한 상태에서 지정된 psm으로 들어오는 L2CAP 채널 요청을 수신 대기하기 시작합니다.

원격 장치가 연결을 시작하면 _IRQ_L2CAP_ACCEPT 이벤트가 발생하며, 이는 수신 대기 서버가 (0이 아닌 정수를 반환하여) 들어오는 연결을 거부할 기회를 제공합니다.

연결이 수락되면 _IRQ_L2CAP_CONNECT 이벤트가 발생하여 서버가 channel ID(CID)와 로컬 및 원격 MTU를 얻을 수 있게 합니다.

참고: 현재 수신 대기를 중지하는 것은 불가능합니다.

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

로컬 MTU를 mtu로 설정한 상태에서 지정된 psm의 수신 대기 중인 피어에 연결합니다.

연결에 성공하면 _IRQ_L2CAP_CONNECT 이벤트가 발생하여 클라이언트가 CID와 로컬 및 원격(피어) MTU를 얻을 수 있게 합니다.

연결에 실패하면 0이 아닌 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 이벤트를 받은 후, 애플리케이션은 수신 버퍼에 더 이상 사용 가능한 바이트가 없을 때까지(일반적으로 원격(피어) MTU 크기까지) l2cap_recvinto를 계속 호출해야 합니다.

수신 버퍼가 비워질 때까지 원격 장치에는 더 많은 채널 크레딧이 부여되지 않으며 더 이상 데이터를 보낼 수 없습니다.

페어링 및 본딩

페어링을 통해 비밀(secret) 교환을 통해 연결을 암호화하고 인증할 수 있습니다(패스키 인증을 통한 선택적 MITM 보호 포함).

본딩은 그러한 비밀을 비휘발성 저장소에 저장하는 과정입니다. 본딩되면 장치는 저장된 identity resolving key(IRK)를 기반으로 다른 장치의 resolvable private address(RPA)를 확인할 수 있습니다. 본딩을 지원하려면 애플리케이션이 _IRQ_GET_SECRET_IRQ_SET_SECRET 이벤트를 구현해야 합니다.

gap_pair(conn_handle: int, /) None

원격 장치와 페어링을 시작합니다.

이를 호출하기 전에 io, mitm, le_secure, bond 설정 옵션이 설정되어 있는지 확인하세요(config를 통해).

페어링에 성공하면 _IRQ_ENCRYPTION_UPDATE 이벤트가 발생합니다.

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

지정된 conn_handleaction에 대한 _IRQ_PASSKEY_ACTION 이벤트에 응답합니다. passkey의 의미는 action에 따라 다릅니다(이는 다시 설정된 I/O 기능에 따라 다릅니다):

작업

필요한 passkey 응답

_PASSKEY_ACTION_INPUT

사용자가 원격 장치에서 읽은 패스키.

_PASSKEY_ACTION_DISPLAY

사용자에게 표시되는 로컬에서 생성된 무작위 6자리 패스키.

_PASSKEY_ACTION_NUMERIC_COMPARISON

_IRQ_PASSKEY_ACTION 이벤트에 표시된 패스키를 수락하려면 1, 페어링을 취소하려면 0.

class UUID

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

지정된 value로 UUID 인스턴스를 생성합니다. Bluetooth는 세 가지 UUID 폭을 사용하며, UUID는 그중 어느 것이든 받습니다:

UUID 폭

허용되는 value 유형

예시

16비트

int 또는 2바이트 버퍼(little-endian)

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

32비트

4바이트 버퍼(little-endian)

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

128비트

16바이트 버퍼 또는 하이픈으로 구분된 문자열

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

16비트 및 32비트 UUID는 일반적으로 SIG가 할당한 식별자입니다(Bluetooth assigned numbers 참고). 128비트 UUID는 일반적으로 벤더가 정의합니다.