bluetooth — Bluetooth de baixo nível

Este módulo fornece uma interface para o controlador Bluetooth integrado. Ele oferece suporte a Bluetooth Low Energy (BLE) nos papéis Central, Periférico, Broadcaster e Observador, bem como Servidor e Cliente GATT e canais L2CAP orientados a conexão. Um dispositivo pode operar em vários papéis simultaneamente. O pareamento e o vínculo (bonding) também são suportados.

Esta API foi projetada para corresponder ao protocolo Bluetooth de baixo nível e fornecer blocos de construção para abstrações de nível mais alto, como tipos de dispositivos específicos.

Dica

Para a maioria das aplicações, prefira a biblioteca de nível mais alto aioble, que fornece um wrapper baseado em asyncio em torno deste módulo. Consulte aioble — BLE Assíncrono.

class BLE

class bluetooth.BLE

Retorna o objeto BLE singleton.

Configuração

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

Opcionalmente altera o estado ativo do rádio BLE e retorna o estado atual.

O rádio deve estar ativo antes de usar qualquer outro método desta classe.

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

Obtém ou define valores de configuração da interface BLE. Para obter um valor, o nome do parâmetro deve ser entre aspas como uma string, e apenas um parâmetro é consultado por vez. Para definir valores use a sintaxe de palavra-chave, e um ou mais parâmetros podem ser definidos por vez.

Os valores atualmente suportados são:

  • 'mac': O endereço atualmente em uso, dependendo do modo de endereço atual. Isso retorna uma tupla de (addr_type, addr).

    Consulte gap_scan para detalhes sobre o tipo de endereço.

    Isso só pode ser consultado enquanto a interface estiver atualmente ativa.

  • 'addr_mode': Define o modo de endereço. Os valores são:

    Valor

    Nome

    Comportamento

    0x00

    PUBLIC

    Usa o endereço público do controlador.

    0x01

    RANDOM

    Usa um endereço estático gerado.

    0x02

    RPA

    Usa endereços privados resolvíveis.

    0x03

    NRPA

    Usa endereços privados não resolvíveis.

    Por padrão, a interface usará um endereço PUBLIC se disponível; caso contrário, usará um endereço RANDOM.

  • 'gap_name': Obtém/define o nome do dispositivo GAP usado pelo serviço Generic Access (UUID 0x1800), característica Device Name (UUID 0x2a00). Isso pode ser definido a qualquer momento e alterado várias vezes.

  • 'rxbuf': Obtém/define o tamanho em bytes do buffer interno usado para armazenar eventos recebidos. Esse buffer é global para todo o driver BLE e, portanto, lida com os dados recebidos de todos os eventos, incluindo todas as características. Aumentá-lo permite um melhor tratamento de dados recebidos em rajadas (por exemplo, resultados de varredura) e a capacidade de receber valores de características maiores.

  • 'mtu': Obtém/define a MTU que será usada durante uma troca de MTU ATT. A MTU resultante será o mínimo entre esta e a MTU do dispositivo remoto. A troca de MTU ATT não acontecerá automaticamente (a menos que o dispositivo remoto a inicie) e deve ser iniciada manualmente com gattc_exchange_mtu. Use o evento _IRQ_MTU_EXCHANGED para descobrir a MTU de uma determinada conexão.

  • 'bond': Define se o vínculo (bonding) será habilitado durante o pareamento. Quando habilitado, as solicitações de pareamento definirão a flag “bond” e as chaves serão armazenadas por ambos os dispositivos.

  • 'mitm': Define se a proteção MITM é necessária para o pareamento.

  • 'io': Define as capacidades de E/S deste dispositivo.

    As opções disponíveis são:

    Constante

    Valor

    Capacidade

    _IO_CAPABILITY_DISPLAY_ONLY

    0

    Apenas exibição

    _IO_CAPABILITY_DISPLAY_YESNO

    1

    Exibição com entrada sim/não

    _IO_CAPABILITY_KEYBOARD_ONLY

    2

    Apenas teclado

    _IO_CAPABILITY_NO_INPUT_OUTPUT

    3

    Sem entrada ou saída

    _IO_CAPABILITY_KEYBOARD_DISPLAY

    4

    Teclado e exibição

  • 'le_secure': Define se o pareamento “LE Secure” é necessário. O padrão é false (ou seja, permite “Legacy Pairing”).

Tratamento de Eventos

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

