bluetooth — niskopoziomowa obsługa Bluetooth

Ten moduł zapewnia interfejs do wbudowanego kontrolera Bluetooth. Obsługuje Bluetooth Low Energy (BLE) w rolach Central, Peripheral, Broadcaster i Observer, a także serwer i klient GATT oraz kanały L2CAP zorientowane na połączenie. Urządzenie może jednocześnie działać w wielu rolach. Obsługiwane są również parowanie i wiązanie (bonding).

To API ma odzwierciedlać niskopoziomowy protokół Bluetooth i dostarczać elementów składowych dla abstrakcji wyższego poziomu, takich jak konkretne typy urządzeń.

Wskazówka

W przypadku większości zastosowań preferuj bibliotekę wyższego poziomu aioble, która zapewnia opartą na asyncio nakładkę na ten moduł. Zobacz aioble — Asynchroniczne BLE.

class BLE

class bluetooth.BLE

Zwraca singletonowy obiekt BLE.

Konfiguracja

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

Opcjonalnie zmienia stan aktywności radia BLE i zwraca jego bieżący stan.

Radio musi zostać aktywowane przed użyciem jakichkolwiek innych metod tej klasy.

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

Pobiera lub ustawia wartości konfiguracyjne interfejsu BLE. Aby pobrać wartość, nazwa parametru powinna zostać podana jako łańcuch znaków w cudzysłowie i w danej chwili odpytywany jest tylko jeden parametr. Aby ustawić wartości, użyj składni z argumentami nazwanymi; jednocześnie można ustawić jeden lub więcej parametrów.

Obecnie obsługiwane są następujące wartości:

  • 'mac': Bieżący adres w użyciu, zależny od aktualnego trybu adresowania. Zwraca krotkę (addr_type, addr).

    Szczegóły dotyczące typu adresu znajdziesz w gap_scan.

    Można to odpytać tylko wtedy, gdy interfejs jest aktualnie aktywny.

  • 'addr_mode': Ustawia tryb adresowania. Dostępne wartości to:

    Wartość

    Nazwa

    Zachowanie

    0x00

    PUBLIC

    Użyj publicznego adresu kontrolera.

    0x01

    RANDOM

    Użyj wygenerowanego adresu statycznego.

    0x02

    RPA

    Użyj rozwiązywalnych adresów prywatnych.

    0x03

    NRPA

    Użyj nierozwiązywalnych adresów prywatnych.

    Domyślnie interfejs będzie używał adresu PUBLIC, jeśli jest dostępny, w przeciwnym razie użyje adresu RANDOM.

  • 'gap_name': Pobiera/ustawia nazwę urządzenia GAP używaną przez usługę Generic Access (UUID 0x1800), charakterystykę Device Name (UUID 0x2a00). Można ją ustawić w dowolnym momencie i zmieniać wielokrotnie.

  • 'rxbuf': Pobiera/ustawia rozmiar w bajtach wewnętrznego bufora używanego do przechowywania przychodzących zdarzeń. Bufor ten jest globalny dla całego sterownika BLE i dlatego obsługuje dane przychodzące dla wszystkich zdarzeń, w tym wszystkich charakterystyk. Zwiększenie go pozwala lepiej obsługiwać gwałtowne napływy danych przychodzących (na przykład wyniki skanowania) oraz umożliwia odbieranie większych wartości charakterystyk.

  • 'mtu': Pobiera/ustawia MTU, które będzie używane podczas wymiany ATT MTU. Wynikowe MTU będzie minimum z tej wartości i MTU urządzenia zdalnego. Wymiana ATT MTU nie nastąpi automatycznie (chyba że zainicjuje ją urządzenie zdalne) i musi zostać ręcznie zainicjowana za pomocą gattc_exchange_mtu. Użyj zdarzenia _IRQ_MTU_EXCHANGED, aby poznać MTU dla danego połączenia.

  • 'bond': Ustawia, czy wiązanie będzie włączone podczas parowania. Po włączeniu żądania parowania ustawią flagę „bond”, a klucze będą przechowywane przez oba urządzenia.

  • 'mitm': Ustawia, czy do parowania wymagana jest ochrona MITM.

  • 'io': Ustawia możliwości wejścia/wyjścia tego urządzenia.

    Dostępne opcje to:

    Stała

    Wartość

    Możliwość

    _IO_CAPABILITY_DISPLAY_ONLY

    0

    Tylko wyświetlanie

    _IO_CAPABILITY_DISPLAY_YESNO

    1

    Wyświetlanie z wejściem tak/nie

    _IO_CAPABILITY_KEYBOARD_ONLY

    2

    Tylko klawiatura

    _IO_CAPABILITY_NO_INPUT_OUTPUT

    3

    Brak wejścia ani wyjścia

    _IO_CAPABILITY_KEYBOARD_DISPLAY

    4

    Klawiatura i wyświetlacz

  • 'le_secure': Ustawia, czy wymagane jest parowanie „LE Secure”. Domyślnie jest to false (tzn. zezwala na „Legacy Pairing”).

