bluetooth — низькорівневий Bluetooth

Цей модуль надає інтерфейс до вбудованого контролера Bluetooth. Він підтримує Bluetooth Low Energy (BLE) у ролях Central, Peripheral, Broadcaster та Observer, а також сервер та клієнт GATT і канали L2CAP з орієнтацією на з’єднання. Пристрій може одночасно виконувати кілька ролей. Підтримуються також сполучення та зв’язування.

Цей API призначений для відповідності низькорівневому протоколу Bluetooth і надання будівельних блоків для абстракцій вищого рівня, наприклад типів пристроїв.

Порада

Для більшості застосунків надайте перевагу бібліотеці aioble вищого рівня, яка надає обгортку на основі asyncio навколо цього модуля. Дивіться aioble — Async BLE.

клас 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

    Використовувати публічну адресу контролера.

    0x01

    RANDOM

    Використовувати згенеровану статичну адресу.

    0x02

    RPA

    Використовувати приватні адреси, що можна розпізнати.

    0x03

    NRPA

    Використовувати приватні адреси, які не можна розпізнати.

    За замовчуванням інтерфейс використовуватиме адресу PUBLIC, якщо вона доступна, інакше використовуватиметься адреса RANDOM.

  • 'gap_name': Отримати/встановити назву пристрою GAP, яка використовується сервісом Generic Access (UUID 0x1800), характеристика Device Name (UUID 0x2a00). Може бути встановлена будь-коли та змінена кілька разів.

  • 'rxbuf': Отримати/встановити розмір у байтах внутрішнього буфера, що використовується для зберігання вхідних подій. Цей буфер є глобальним для всього драйвера BLE і тому обробляє вхідні дані для всіх подій, включаючи всі характеристики. Збільшення цього значення дозволяє краще обробляти пакетні вхідні дані (наприклад результати сканування) і отримувати більші значення характеристик.

  • 'mtu': Отримати/встановити MTU, що буде використовуватися під час обміну ATT MTU. Отриманий MTU буде мінімальним із цього значення та MTU віддаленого пристрою. Обмін ATT MTU не відбуватиметься автоматично (якщо тільки його не ініціює віддалений пристрій) і має бути ініційований вручну за допомогою gattc_exchange_mtu. Використовуйте подію _IRQ_MTU_EXCHANGED для визначення MTU для певного з’єднання.

  • 'bond': Встановлює, чи буде зв’язування увімкнено під час сполучення. Коли увімкнено, запити на сполучення встановлюватимуть прапор «bond» і ключі будуть збережені обома пристроями.

  • 'mitm': Встановлює, чи потрібен захист від MITM для сполучення.

  • 'io': Встановлює можливості вводу/виводу цього пристрою.

    Доступні параметри:

    Константа

    Значення

    Можливість

    _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 у кортежах є екземплярами 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

Центральний пристрій підключився до цього периферійного пристрою.

(conn_handle, addr_type, addr)

_IRQ_CENTRAL_DISCONNECT

2

Центральний пристрій відключився від цього периферійного пристрою.