Registra um callback para eventos da pilha BLE. O handler recebe dois argumentos, event (que será um dos códigos abaixo) e data (que é uma tupla de valores específica do evento).

Observação: Como otimização para evitar alocações desnecessárias, as entradas addr, adv_data, char_data, notify_data e uuid nas tuplas são instâncias de memoryview somente leitura que apontam para o ringbuffer interno do bluetooth e são válidas apenas durante a invocação da função de tratamento de IRQ. Se o seu programa precisar salvar um desses valores para acessá-lo depois que o tratador de IRQ retornar (por exemplo, salvando-o em uma instância de classe ou variável global), ele precisa fazer uma cópia dos dados, seja usando bytes() ou bluetooth.UUID(), assim:

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

Por exemplo, o tratador de IRQ para um resultado de varredura pode inspecionar o adv_data para decidir se é o dispositivo correto e só então copiar os dados de endereço para serem usados em outro lugar do programa. E para imprimir dados de dentro do tratador de IRQ, será necessário print(bytes(addr)).

Um tratador normalmente despacha com base no código do evento e desempacota a tupla de payload específica do evento:

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

Cada código de evento, o payload que ele entrega e uma breve descrição estão listados abaixo. Para eventos cujo campo status é mencionado, status é 0 em caso de sucesso e um valor não nulo específico da implementação em caso de falha.

Constante

Valor

Evento

Tupla de payload

_IRQ_CENTRAL_CONNECT

1

Um central se conectou a este periférico.

(conn_handle, addr_type, addr)

_IRQ_CENTRAL_DISCONNECT

2

Um central se desconectou deste periférico.

(conn_handle, addr_type, addr)

_IRQ_GATTS_WRITE

3

Um cliente conectado escreveu em uma característica ou descritor local. Use gatts_read para obter o novo valor.

(conn_handle, attr_handle)

_IRQ_GATTS_READ_REQUEST

4

Um cliente conectado emitiu uma leitura. Retorne um código de erro não nulo da tabela abaixo para negar a leitura, ou 0 / None para aceitá-la.

(conn_handle, attr_handle)

_IRQ_SCAN_RESULT

5

Um único pacote de anúncio foi recebido durante uma varredura ativa.

(addr_type, addr, adv_type, rssi, adv_data)

_IRQ_SCAN_DONE

6

A varredura atual foi encerrada, seja porque a duração configurada expirou ou porque gap_scan(None) foi chamado.

()

_IRQ_PERIPHERAL_CONNECT

7

Um gap_connect emitido anteriormente teve sucesso.

(conn_handle, addr_type, addr)

_IRQ_PERIPHERAL_DISCONNECT

8

Um periférico conectado se desconectou.

(conn_handle, addr_type, addr)

_IRQ_GATTC_SERVICE_RESULT

9

Um serviço foi encontrado por gattc_discover_services.

(conn_handle, start_handle, end_handle, uuid)

_IRQ_GATTC_SERVICE_DONE

10

A descoberta de serviços foi concluída.

(conn_handle, status)

_IRQ_GATTC_CHARACTERISTIC_RESULT

11

Uma característica foi encontrada por gattc_discover_characteristics.

(conn_handle, end_handle, value_handle, properties, uuid)

_IRQ_GATTC_CHARACTERISTIC_DONE

12

A descoberta de características foi concluída.

(conn_handle, status)

_IRQ_GATTC_DESCRIPTOR_RESULT

13

Um descritor foi encontrado por gattc_discover_descriptors.

(conn_handle, dsc_handle, uuid)

_IRQ_GATTC_DESCRIPTOR_DONE

14

A descoberta de descritores foi concluída.

(conn_handle, status)

_IRQ_GATTC_READ_RESULT

15

Um gattc_read emitido anteriormente retornou dados.

(conn_handle, value_handle, char_data)

_IRQ_GATTC_READ_DONE

16

Um gattc_read emitido anteriormente foi concluído.

(conn_handle, value_handle, status)

_IRQ_GATTC_WRITE_DONE

17

Um gattc_write emitido anteriormente foi confirmado.

(conn_handle, value_handle, status)

_IRQ_GATTC_NOTIFY

18

Um servidor remoto enviou uma notificação (não confirmada).

(conn_handle, value_handle, notify_data)

_IRQ_GATTC_INDICATE

19

Um servidor remoto enviou uma indicação (confirmada).

(conn_handle, value_handle, notify_data)