Obsługa zdarzeń

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

Rejestruje wywołanie zwrotne dla zdarzeń ze stosu BLE. handler przyjmuje dwa argumenty: event (który będzie jednym z poniższych kodów) oraz data (który jest krotką wartości specyficzną dla zdarzenia).

Uwaga: W ramach optymalizacji zapobiegającej niepotrzebnym alokacjom wpisy addr, adv_data, char_data, notify_data oraz uuid w krotkach są instancjami memoryview tylko do odczytu wskazującymi na wewnętrzny bufor pierścieniowy modułu bluetooth i są ważne tylko podczas wywołania funkcji obsługi IRQ. Jeśli program musi zapisać jedną z tych wartości, aby uzyskać do niej dostęp po powrocie z funkcji obsługi IRQ (np. zapisując ją w instancji klasy lub zmiennej globalnej), musi wykonać kopię danych, używając bytes() lub bluetooth.UUID(), w ten sposób:

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

Na przykład funkcja obsługi IRQ dla wyniku skanowania mogłaby sprawdzić adv_data, aby zdecydować, czy jest to właściwe urządzenie, i dopiero wtedy skopiować dane adresowe do użycia w innym miejscu programu. Aby wydrukować dane wewnątrz funkcji obsługi IRQ, potrzebne będzie print(bytes(addr)).

Funkcja obsługi zazwyczaj rozdziela działanie na podstawie kodu zdarzenia i rozpakowuje krotkę ładunku specyficzną dla zdarzenia:

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
        ...

Każdy kod zdarzenia, dostarczany przez nie ładunek oraz krótki opis wymieniono poniżej. W przypadku zdarzeń, w których wspomniane jest pole status, status ma wartość 0 w razie powodzenia i specyficzną dla implementacji wartość niezerową w razie niepowodzenia.

Stała

Wartość

Zdarzenie

Krotka ładunku

_IRQ_CENTRAL_CONNECT

1

Urządzenie central połączyło się z tym urządzeniem peripheral.

(conn_handle, addr_type, addr)

_IRQ_CENTRAL_DISCONNECT

2

Urządzenie central rozłączyło się z tym urządzeniem peripheral.

(conn_handle, addr_type, addr)

_IRQ_GATTS_WRITE

3

Połączony klient zapisał wartość do lokalnej charakterystyki lub deskryptora. Użyj gatts_read, aby pobrać nową wartość.

(conn_handle, attr_handle)

_IRQ_GATTS_READ_REQUEST

4

Połączony klient wysłał żądanie odczytu. Zwróć niezerowy kod błędu z poniższej tabeli, aby odmówić odczytu, lub 0 / None, aby go zaakceptować.

(conn_handle, attr_handle)

_IRQ_SCAN_RESULT

5

Podczas aktywnego skanowania odebrano pojedynczy pakiet rozgłoszeniowy.

(addr_type, addr, adv_type, rssi, adv_data)

_IRQ_SCAN_DONE

6

Bieżące skanowanie zakończyło się, albo z powodu upłynięcia skonfigurowanego czasu trwania, albo dlatego, że wywołano gap_scan(None).

()

_IRQ_PERIPHERAL_CONNECT

7

Wcześniej wysłane gap_connect powiodło się.

(conn_handle, addr_type, addr)

_IRQ_PERIPHERAL_DISCONNECT

8

Połączone urządzenie peripheral rozłączyło się.

(conn_handle, addr_type, addr)

_IRQ_GATTC_SERVICE_RESULT

9

Metoda gattc_discover_services znalazła jedną usługę.

(conn_handle, start_handle, end_handle, uuid)

_IRQ_GATTC_SERVICE_DONE

10

Wykrywanie usług zostało zakończone.

(conn_handle, status)

_IRQ_GATTC_CHARACTERISTIC_RESULT

11

Metoda gattc_discover_characteristics znalazła jedną charakterystykę.

(conn_handle, end_handle, value_handle, properties, uuid)

_IRQ_GATTC_CHARACTERISTIC_DONE

12

Wykrywanie charakterystyk zostało zakończone.

(conn_handle, status)

