ubluepy — периферийное и центральное устройство Bluetooth LE

Модуль ubluepy — это устаревший API Bluetooth LE, поставляемый с портом nRF MicroPython. Он нестрого смоделирован по образцу Python-библиотеки bluepy для Linux и располагается непосредственно поверх Nordic SoftDevice — переносимого бэкенда нет, поэтому модуль доступен только на платформах Nordic (в линейке OpenMV — это Arduino Nano 33 BLE Sense). Более новые API bluetooth / aioble в этой сборке не включены, так что 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 мс и декодировать рекламные данные каждой записи 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-битный UUID Bluetooth.

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

Возвращает младшие 16 бит UUID в виде int. Для 128-битных UUID возвращается только 16-битное поле, встроенное в специфичный для вендора UUID (полное 128-битное значение доступно только через специфичный для вендора индекс SoftDevice).

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

Определяет службу GATT, которая будет зарегистрирована в SoftDevice при добавлении к Peripheral.

uuid

Экземпляр UUID. Передача объекта, не являющегося UUID, вызывает ValueError.

type

Либо Service.PRIMARY (по умолчанию), либо Service.SECONDARY. Другие значения вызывают ValueError.

uuid() UUID

Возвращает экземпляр UUID службы.

addCharacteristic(characteristic: Characteristic) None

Регистрирует Characteristic в службе. Дескриптор GATT характеристики назначается во время этого вызова.

getCharacteristic(uuid: UUID) Characteristic | None

Ищет ранее добавленную Characteristic по UUID. Возвращает экземпляр характеристики или 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 с помощью Service.addCharacteristic() до того, как родительское Peripheral начнёт рекламную рассылку.

uuid

Экземпляр UUID.

props (только именованный)

Битовая маска из одного или нескольких значений Characteristic.PROP_*, описывающая, какие операции поддерживает характеристика.

attrs (только именованный)

Битовая маска дополнительных атрибутов GATT. Используйте Characteristic.ATTR_CCCD, чтобы прикрепить Client Characteristic Configuration Descriptor — это необходимо для работы характеристик 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 — любой объект, поддерживающий протокол буфера (bytes, bytearray, memoryview).

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

Добавляет к характеристике Client Characteristic Configuration Descriptor (0x01). Необходимо, чтобы клиенты могли подписываться на уведомления/индикации.

class ubluepy.Descriptor(uuid: UUID)

Класс-заглушка для представления дескрипторов GATT. Текущая реализация хранит только UUID и не предоставляет методов — он добавлен для совместимости с будущими версиями модуля.

class ubluepy.Peripheral

Локальное устройство Bluetooth LE. Один и тот же класс используется для ролей как периферийного, так и центрального устройства; роль выбирается тем, какие методы вы вызываете (advertise() выбирает периферийное устройство, connect() — центральное).

addService(service: Service) None

Регистрирует Service (и все ранее добавленные к ней характеристики) на локальном сервере GATT.

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_id — одно из значений constants.EVT_GAP_CONNECTED, constants.EVT_GAP_DISCONNECTED или constants.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_PUBLIC или constants.ADDR_TYPE_RANDOM_STATIC).

rssi() int

Возвращает индикатор уровня сигнала в дБм.

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

Значение event_id обработчика подключения Peripheral для подключения GAP (16).

constants.EVT_GAP_DISCONNECTED: int

Значение event_id обработчика подключения Peripheral для отключения GAP (17).

constants.EVT_GATTS_WRITE: int

Значение event_id обработчика подключения Peripheral для записи в локальный атрибут GATT, включая записи в CCCD, которые включают/отключают уведомления (80).

constants.UUID_CCCD: int

Стандартный UUID Bluetooth для Client Characteristic Configuration Descriptor (0x2902).

constants.ADDR_TYPE_PUBLIC: int

Публичный адрес устройства Bluetooth (0).

constants.ADDR_TYPE_RANDOM_STATIC: int

Статический случайный адрес устройства Bluetooth (1).

constants.ad_types: type

Пространство имён констант типов AD рекламных данных из Bluetooth Core Specification Supplement. Каждое имя соответствует своему 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