_IRQ_GATTS_INDICATE_DONE

20

Uma indicação enviada anteriormente foi confirmada pelo cliente (ou expirou).

(conn_handle, value_handle, status)

_IRQ_MTU_EXCHANGED

21

Uma troca de MTU ATT foi concluída (iniciada por qualquer um dos lados).

(conn_handle, mtu)

_IRQ_L2CAP_ACCEPT

22

Um dispositivo remoto solicitou uma conexão L2CAP em um PSM no qual este dispositivo está escutando. Retorne um inteiro não nulo para rejeitar, ou 0 / None para aceitar.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_CONNECT

23

Um canal L2CAP agora está estabelecido, seja aceitando uma solicitação recebida ou concluindo um l2cap_connect de saída.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_DISCONNECT

24

Um canal L2CAP foi desconectado. status é 0 para uma desconexão limpa, ou não nulo se uma tentativa de conexão de saída falhou.

(conn_handle, cid, psm, status)

_IRQ_L2CAP_RECV

25

Dados chegaram em um canal L2CAP. Chame l2cap_recvinto para lê-los.

(conn_handle, cid)

_IRQ_L2CAP_SEND_READY

26

Um l2cap_send anterior que retornou False foi esvaziado e o canal está pronto novamente. Um status não nulo significa que o buffer de transmissão transbordou e a aplicação deve reenviar os dados.

(conn_handle, cid, status)

_IRQ_CONNECTION_UPDATE

27

O dispositivo remoto atualizou os parâmetros da conexão (intervalo, latência, tempo limite de supervisão).

(conn_handle, conn_interval, conn_latency, supervision_timeout, status)

_IRQ_ENCRYPTION_UPDATE

28

O estado de criptografia de uma conexão mudou, normalmente após a conclusão do pareamento ou vínculo.

(conn_handle, encrypted, authenticated, bonded, key_size)

_IRQ_GET_SECRET

29

A pilha está solicitando um segredo de vínculo armazenado. Se key for None, retorne o index-ésimo valor armazenado de sec_type; caso contrário, retorne o valor associado ao (sec_type, key) fornecido. Retorne None se nada estiver armazenado.

(sec_type, index, key)

_IRQ_SET_SECRET

30

A pilha está pedindo à aplicação para persistir um segredo de vínculo. Retorne True quando armazenado.

(sec_type, key, value)

_IRQ_PASSKEY_ACTION

31

Uma ação de passkey é necessária como parte do pareamento. Responda usando gap_passkey; consulte a tabela de ações de passkey abaixo para as ações possíveis.

(conn_handle, action, passkey)

Para o evento _IRQ_GATTS_READ_REQUEST, os códigos de retorno disponíveis são:

Constante

Valor

Significado

_GATTS_NO_ERROR

0x00

Aceita a leitura.

_GATTS_ERROR_READ_NOT_PERMITTED

0x02

Leitura não permitida.

_GATTS_ERROR_WRITE_NOT_PERMITTED

0x03

Escrita não permitida.

_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION

0x05

O cliente não está autenticado.

_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION

0x08

O cliente não está autorizado.

_GATTS_ERROR_INSUFFICIENT_ENCRYPTION

0x0f

O enlace não está criptografado.

Para o evento _IRQ_PASSKEY_ACTION, as ações disponíveis são:

Constante

Valor

Significado

_PASSKEY_ACTION_NONE

0

Nenhuma ação necessária.

_PASSKEY_ACTION_INPUT

2

Solicita ao usuário que digite a passkey mostrada no dispositivo remoto.

_PASSKEY_ACTION_DISPLAY

3

Exibe uma passkey de 6 dígitos para o dispositivo remoto digitar.

_PASSKEY_ACTION_NUMERIC_COMPARISON

4

Confirma que a passkey corresponde à mostrada no dispositivo remoto.

A fim de economizar espaço no firmware, essas constantes não estão incluídas no módulo bluetooth. Adicione ao seu programa as que você precisar das listas acima.

Papel de Broadcaster (Anunciante)

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

Inicia o anúncio no intervalo especificado (em microssegundos). Esse intervalo será arredondado para baixo até o múltiplo de 625us mais próximo. Para parar de anunciar, defina interval_us como None.

adv_data e resp_data podem ser de qualquer tipo que implemente o protocolo de buffer (por exemplo, bytes, bytearray, str). adv_data é incluído em todos os anúncios, e resp_data é enviado em resposta a uma varredura ativa.