_IRQ_GATTC_DESCRIPTOR_RESULT

13

Metoda gattc_discover_descriptors znalazła jeden deskryptor.

(conn_handle, dsc_handle, uuid)

_IRQ_GATTC_DESCRIPTOR_DONE

14

Wykrywanie deskryptorów zostało zakończone.

(conn_handle, status)

_IRQ_GATTC_READ_RESULT

15

Wcześniej wysłane gattc_read zwróciło dane.

(conn_handle, value_handle, char_data)

_IRQ_GATTC_READ_DONE

16

Wcześniej wysłane gattc_read zostało zakończone.

(conn_handle, value_handle, status)

_IRQ_GATTC_WRITE_DONE

17

Wcześniej wysłane gattc_write zostało potwierdzone.

(conn_handle, value_handle, status)

_IRQ_GATTC_NOTIFY

18

Zdalny serwer wysłał (niepotwierdzone) powiadomienie.

(conn_handle, value_handle, notify_data)

_IRQ_GATTC_INDICATE

19

Zdalny serwer wysłał (potwierdzone) wskazanie.

(conn_handle, value_handle, notify_data)

_IRQ_GATTS_INDICATE_DONE

20

Wcześniej wysłane wskazanie zostało potwierdzone przez klienta (lub upłynął jego limit czasu).

(conn_handle, value_handle, status)

_IRQ_MTU_EXCHANGED

21

Wymiana ATT MTU została zakończona (zainicjowana przez którąkolwiek ze stron).

(conn_handle, mtu)

_IRQ_L2CAP_ACCEPT

22

Urządzenie zdalne zażądało połączenia L2CAP na PSM, na którym to urządzenie nasłuchuje. Zwróć niezerową liczbę całkowitą, aby odrzucić, lub 0 / None, aby zaakceptować.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_CONNECT

23

Kanał L2CAP został teraz ustanowiony, albo przez zaakceptowanie przychodzącego żądania, albo przez zakończenie wychodzącego l2cap_connect.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_DISCONNECT

24

Kanał L2CAP został rozłączony. status ma wartość 0 w przypadku czystego rozłączenia lub wartość niezerową, jeśli próba połączenia wychodzącego nie powiodła się.

(conn_handle, cid, psm, status)

_IRQ_L2CAP_RECV

25

Na kanale L2CAP nadeszły dane. Wywołaj l2cap_recvinto, aby je odczytać.

(conn_handle, cid)

_IRQ_L2CAP_SEND_READY

26

Wcześniejsze l2cap_send, które zwróciło False, opróżniło się i kanał jest ponownie gotowy. Niezerowy status oznacza, że bufor nadawczy się przepełnił i aplikacja musi ponownie wysłać dane.

(conn_handle, cid, status)

_IRQ_CONNECTION_UPDATE

27

Urządzenie zdalne zaktualizowało parametry połączenia (interwał, latency, supervision timeout).

(conn_handle, conn_interval, conn_latency, supervision_timeout, status)

_IRQ_ENCRYPTION_UPDATE

28

Stan szyfrowania połączenia uległ zmianie, zazwyczaj po zakończeniu parowania lub wiązania.

(conn_handle, encrypted, authenticated, bonded, key_size)

_IRQ_GET_SECRET

29

Stos żąda przechowywanego sekretu wiązania. Jeśli key ma wartość None, zwróć index-tą przechowywaną wartość typu sec_type; w przeciwnym razie zwróć wartość powiązaną z podanym (sec_type, key). Zwróć None, jeśli nic nie jest przechowywane.

(sec_type, index, key)

_IRQ_SET_SECRET

30

Stos prosi aplikację o trwałe zapisanie sekretu wiązania. Zwróć True po zapisaniu.

(sec_type, key, value)

_IRQ_PASSKEY_ACTION

31

W ramach parowania wymagana jest akcja związana z passkey. Odpowiedz, używając gap_passkey; możliwe akcje znajdziesz w poniższej tabeli akcji passkey.

(conn_handle, action, passkey)

Dla zdarzenia _IRQ_GATTS_READ_REQUEST dostępne kody zwrotne to:

Stała

Wartość

Znaczenie

_GATTS_NO_ERROR

0x00

Zaakceptuj odczyt.

_GATTS_ERROR_READ_NOT_PERMITTED

0x02

Odczyt niedozwolony.

_GATTS_ERROR_WRITE_NOT_PERMITTED

0x03

Zapis niedozwolony.

_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION

0x05

Klient nie jest uwierzytelniony.

_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION

0x08

Klient nie jest autoryzowany.