(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

Підключений периферійний пристрій відключився.

(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

Віддалений пристрій запросив L2CAP-з’єднання на PSM, який прослуховує цей пристрій. Поверніть ненульове ціле число, щоб відхилити, або 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

Попередній l2cap_send, що повернув False, завершив передачу і канал готовий знову. Ненульовий status означає, що буфер передачі переповнився і застосунок повинен повторно надіслати дані.

(conn_handle, cid, status)

_IRQ_CONNECTION_UPDATE

27

Віддалений пристрій оновив параметри з’єднання (інтервал, затримка, час нагляду).

(conn_handle, conn_interval, conn_latency, supervision_timeout, status)

_IRQ_ENCRYPTION_UPDATE

28

Стан шифрування з’єднання змінився, зазвичай після завершення сполучення або зв’язування.

(conn_handle, encrypted, authenticated, bonded, key_size)

_IRQ_GET_SECRET

29

Стек запитує збережений секрет зв’язування. Якщо key дорівнює None, повертається index-е збережене значення sec_type; інакше повертається значення, пов’язане з (sec_type, key). Поверніть None, якщо нічого не збережено.

(sec_type, index, key)

_IRQ_SET_SECRET

30

Стек просить застосунок зберегти секрет зв’язування. Поверніть True після збереження.

(sec_type, key, value)

_IRQ_PASSKEY_ACTION

31

Під час сполучення потрібна дія з паролем. Відповідайте за допомогою 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 (Advertiser)

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

Розпочинає рекламування з вказаним інтервалом (у мікросекундах). Цей інтервал буде округлено вниз до найближчих 625 мкс. Щоб зупинити рекламування, встановіть interval_us на None.

adv_data і resp_data можуть бути будь-якого типу, що реалізує буферний протокол (наприклад bytes, bytearray, str). adv_data включається у всі широкомовні передачі, а resp_data надсилається у відповідь на активне сканування.

Примітка: якщо adv_data (або resp_data) дорівнює None, тоді будуть повторно використані дані, передані в попередньому виклику gap_advertise. Це дозволяє broadcaster’у відновити рекламування за допомогою лише gap_advertise(interval_us). Щоб очистити рекламне навантаження, передайте порожній bytes, тобто b''.

Роль Observer (Scanner)

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_us і window_us для необов’язкового налаштування робочого циклу. Сканер працюватиме протягом window_us мікросекунд кожні interval_us мікросекунд загальною тривалістю duration_ms мілісекунд. Інтервал і вікно за замовчуванням становлять 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 відповідають специфікації Bluetooth:

Значення

Назва

Значення

0x00

ADV_IND

Спрямоване рекламування з можливістю підключення та сканування.

0x01

ADV_DIRECT_IND

Спрямоване рекламування з можливістю підключення.

0x02

ADV_SCAN_IND

Неспрямоване рекламування з можливістю сканування.

0x03

ADV_NONCONN_IND

Неспрямоване рекламування без можливості підключення.

0x04

SCAN_RSP

Відповідь на сканування.

active може бути встановлено на True, якщо ви хочете отримувати відповіді на сканування у результатах.

Коли сканування зупинено (або після закінчення тривалості, або при явній зупинці), буде викликана подія _IRQ_SCAN_DONE.

Роль Central

Центральний пристрій може підключатися до периферійних пристроїв, які він виявив за допомогою ролі Observer (дивіться gap_scan) або із відомою адресою.

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

Підключитися до периферійного пристрою.

Дивіться gap_scan для отримання відомостей про типи адрес.

Щоб скасувати незавершену спробу підключення раніше, викличте gap_connect(None).

У разі успіху буде викликана подія _IRQ_PERIPHERAL_CONNECT. При скасуванні спроби підключення буде викликана подія _IRQ_PERIPHERAL_DISCONNECT.

Пристрій очікуватиме до scan_duration_ms мілісекунд для отримання рекламного пакету від пристрою.

Інтервал з’єднання можна налаштувати в мікросекундах за допомогою одного або обох параметрів min_conn_interval_us і max_conn_interval_us. Інакше буде обрано інтервал за замовчуванням, зазвичай від 30000 до 50000 мікросекунд. Коротший інтервал збільшить пропускну здатність за рахунок споживання енергії.

Роль Peripheral

Від периферійного пристрою очікується надсилання рекламних пакетів з можливістю підключення (дивіться gap_advertise). Зазвичай він діє як сервер GATT, попередньо зареєструвавши сервіси та характеристики за допомогою gatts_register_services.

Коли центральний пристрій підключається, буде викликана подія _IRQ_CENTRAL_CONNECT.

Ролі Central і Peripheral

gap_disconnect(conn_handle: int, /) bool

Відключити вказаний дескриптор з’єднання. Це може бути як центральний пристрій, що підключився до цього пристрою (якщо він діє як периферійний), так і периферійний пристрій, до якого цей пристрій підключався раніше (якщо він діє як центральний).

У разі успіху буде викликана подія _IRQ_PERIPHERAL_DISCONNECT або _IRQ_CENTRAL_DISCONNECT.

Повертає False, якщо дескриптор з’єднання не був підключений, і True в іншому випадку.

GATT Server

GATT server має набір зареєстрованих сервісів. Кожен сервіс може містити характеристики, кожна з яких має значення. Характеристики також можуть містити дескриптори, які самі мають значення.

Ці значення зберігаються локально та доступні за їх «value handle», що генерується під час реєстрації сервісу. Вони також можуть бути прочитані або записані віддаленим клієнтським пристроєм. Крім того, сервер може «сповіщати» характеристику підключеному клієнту через дескриптор з’єднання.

Пристрій у ролі центрального або периферійного може функціонувати як GATT server, однак у більшості випадків периферійний пристрій виступатиме сервером.

Характеристики та дескриптори мають максимальний розмір за замовчуванням 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 і список характеристик.

Кожна характеристика — це кортеж із двох або трьох елементів, що містить UUID, значення flags і, за потреби, список дескрипторів.

Кожен дескриптор — це кортеж із двох елементів, що містить UUID і значення flags.

flags — це побітова комбінація OR прапорів, визначених нижче. Вони встановлюють як поведінку характеристики (або дескриптора), так і вимоги до безпеки та конфіденційності.

Значення, що повертається, — це список (по одному елементу на сервіс) кортежів (кожен елемент є value handle). Дескриптори характеристик і їх 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

Сервер може надсилати сповіщення (непідтверджені).

_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

Читає локальне значення для цього handle (яке було записано gatts_write або віддаленим клієнтом).

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

Записує локальне значення для цього handle, яке може бути прочитане клієнтом.

Якщо send_update дорівнює True, то підписані клієнти будуть сповіщені (або отримають індикацію, залежно від того, на що вони підписані та які операції підтримує характеристика) про цей запис.

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

Надсилає запит сповіщення підключеному клієнту.

Якщо data дорівнює None (за замовчуванням), буде надіслано поточне локальне значення (встановлене за допомогою gatts_write).

Інакше, якщо data не дорівнює None, це значення надсилається клієнту як частина сповіщення. Локальне значення не змінюватиметься.

Примітка: Сповіщення буде надіслано незалежно від статусу підписки клієнта на цю характеристику.

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

Надсилає запит індикації підключеному клієнту.

Якщо data дорівнює None (за замовчуванням), буде надіслано поточне локальне значення (встановлене за допомогою 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 Client

GATT client може виявляти та читати/записувати характеристики на віддаленому GATT server.

Пристрій у ролі центрального частіше діє як GATT client, однак периферійний пристрій також може виступати клієнтом для виявлення інформації про центральний пристрій, що підключився до нього (наприклад для читання назви пристрою зі служби інформації про пристрій).

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=1 і end_handle=0xffff охоплює весь діапазон GATT attribute-handle, тому ця комбінація фактично здійснює пошук по всіх сервісах на віддаленому пристрої.

Для кожної виявленої характеристики буде викликана подія _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 з підключеним сервером, використовуючи бажаний MTU, встановлений за допомогою BLE.config(mtu=value).

Подія _IRQ_MTU_EXCHANGED буде викликана після завершення обміну MTU.

Обмін MTU зазвичай ініціюється центральним пристроєм; NimBLE підтримує обидві ролі.

Канали L2CAP з орієнтацією на з’єднання

Ця функція дозволяє обмін даними в стилі сокетів між двома BLE-пристроями. Після підключення пристроїв через GAP будь-який пристрій може прослуховувати, чи намагається інший підключитися на числовому PSM (Protocol/Service Multiplexer).

Одночасно може бути активний лише один L2CAP канал (тобто не можна підключатися під час прослуховування).

Активні канали L2CAP ідентифікуються дескриптором з’єднання, на якому вони були встановлені, та CID (ідентифікатор каналу).

Канали з орієнтацією на з’єднання мають вбудований керування потоком на основі кредитів. На відміну від ATT, де пристрої узгоджують спільний MTU, пристрій, що прослуховує, та пристрій, що підключається, кожен встановлюють незалежний MTU, який обмежує максимальну кількість необроблених даних, що може надіслати віддалений пристрій до їх повного споживання в l2cap_recvinto.

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

Починає прослуховування вхідних запитів L2CAP каналу на вказаному psm із локальним MTU, встановленим на mtu.

Коли віддалений пристрій ініціює з’єднання, буде викликана подія _IRQ_L2CAP_ACCEPT, яка дає можливість сервісу, що прослуховує, відхилити вхідне з’єднання (повернувши ненульове ціле число).

Після прийняття з’єднання буде викликана подія _IRQ_L2CAP_CONNECT, дозволяючи серверу отримати ідентифікатор каналу (CID) та локальний і віддалений MTU.

Примітка: Наразі неможливо зупинити прослуховування.

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

Підключитися до пристрою, що прослуховує на вказаному psm, із локальним MTU, встановленим на mtu.

При успішному з’єднанні буде викликана подія _IRQ_L2CAP_CONNECT, дозволяючи клієнту отримати CID та локальний і віддалений (peer) MTU.

Невдала спроба з’єднання ініціює подію _IRQ_L2CAP_DISCONNECT з ненульовим статусом.

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

Відключити активний канал L2CAP із вказаним conn_handle і cid.

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

Надіслати вказаний buf (що має підтримувати буферний протокол) по каналу L2CAP, ідентифікованому conn_handle і cid.

Буфер повинен задовольняти обидва обмеження: він не повинен перевищувати MTU віддаленого (peer) пристрою і не повинен перевищувати подвійний локальний MTU.

Це поверне False, якщо канал зараз «заблокований», що означає, що l2cap_send не можна викликати знову, поки не буде отримана подія _IRQ_L2CAP_SEND_READY (яка відбудеться, коли віддалений пристрій надасть більше кредитів, зазвичай після отримання та обробки даних).

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

Прийняти дані з вказаного conn_handle і cid у наданий buf (що має підтримувати буферний протокол, наприклад bytearray або memoryview).

Повертає кількість байт, прочитаних із каналу.

Якщо buf дорівнює None, повертає кількість доступних байт.

Примітка: Після отримання події _IRQ_L2CAP_RECV застосунок повинен продовжувати викликати l2cap_recvinto до тих пір, поки у буфері прийому не залишиться жодного байта (зазвичай до розміру MTU віддаленого (peer) пристрою).

Поки буфер прийому не порожній, віддаленому пристрою не будуть надані додаткові кредити каналу і він не зможе надіслати більше даних.

Сполучення та зв’язування

Сполучення дозволяє шифрувати та автентифікувати з’єднання за допомогою обміну секретами (з необов’язковим захистом від MITM за допомогою автентифікації паролем).

Зв’язування — це процес збереження цих секретів у незмінному сховищі. При зв’язуванні пристрій може розпізнати приватну адресу, що можна розпізнати (RPA), іншого пристрою на основі збереженого ключа розпізнавання ідентичності (IRK). Для підтримки зв’язування застосунок повинен реалізувати події _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

Відповісти на подію _IRQ_PASSKEY_ACTION для вказаних conn_handle і action. Значення passkey залежить від action (що, своєю чергою, залежить від налаштованих можливостей вводу/виводу):

Дія

Потрібна відповідь passkey

_PASSKEY_ACTION_INPUT

Пароль, який користувач зчитує з віддаленого пристрою.

_PASSKEY_ACTION_DISPLAY

Локально згенерований випадковий 6-значний пароль, показаний користувачу.

_PASSKEY_ACTION_NUMERIC_COMPARISON

1 для прийняття пароля, показаного в події _IRQ_PASSKEY_ACTION, або 0 для скасування сполучення.

клас UUID

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

Створює екземпляр UUID із вказаним value. 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 зазвичай визначаються виробниками.