Observação: se adv_data (ou resp_data) for None, então os dados passados à chamada anterior de gap_advertise serão reutilizados. Isso permite que um broadcaster retome o anúncio apenas com gap_advertise(interval_us). Para limpar o payload de anúncio, passe um bytes vazio, ou seja, b''.

Papel de Observador (Scanner)

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

Executa uma operação de varredura com a duração especificada (em milissegundos).

Para varrer indefinidamente, defina duration_ms como 0.

Para parar de varrer, defina duration_ms como None.

Use interval_us e window_us para configurar opcionalmente o ciclo de trabalho. O scanner será executado por window_us microssegundos a cada interval_us microssegundos, durante um total de duration_ms milissegundos. O intervalo e a janela padrão são 1,28 segundos e 11,25 milissegundos, respectivamente (varredura em segundo plano).

Para cada resultado de varredura, o evento _IRQ_SCAN_RESULT será gerado, com os dados de evento (addr_type, addr, adv_type, rssi, adv_data).

Os valores de addr_type indicam endereços públicos ou aleatórios:

Valor

Nome

Significado

0x00

PUBLIC

Endereço de dispositivo público.

0x01

RANDOM

Endereço aleatório (estático, RPA ou NRPA; o tipo é codificado no próprio endereço).

Os valores de adv_type correspondem à Especificação Bluetooth:

Valor

Nome

Significado

0x00

ADV_IND

Anúncio não direcionado conectável e varrível.

0x01

ADV_DIRECT_IND

Anúncio direcionado conectável.

0x02

ADV_SCAN_IND

Anúncio não direcionado varrível.

0x03

ADV_NONCONN_IND

Anúncio não direcionado não conectável.

0x04

SCAN_RSP

Resposta de varredura.

active pode ser definido como True se você quiser receber respostas de varredura nos resultados.

Quando a varredura é interrompida (seja devido ao término da duração ou quando explicitamente interrompida), o evento _IRQ_SCAN_DONE será gerado.

Papel Central

Um dispositivo central pode se conectar a periféricos que ele descobriu usando o papel de observador (consulte gap_scan) ou com um endereço conhecido.

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

Conecta-se a um periférico.

Consulte gap_scan para detalhes sobre os tipos de endereço.

Para cancelar antecipadamente uma tentativa de conexão pendente, chame gap_connect(None).

Em caso de sucesso, o evento _IRQ_PERIPHERAL_CONNECT será gerado. Se uma tentativa de conexão for cancelada, o evento _IRQ_PERIPHERAL_DISCONNECT será gerado.

O dispositivo aguardará até scan_duration_ms para receber um payload de anúncio do dispositivo.

O intervalo de conexão pode ser configurado em microssegundos usando min_conn_interval_us e/ou max_conn_interval_us. Caso contrário, um intervalo padrão será escolhido, normalmente entre 30000 e 50000 microssegundos. Um intervalo mais curto aumentará o throughput, à custa do consumo de energia.

Papel de Periférico

Espera-se que um dispositivo periférico envie anúncios conectáveis (consulte gap_advertise). Ele geralmente atuará como um servidor GATT, tendo primeiro registrado serviços e características usando gatts_register_services.

Quando um central se conecta, o evento _IRQ_CENTRAL_CONNECT será gerado.

Papéis Central e Periférico

gap_disconnect(conn_handle: int, /) bool

Desconecta o handle de conexão especificado. Este pode ser um central que se conectou a este dispositivo (se atuando como periférico) ou um periférico ao qual este dispositivo se conectou anteriormente (se atuando como central).

Em caso de sucesso, o evento _IRQ_PERIPHERAL_DISCONNECT ou _IRQ_CENTRAL_DISCONNECT será gerado.

Retorna False se o handle de conexão não estava conectado, e True caso contrário.

Servidor GATT

Um servidor GATT possui um conjunto de serviços registrados. Cada serviço pode conter características, cada uma das quais tem um valor. As características também podem conter descritores, que por sua vez têm valores.

Esses valores são armazenados localmente e são acessados por seu “value handle”, que é gerado durante o registro do serviço. Eles também podem ser lidos ou escritos por um dispositivo cliente remoto. Além disso, um servidor pode “notificar” uma característica a um cliente conectado por meio de um handle de conexão.

Um dispositivo nos papéis central ou periférico pode funcionar como um servidor GATT; no entanto, na maioria dos casos será mais comum que um dispositivo periférico atue como o servidor.