_GATTS_ERROR_INSUFFICIENT_ENCRYPTION

0x0f

Łącze nie jest szyfrowane.

Dla zdarzenia _IRQ_PASSKEY_ACTION dostępne akcje to:

Stała

Wartość

Znaczenie

_PASSKEY_ACTION_NONE

0

Nie jest wymagana żadna akcja.

_PASSKEY_ACTION_INPUT

2

Poproś użytkownika o wprowadzenie passkey wyświetlonego na urządzeniu zdalnym.

_PASSKEY_ACTION_DISPLAY

3

Wyświetl 6-cyfrowy passkey, który ma zostać wprowadzony na urządzeniu zdalnym.

_PASSKEY_ACTION_NUMERIC_COMPARISON

4

Potwierdź, że passkey jest zgodny z tym wyświetlonym na urządzeniu zdalnym.

Aby zaoszczędzić miejsce w oprogramowaniu układowym, te stałe nie są dołączone do modułu bluetooth. Dodaj do swojego programu te z powyższych list, których potrzebujesz.

Rola Broadcaster (Advertiser)

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

Rozpoczyna rozgłaszanie w określonym interwale (w mikrosekundach). Interwał ten zostanie zaokrąglony w dół do najbliższych 625us. Aby zatrzymać rozgłaszanie, ustaw interval_us na None.

adv_data i resp_data mogą być dowolnym typem implementującym protokół buforowy (np. bytes, bytearray, str). adv_data jest zawarte we wszystkich rozgłoszeniach, a resp_data jest wysyłane w odpowiedzi na aktywne skanowanie.

Uwaga: jeśli adv_data (lub resp_data) ma wartość None, to ponownie użyte zostaną dane przekazane w poprzednim wywołaniu gap_advertise. Pozwala to rozgłaszaczowi wznowić rozgłaszanie za pomocą samego gap_advertise(interval_us). Aby wyczyścić ładunek rozgłoszeniowy, przekaż pusty bytes, tzn. b''.

Rola Observer (Scanner)

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

Uruchamia operację skanowania trwającą przez określony czas (w milisekundach).

Aby skanować w nieskończoność, ustaw duration_ms na 0.

Aby zatrzymać skanowanie, ustaw duration_ms na None.

Użyj interval_us i window_us, aby opcjonalnie skonfigurować cykl pracy. Skaner będzie działał przez window_us mikrosekund co interval_us mikrosekund przez łącznie duration_ms milisekund. Domyślny interwał i okno wynoszą odpowiednio 1,28 sekundy oraz 11,25 milisekundy (skanowanie w tle).

Dla każdego wyniku skanowania zgłaszane będzie zdarzenie _IRQ_SCAN_RESULT z danymi zdarzenia (addr_type, addr, adv_type, rssi, adv_data).

Wartości addr_type wskazują adresy publiczne lub losowe:

Wartość

Nazwa

Znaczenie

0x00

PUBLIC

Publiczny adres urządzenia.

0x01

RANDOM

Adres losowy (statyczny, RPA lub NRPA; typ jest zakodowany w samym adresie).

Wartości adv_type odpowiadają specyfikacji Bluetooth:

Wartość

Nazwa

Znaczenie

0x00

ADV_IND

Rozgłaszanie bezkierunkowe, umożliwiające połączenie i skanowanie.

0x01

ADV_DIRECT_IND

Rozgłaszanie kierunkowe, umożliwiające połączenie.

0x02

ADV_SCAN_IND

Rozgłaszanie bezkierunkowe, umożliwiające skanowanie.

0x03

ADV_NONCONN_IND

Rozgłaszanie bezkierunkowe, nieumożliwiające połączenia.

0x04

SCAN_RSP

Odpowiedź na skanowanie.

active można ustawić na True, jeśli chcesz otrzymywać odpowiedzi na skanowanie w wynikach.

Gdy skanowanie zostanie zatrzymane (z powodu upłynięcia czasu trwania lub jawnego zatrzymania), zgłoszone zostanie zdarzenie _IRQ_SCAN_DONE.

Rola Central

Urządzenie central może łączyć się z urządzeniami peripheral, które wykryło, korzystając z roli observer (zobacz gap_scan), lub o znanym adresie.

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

Łączy się z urządzeniem peripheral.

Szczegóły dotyczące typów adresów znajdziesz w gap_scan.

Aby wcześnie anulować trwającą próbę połączenia, wywołaj gap_connect(None).

W razie powodzenia zgłoszone zostanie zdarzenie _IRQ_PERIPHERAL_CONNECT. W przypadku anulowania próby połączenia zgłoszone zostanie zdarzenie _IRQ_PERIPHERAL_DISCONNECT.

Urządzenie będzie czekać maksymalnie scan_duration_ms na odebranie ładunku rozgłoszeniowego od urządzenia.

Interwał połączenia można skonfigurować w mikrosekundach, używając jednego lub obu parametrów min_conn_interval_us i max_conn_interval_us. W przeciwnym razie zostanie wybrany domyślny interwał, zazwyczaj między 30000 a 50000 mikrosekund. Krótszy interwał zwiększy przepustowość kosztem zużycia energii.

Rola Peripheral

Oczekuje się, że urządzenie peripheral będzie wysyłać rozgłoszenia umożliwiające połączenie (zobacz gap_advertise). Zazwyczaj będzie ono działać jako serwer GATT, po wcześniejszym zarejestrowaniu usług i charakterystyk za pomocą gatts_register_services.

Gdy urządzenie central się połączy, zgłoszone zostanie zdarzenie _IRQ_CENTRAL_CONNECT.

Role Central i Peripheral

gap_disconnect(conn_handle: int, /) bool

Rozłącza określony uchwyt połączenia. Może to być albo urządzenie central, które połączyło się z tym urządzeniem (jeśli działa ono jako peripheral), albo urządzenie peripheral, z którym to urządzenie wcześniej się połączyło (jeśli działa ono jako central).

W razie powodzenia zgłoszone zostanie zdarzenie _IRQ_PERIPHERAL_DISCONNECT lub _IRQ_CENTRAL_DISCONNECT.

Zwraca False, jeśli uchwyt połączenia nie był połączony, a True w przeciwnym razie.

Serwer GATT

Serwer GATT ma zestaw zarejestrowanych usług. Każda usługa może zawierać charakterystyki, z których każda ma wartość. Charakterystyki mogą również zawierać deskryptory, które same mają wartości.

Wartości te są przechowywane lokalnie i są dostępne przez ich „value handle”, który jest generowany podczas rejestracji usługi. Mogą być również odczytywane lub zapisywane przez zdalne urządzenie klienckie. Dodatkowo serwer może „powiadomić” o charakterystyce połączonego klienta za pomocą uchwytu połączenia.

Urządzenie w roli central lub peripheral może funkcjonować jako serwer GATT, jednak w większości przypadków częściej to urządzenie peripheral będzie działać jako serwer.

Charakterystyki i deskryptory mają domyślny maksymalny rozmiar 20 bajtów (domyślne ATT MTU wynoszące 23 bajty minus 3-bajtowy nagłówek ATT; większe wynegocjowane MTU samo w sobie nie podnosi tego limitu). Wszystko, co klient do nich zapisze, zostanie obcięte do tej długości. Jednak każdy lokalny zapis zwiększy maksymalny rozmiar, więc jeśli chcesz zezwolić na większe zapisy od klienta do danej charakterystyki, użyj gatts_write po rejestracji. Np. gatts_write(char_handle, bytes(100)).

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

Konfiguruje serwer z określonymi usługami, zastępując wszelkie istniejące usługi.

services_definition jest listą usług, gdzie każda usługa jest dwuelementową krotką zawierającą UUID oraz listę charakterystyk.

Każda charakterystyka jest dwu- lub trzyelementową krotką zawierającą UUID, wartość flags oraz opcjonalnie listę deskryptorów.

Każdy deskryptor jest dwuelementową krotką zawierającą UUID oraz wartość flags.

flags są kombinacją bitową OR flag zdefiniowanych poniżej. Ustawiają one zarówno zachowanie charakterystyki (lub deskryptora), jak i wymagania dotyczące bezpieczeństwa i prywatności.

Wartością zwracaną jest lista (po jednym elemencie na usługę) krotek (każdy element jest uchwytem wartości). Uchwyty charakterystyk i deskryptorów są spłaszczone do tej samej krotki, w kolejności, w jakiej zostały zdefiniowane.

Poniższy przykład rejestruje dwie usługi (Heart Rate oraz 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),
)

Trzy uchwyty wartości (hr, tx, rx) mogą być używane z gatts_read, gatts_write, gatts_notify oraz gatts_indicate.

Uwaga: Rozgłaszanie musi zostać zatrzymane przed zarejestrowaniem usług.

Dostępne flagi dla charakterystyk i deskryptorów to:

Stała

Wartość

Znaczenie

_FLAG_BROADCAST

0x0001

Charakterystyka może być rozgłaszana.

_FLAG_READ

0x0002

Klient może odczytać wartość.

_FLAG_WRITE_NO_RESPONSE