Características e descritores têm um tamanho máximo padrão de 20 bytes (a MTU ATT padrão de 23 bytes menos um cabeçalho ATT de 3 bytes; uma MTU negociada maior não eleva por si só esse limite). Qualquer coisa escrita neles por um cliente será truncada para esse tamanho. No entanto, qualquer escrita local aumentará o tamanho máximo, então se você quiser permitir escritas maiores de um cliente em uma determinada característica, use gatts_write após o registro. Por exemplo, gatts_write(char_handle, bytes(100)).

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

Configura o servidor com os serviços especificados, substituindo quaisquer serviços existentes.

services_definition é uma lista de serviços, onde cada serviço é uma tupla de dois elementos contendo um UUID e uma lista de características.

Cada característica é uma tupla de dois ou três elementos contendo um UUID, um valor de flags e, opcionalmente, uma lista de descritores.

Cada descritor é uma tupla de dois elementos contendo um UUID e um valor de flags.

As flags são uma combinação OR bit a bit das flags definidas abaixo. Elas definem tanto o comportamento da característica (ou descritor) quanto os requisitos de segurança e privacidade.

O valor de retorno é uma lista (um elemento por serviço) de tuplas (cada elemento é um value handle). Os handles de características e descritores são achatados na mesma tupla, na ordem em que são definidos.

O exemplo a seguir registra dois serviços (Heart Rate e 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),
)

Os três value handles (hr, tx, rx) podem ser usados com gatts_read, gatts_write, gatts_notify e gatts_indicate.

Observação: O anúncio deve ser interrompido antes de registrar serviços.

As flags disponíveis para características e descritores são:

Constante

Valor

Significado

_FLAG_BROADCAST

0x0001

A característica pode ser transmitida.

_FLAG_READ

0x0002

O cliente pode ler o valor.

_FLAG_WRITE_NO_RESPONSE

0x0004

O cliente pode escrever sem esperar uma resposta.

_FLAG_WRITE

0x0008

O cliente pode escrever com uma resposta confirmada.

_FLAG_NOTIFY

0x0010

O servidor pode enviar notificações (não confirmadas).

_FLAG_INDICATE

0x0020

O servidor pode enviar indicações (confirmadas).

_FLAG_AUTHENTICATED_SIGNED_WRITE

0x0040

O cliente pode emitir escritas assinadas.

_FLAG_AUX_WRITE

0x0100

Propriedades estendidas: escritas enfileiradas/confiáveis são permitidas.

_FLAG_READ_ENCRYPTED

0x0200

A leitura requer um enlace criptografado.

_FLAG_READ_AUTHENTICATED

0x0400

A leitura requer um enlace autenticado (com proteção MITM).

_FLAG_READ_AUTHORIZED

0x0800

A leitura requer autorização em nível de aplicação.

_FLAG_WRITE_ENCRYPTED

0x1000

A escrita requer um enlace criptografado.

_FLAG_WRITE_AUTHENTICATED

0x2000

A escrita requer um enlace autenticado (com proteção MITM).

_FLAG_WRITE_AUTHORIZED

0x4000

A escrita requer autorização em nível de aplicação.

Assim como as constantes de evento acima, essas flags não são fornecidas pelo módulo bluetooth; copie as que você precisar para o seu programa.

gatts_read(value_handle: int, /) bytes

Lê o valor local deste handle (que foi escrito por gatts_write ou por um cliente remoto).

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

Escreve o valor local deste handle, que pode ser lido por um cliente.

Se send_update for True, então quaisquer clientes inscritos serão notificados (ou indicados, dependendo do que eles assinaram e de quais operações a característica suporta) sobre essa escrita.

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

Envia uma solicitação de notificação a um cliente conectado.

Se data for None (o padrão), então o valor local atual (conforme definido com gatts_write) será enviado.

Caso contrário, se data não for None, então esse valor é enviado ao cliente como parte da notificação. O valor local não será modificado.

Observação: A notificação será enviada independentemente do status de inscrição do cliente nesta característica.

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

Envia uma solicitação de indicação a um cliente conectado.

Se data for None (o padrão), então o valor local atual (conforme definido com gatts_write) será enviado.

Caso contrário, se data não for None, então esse valor é enviado ao cliente como parte da indicação. O valor local não será modificado.

Na confirmação (ou falha, por exemplo, tempo limite), o evento _IRQ_GATTS_INDICATE_DONE será gerado.