0x0004

Klient może zapisywać bez oczekiwania na odpowiedź.

_FLAG_WRITE

0x0008

Klient może zapisywać z potwierdzoną odpowiedzią.

_FLAG_NOTIFY

0x0010

Serwer może wysyłać powiadomienia (niepotwierdzone).

_FLAG_INDICATE

0x0020

Serwer może wysyłać wskazania (potwierdzone).

_FLAG_AUTHENTICATED_SIGNED_WRITE

0x0040

Klient może wysyłać podpisane zapisy.

_FLAG_AUX_WRITE

0x0100

Rozszerzone właściwości: dozwolone są zapisy kolejkowane/niezawodne.

_FLAG_READ_ENCRYPTED

0x0200

Odczyt wymaga szyfrowanego łącza.

_FLAG_READ_AUTHENTICATED

0x0400

Odczyt wymaga uwierzytelnionego (chronionego MITM) łącza.

_FLAG_READ_AUTHORIZED

0x0800

Odczyt wymaga autoryzacji na poziomie aplikacji.

_FLAG_WRITE_ENCRYPTED

0x1000

Zapis wymaga szyfrowanego łącza.

_FLAG_WRITE_AUTHENTICATED

0x2000

Zapis wymaga uwierzytelnionego (chronionego MITM) łącza.

_FLAG_WRITE_AUTHORIZED

0x4000

Zapis wymaga autoryzacji na poziomie aplikacji.

Podobnie jak w przypadku powyższych stałych zdarzeń, flagi te nie są dostarczane przez moduł bluetooth; skopiuj do swojego programu te, których potrzebujesz.

gatts_read(value_handle: int, /) bytes

Odczytuje lokalną wartość dla tego uchwytu (która została zapisana albo przez gatts_write, albo przez zdalnego klienta).

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

Zapisuje lokalną wartość dla tego uchwytu, którą może odczytać klient.

Jeśli send_update ma wartość True, to wszyscy subskrybujący klienci zostaną powiadomieni (lub otrzymają wskazanie, w zależności od tego, co subskrybują i które operacje obsługuje charakterystyka) o tym zapisie.

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

Wysyła żądanie powiadomienia do połączonego klienta.

Jeśli data ma wartość None (domyślnie), to wysłana zostanie bieżąca lokalna wartość (ustawiona za pomocą gatts_write).

W przeciwnym razie, jeśli data nie ma wartości None, to wartość ta zostanie wysłana do klienta jako część powiadomienia. Lokalna wartość nie zostanie zmodyfikowana.

Uwaga: Powiadomienie zostanie wysłane niezależnie od statusu subskrypcji klienta dla tej charakterystyki.

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

Wysyła żądanie wskazania do połączonego klienta.

Jeśli data ma wartość None (domyślnie), to wysłana zostanie bieżąca lokalna wartość (ustawiona za pomocą gatts_write).

W przeciwnym razie, jeśli data nie ma wartości None, to wartość ta zostanie wysłana do klienta jako część wskazania. Lokalna wartość nie zostanie zmodyfikowana.

Po potwierdzeniu (lub niepowodzeniu, np. przekroczeniu limitu czasu) zgłoszone zostanie zdarzenie _IRQ_GATTS_INDICATE_DONE.

Uwaga: Wskazanie zostanie wysłane niezależnie od statusu subskrypcji klienta dla tej charakterystyki.

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

Ustawia rozmiar wewnętrznego bufora dla wartości w bajtach. Ograniczy to największy możliwy zapis, który może zostać odebrany. Domyślnie jest to 20 bajtów (domyślne ATT MTU wynoszące 23 minus 3-bajtowy nagłówek ATT).

Ustawienie append na True spowoduje, że wszystkie zdalne zapisy będą dołączane do bieżącej wartości, a nie ją zastępować. W ten sposób można zbuforować maksymalnie len bajtów. Gdy użyjesz gatts_read, wartość zostanie wyczyszczona po odczycie. Funkcja ta jest przydatna przy implementowaniu czegoś takiego jak Nordic UART Service.

Klient GATT

Klient GATT może wykrywać oraz odczytywać/zapisywać charakterystyki na zdalnym serwerze GATT.

Częściej to urządzenie w roli central działa jako klient GATT, jednak możliwe jest również, aby urządzenie peripheral działało jako klient w celu wykrycia informacji o urządzeniu central, które się z nim połączyło (np. aby odczytać nazwę urządzenia z usługi informacji o urządzeniu).

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

Odpytuje połączony serwer o jego usługi.

Opcjonalnie podaj uuid usługi, aby odpytać tylko o tę usługę.

Dla każdej wykrytej usługi zgłoszone zostanie zdarzenie _IRQ_GATTC_SERVICE_RESULT, a po zakończeniu zdarzenie _IRQ_GATTC_SERVICE_DONE.

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

Odpytuje połączony serwer o charakterystyki w określonym zakresie.

Opcjonalnie podaj uuid charakterystyki, aby odpytać tylko o tę charakterystykę.

Przekazanie start_handle=1 oraz end_handle=0xffff obejmuje pełny zakres uchwytów atrybutów GATT, więc ta kombinacja skutecznie przeszukuje każdą usługę na urządzeniu zdalnym.

Dla każdej wykrytej charakterystyki zgłoszone zostanie zdarzenie _IRQ_GATTC_CHARACTERISTIC_RESULT, a po zakończeniu zdarzenie _IRQ_GATTC_CHARACTERISTIC_DONE.

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

Odpytuje połączony serwer o deskryptory w określonym zakresie.

Dla każdego wykrytego deskryptora zgłoszone zostanie zdarzenie _IRQ_GATTC_DESCRIPTOR_RESULT, a po zakończeniu zdarzenie _IRQ_GATTC_DESCRIPTOR_DONE.

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

Wysyła zdalny odczyt do połączonego serwera dla określonego uchwytu charakterystyki lub deskryptora.

Gdy wartość będzie dostępna, zgłoszone zostanie zdarzenie _IRQ_GATTC_READ_RESULT, a po zakończeniu zdarzenie _IRQ_GATTC_READ_DONE.

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

Wysyła zdalny zapis do połączonego serwera dla określonego uchwytu charakterystyki lub deskryptora.

Argument mode określa zachowanie zapisu, a obecnie obsługiwane wartości to:

  • mode=0 (domyślnie) to zapis bez odpowiedzi: zapis zostanie wysłany do zdalnego serwera, ale nie zostanie zwrócone żadne potwierdzenie ani zgłoszone żadne zdarzenie.

  • mode=1 to zapis z odpowiedzią: zdalny serwer jest proszony o wysłanie odpowiedzi/potwierdzenia, że otrzymał dane.

Jeśli od zdalnego serwera zostanie odebrana odpowiedź, zgłoszone zostanie zdarzenie _IRQ_GATTC_WRITE_DONE.

gattc_exchange_mtu(conn_handle: int, /) None

Inicjuje wymianę MTU z połączonym serwerem, używając preferowanego MTU ustawionego za pomocą BLE.config(mtu=value).

Zdarzenie _IRQ_MTU_EXCHANGED zostanie zgłoszone po zakończeniu wymiany MTU.

Wymiana MTU jest zazwyczaj inicjowana przez urządzenie central; NimBLE obsługuje obie role.

Kanały L2CAP zorientowane na połączenie

Funkcja ta umożliwia wymianę danych podobną do gniazd (socket) między dwoma urządzeniami BLE. Po połączeniu urządzeń przez GAP każde z nich może nasłuchiwać, aż drugie połączy się na numerycznym PSM (Protocol/Service Multiplexer).

W danej chwili aktywny może być tylko jeden kanał L2CAP (tzn. nie można się połączyć podczas nasłuchiwania).

Aktywne kanały L2CAP są identyfikowane przez uchwyt połączenia, na którym zostały ustanowione, oraz przez CID (channel ID).

Kanały zorientowane na połączenie mają wbudowaną kontrolę przepływu opartą na kredytach. W przeciwieństwie do ATT, gdzie urządzenia negocjują wspólne MTU, zarówno urządzenie nasłuchujące, jak i łączące się ustawiają niezależne MTU, które ogranicza maksymalną ilość zaległych danych, jakie urządzenie zdalne może wysłać, zanim zostaną one w pełni odebrane w l2cap_recvinto.

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

Rozpoczyna nasłuchiwanie przychodzących żądań kanału L2CAP na określonym psm z lokalnym MTU ustawionym na mtu.

Gdy urządzenie zdalne zainicjuje połączenie, zgłoszone zostanie zdarzenie _IRQ_L2CAP_ACCEPT, które daje nasłuchującemu serwerowi szansę na odrzucenie przychodzącego połączenia (poprzez zwrócenie niezerowej liczby całkowitej).

Po zaakceptowaniu połączenia zgłoszone zostanie zdarzenie _IRQ_L2CAP_CONNECT, umożliwiające serwerowi uzyskanie channel ID (CID) oraz lokalnego i zdalnego MTU.

Uwaga: Obecnie nie jest możliwe zatrzymanie nasłuchiwania.

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