Observação: A indicação será enviada independentemente do status de inscrição do cliente nesta característica.

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

Define o tamanho do buffer interno para um valor em bytes. Isso limitará a maior escrita possível que pode ser recebida. O padrão é 20 bytes (MTU ATT padrão de 23 menos o cabeçalho ATT de 3 bytes).

Definir append como True fará com que todas as escritas remotas sejam anexadas ao valor atual, em vez de substituí-lo. No máximo len bytes podem ser armazenados em buffer dessa forma. Quando você usa gatts_read, o valor será limpo após a leitura. Esse recurso é útil ao implementar algo como o Nordic UART Service.

Cliente GATT

Um cliente GATT pode descobrir e ler/escrever características em um servidor GATT remoto.

É mais comum que um dispositivo no papel central atue como o cliente GATT; no entanto, também é possível que um periférico atue como cliente a fim de descobrir informações sobre o central que se conectou a ele (por exemplo, para ler o nome do dispositivo a partir do serviço de informações do dispositivo).

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

Consulta um servidor conectado por seus serviços.

Opcionalmente, especifique um uuid de serviço para consultar apenas esse serviço.

Para cada serviço descoberto, o evento _IRQ_GATTC_SERVICE_RESULT será gerado, seguido de _IRQ_GATTC_SERVICE_DONE na conclusão.

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

Consulta um servidor conectado por características no intervalo especificado.

Opcionalmente, especifique um uuid de característica para consultar apenas essa característica.

Passar start_handle=1 e end_handle=0xffff cobre todo o intervalo de handles de atributos GATT, então essa combinação pesquisa efetivamente todos os serviços no dispositivo remoto.

Para cada característica descoberta, o evento _IRQ_GATTC_CHARACTERISTIC_RESULT será gerado, seguido de _IRQ_GATTC_CHARACTERISTIC_DONE na conclusão.

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

Consulta um servidor conectado por descritores no intervalo especificado.

Para cada descritor descoberto, o evento _IRQ_GATTC_DESCRIPTOR_RESULT será gerado, seguido de _IRQ_GATTC_DESCRIPTOR_DONE na conclusão.

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

Emite uma leitura remota a um servidor conectado para o handle de característica ou descritor especificado.

Quando um valor estiver disponível, o evento _IRQ_GATTC_READ_RESULT será gerado, seguido de _IRQ_GATTC_READ_DONE na conclusão.

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

Emite uma escrita remota a um servidor conectado para o handle de característica ou descritor especificado.

O argumento mode especifica o comportamento de escrita, sendo os valores atualmente suportados:

  • mode=0 (padrão) é uma escrita-sem-resposta: a escrita será enviada ao servidor remoto, mas nenhuma confirmação será retornada, e nenhum evento será gerado.

  • mode=1 é uma escrita-com-resposta: o servidor remoto é solicitado a enviar uma resposta/confirmação de que recebeu os dados.

Se uma resposta for recebida do servidor remoto, o evento _IRQ_GATTC_WRITE_DONE será gerado.

gattc_exchange_mtu(conn_handle: int, /) None

Inicia a troca de MTU com um servidor conectado, usando a MTU preferida definida com BLE.config(mtu=value).

O evento _IRQ_MTU_EXCHANGED será gerado quando a troca de MTU for concluída.

A troca de MTU é normalmente iniciada pelo central; o NimBLE suporta ambos os papéis.

Canais L2CAP Orientados a Conexão

Esse recurso permite a troca de dados semelhante a sockets entre dois dispositivos BLE. Uma vez que os dispositivos estejam conectados via GAP, qualquer um deles pode escutar para que o outro se conecte em um PSM numérico (Protocol/Service Multiplexer).

Apenas um canal L2CAP pode estar ativo por vez (ou seja, você não pode conectar enquanto está escutando).

Os canais L2CAP ativos são identificados pelo handle de conexão no qual foram estabelecidos e por um CID (channel ID).

Os canais orientados a conexão possuem controle de fluxo baseado em crédito integrado. Diferente do ATT, onde os dispositivos negociam uma MTU compartilhada, tanto o dispositivo que escuta quanto o que se conecta definem cada um uma MTU independente, que limita a quantidade máxima de dados pendentes que o dispositivo remoto pode enviar antes de serem totalmente consumidos em l2cap_recvinto.

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

Começa a escutar solicitações de canal L2CAP recebidas no psm especificado com a MTU local definida como mtu.

Quando um dispositivo remoto inicia uma conexão, o evento _IRQ_L2CAP_ACCEPT será gerado, o que dá ao servidor que escuta a chance de rejeitar a conexão recebida (retornando um inteiro não nulo).

Uma vez aceita a conexão, o evento _IRQ_L2CAP_CONNECT será gerado, permitindo que o servidor obtenha o channel ID (CID) e as MTUs local e remota.

Observação: Atualmente não é possível parar de escutar.

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

Conecta-se a um par que está escutando no psm especificado com a MTU local definida como mtu.

Em uma conexão bem-sucedida, o evento _IRQ_L2CAP_CONNECT será gerado, permitindo que o cliente obtenha o CID e as MTUs local e remota (do par).

Uma conexão malsucedida gerará o evento _IRQ_L2CAP_DISCONNECT com um status não nulo.

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

Desconecta um canal L2CAP ativo com o conn_handle e o cid especificados.

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

Envia o buf especificado (que deve suportar o protocolo de buffer) no canal L2CAP identificado por conn_handle e cid.

O buffer deve satisfazer ambos os limites: não deve exceder a MTU remota (do par) e não deve exceder o dobro da MTU local.

Isso retornará False se o canal estiver agora “travado” (stalled), o que significa que l2cap_send não deve ser chamado novamente até que o evento _IRQ_L2CAP_SEND_READY seja recebido (o que acontecerá quando o dispositivo remoto conceder mais créditos, normalmente depois de ter recebido e processado os dados).

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

Recebe dados do conn_handle e cid especificados no buf fornecido (que deve suportar o protocolo de buffer, por exemplo, bytearray ou memoryview).

Retorna o número de bytes lidos do canal.

Se buf for None, então retorna o número de bytes disponíveis.

Observação: Após receber o evento _IRQ_L2CAP_RECV, a aplicação deve continuar chamando l2cap_recvinto até que não haja mais bytes disponíveis no buffer de recepção (normalmente até o tamanho da MTU remota (do par)).

Até que o buffer de recepção esteja vazio, o dispositivo remoto não receberá mais créditos de canal e não poderá enviar mais dados.

Pareamento e Vínculo (Bonding)

O pareamento permite que uma conexão seja criptografada e autenticada por meio da troca de segredos (com proteção MITM opcional via autenticação por passkey).

O vínculo (bonding) é o processo de armazenar esses segredos em armazenamento não volátil. Quando vinculado, um dispositivo é capaz de resolver um endereço privado resolvível (RPA) de outro dispositivo com base na chave de resolução de identidade (IRK) armazenada. Para suportar o vínculo, uma aplicação deve implementar os eventos _IRQ_GET_SECRET e _IRQ_SET_SECRET.

gap_pair(conn_handle: int, /) None

Inicia o pareamento com o dispositivo remoto.

Antes de chamar isso, certifique-se de que as opções de configuração io, mitm, le_secure e bond estejam definidas (via config).

Em um pareamento bem-sucedido, o evento _IRQ_ENCRYPTION_UPDATE será gerado.

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

Responde a um evento _IRQ_PASSKEY_ACTION para o conn_handle e a action especificados. O significado de passkey depende de action (que, por sua vez, depende da capacidade de E/S configurada):

Ação

Resposta passkey necessária

_PASSKEY_ACTION_INPUT

A passkey que o usuário lê do dispositivo remoto.

_PASSKEY_ACTION_DISPLAY

Uma passkey aleatória de 6 dígitos gerada localmente e mostrada ao usuário.

_PASSKEY_ACTION_NUMERIC_COMPARISON

1 para aceitar a passkey mostrada no evento _IRQ_PASSKEY_ACTION, ou 0 para cancelar o pareamento.

class UUID

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

Cria uma instância de UUID com o value especificado. O Bluetooth usa três larguras de UUID; UUID aceita qualquer uma delas:

Largura do UUID

Tipos de value aceitos

Exemplo

16 bits

int ou um buffer de 2 bytes (little-endian)

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

32 bits

buffer de 4 bytes (little-endian)

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

128 bits

buffer de 16 bytes ou uma string com hifens

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

UUIDs de 16 e 32 bits são normalmente identificadores alocados pelo SIG (consulte os números atribuídos do Bluetooth); UUIDs de 128 bits são normalmente definidos pelo fornecedor.