Łączy się z nasłuchującym partnerem na określonym psm z lokalnym MTU ustawionym na mtu.

Po pomyślnym połączeniu zgłoszone zostanie zdarzenie _IRQ_L2CAP_CONNECT, umożliwiające klientowi uzyskanie CID oraz lokalnego i zdalnego (peer) MTU.

Nieudane połączenie zgłosi zdarzenie _IRQ_L2CAP_DISCONNECT z niezerowym statusem.

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

Rozłącza aktywny kanał L2CAP o określonym conn_handle i cid.

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

Wysyła określony buf (który musi obsługiwać protokół buforowy) na kanale L2CAP identyfikowanym przez conn_handle i cid.

Bufor musi spełniać oba ograniczenia: nie może przekraczać zdalnego (peer) MTU ani nie może przekraczać dwukrotności lokalnego MTU.

Zwróci to False, jeśli kanał jest teraz „zatrzymany”, co oznacza, że l2cap_send nie może zostać ponownie wywołane, dopóki nie zostanie odebrane zdarzenie _IRQ_L2CAP_SEND_READY (co nastąpi, gdy urządzenie zdalne przyzna więcej kredytów, zazwyczaj po odebraniu i przetworzeniu danych).

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

Odbiera dane z określonego conn_handle i cid do podanego buf (który musi obsługiwać protokół buforowy, np. bytearray lub memoryview).

Zwraca liczbę bajtów odczytanych z kanału.

Jeśli buf ma wartość None, to zwraca liczbę dostępnych bajtów.

Uwaga: Po odebraniu zdarzenia _IRQ_L2CAP_RECV aplikacja powinna kontynuować wywoływanie l2cap_recvinto, dopóki w buforze odbiorczym nie będzie już dostępnych żadnych bajtów (zazwyczaj do rozmiaru zdalnego (peer) MTU).

Dopóki bufor odbiorczy nie zostanie opróżniony, urządzeniu zdalnemu nie zostaną przyznane kolejne kredyty kanału i nie będzie ono mogło wysłać już żadnych danych.

Parowanie i wiązanie (Bonding)

Parowanie pozwala na szyfrowanie i uwierzytelnianie połączenia poprzez wymianę sekretów (z opcjonalną ochroną MITM za pomocą uwierzytelniania passkey).

Wiązanie to proces zapisywania tych sekretów w pamięci nieulotnej. Po związaniu urządzenie jest w stanie rozwiązać rozwiązywalny adres prywatny (RPA) innego urządzenia na podstawie przechowywanego klucza rozwiązywania tożsamości (IRK). Aby obsługiwać wiązanie, aplikacja musi zaimplementować zdarzenia _IRQ_GET_SECRET oraz _IRQ_SET_SECRET.

gap_pair(conn_handle: int, /) None

Inicjuje parowanie z urządzeniem zdalnym.

Przed wywołaniem tej metody upewnij się, że opcje konfiguracyjne io, mitm, le_secure oraz bond są ustawione (za pomocą config).

Po pomyślnym parowaniu zgłoszone zostanie zdarzenie _IRQ_ENCRYPTION_UPDATE.

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

Odpowiada na zdarzenie _IRQ_PASSKEY_ACTION dla określonego conn_handle i action. Znaczenie passkey zależy od action (które z kolei zależy od skonfigurowanej możliwości wejścia/wyjścia):

Akcja

Wymagana odpowiedź passkey

_PASSKEY_ACTION_INPUT

Passkey, który użytkownik odczytuje z urządzenia zdalnego.

_PASSKEY_ACTION_DISPLAY

Wygenerowany lokalnie losowy 6-cyfrowy passkey pokazany użytkownikowi.

_PASSKEY_ACTION_NUMERIC_COMPARISON

1, aby zaakceptować passkey pokazany w zdarzeniu _IRQ_PASSKEY_ACTION, lub 0, aby anulować parowanie.

class UUID

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

Tworzy instancję UUID o określonej wartości value. Bluetooth używa trzech szerokości UUID; UUID akceptuje każdą z nich:

Szerokość UUID

Akceptowane typy value

Przykład

16-bitowy

int lub 2-bajtowy bufor (little-endian)

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

32-bitowy

4-bajtowy bufor (little-endian)

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

128-bitowy

16-bajtowy bufor lub łańcuch znaków z myślnikami

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

16- i 32-bitowe UUID są zazwyczaj identyfikatorami przydzielonymi przez SIG (zobacz przydzielone numery Bluetooth); 128-bitowe UUID są zwykle definiowane przez dostawcę.