bluetooth — Bluetooth de baixo nível

Este módulo fornece uma interface para o controlador Bluetooth integrado. Suporta Bluetooth Low Energy (BLE) nos papéis de Central, Periférico, Transmissor e Observador, bem como servidor e cliente GATT e canais orientados a ligação L2CAP. Um dispositivo pode operar em vários papéis em simultâneo. O emparelhamento e a vinculação também são suportados.

Esta API destina-se a corresponder ao protocolo Bluetooth de baixo nível e a fornecer blocos construtivos para abstrações de nível mais elevado, como tipos de dispositivos específicos.

Dica

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

class BLE

class bluetooth.BLE

Devolve o objeto BLE singleton.

Configuração

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

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

O rádio deve ser ativado antes de utilizar 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 indicado como uma string, e apenas um parâmetro é consultado de cada vez. Para definir valores, utilize a sintaxe de palavra-chave, podendo ser definidos um ou mais parâmetros de cada vez.

Os valores atualmente suportados são:

  • 'mac': O endereço atual em uso, dependendo do modo de endereço atual. Devolve um tuplo de (addr_type, addr).

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

    Isto só pode ser consultado enquanto a interface estiver ativa.

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

    Valor

    Nome

    Comportamento

    0x00

    PUBLIC

    Utiliza o endereço público do controlador.

    0x01

    RANDOM

    Utiliza um endereço estático gerado.

    0x02

    RPA

    Utiliza endereços privados resolúveis.

    0x03

    NRPA

    Utiliza endereços privados não resolúveis.

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

  • 'gap_name': Obtém/define o nome do dispositivo GAP utilizado pelo serviço de Acesso Genérico (UUID 0x1800), característica Nome do Dispositivo (UUID 0x2a00). Pode ser definido em qualquer momento e alterado várias vezes.

  • 'rxbuf': Obtém/define o tamanho em bytes do buffer interno utilizado para armazenar eventos recebidos. Este buffer é global para todo o controlador BLE e trata, portanto, os dados recebidos para todos os eventos, incluindo todas as características. Aumentar este valor permite um melhor tratamento de dados recebidos em rajada (por exemplo, resultados de pesquisa) e a capacidade de receber valores de características maiores.

  • 'mtu': Obtém/define o MTU que será utilizado durante uma troca de MTU ATT. O MTU resultante será o mínimo entre este e o MTU do dispositivo remoto. A troca de MTU ATT não ocorre automaticamente (a menos que o dispositivo remoto a inicie) e deve ser iniciada manualmente com gattc_exchange_mtu. Utilize o evento _IRQ_MTU_EXCHANGED para descobrir o MTU de uma ligação específica.

  • 'bond': Define se a vinculação será ativada durante o emparelhamento. Quando ativada, os pedidos de emparelhamento definirão o sinalizador «bond» e as chaves serão armazenadas por ambos os dispositivos.

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

  • 'io': Define as capacidades de I/O deste dispositivo.

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

    Constante

    Valor

    Capacidade

    _IO_CAPABILITY_DISPLAY_ONLY

    0

    Apenas visualização

    _IO_CAPABILITY_DISPLAY_YESNO

    1

    Visualização com entrada sim/não

    _IO_CAPABILITY_KEYBOARD_ONLY

    2

    Apenas teclado

    _IO_CAPABILITY_NO_INPUT_OUTPUT

    3

    Sem entrada nem saída

    _IO_CAPABILITY_KEYBOARD_DISPLAY

    4

    Teclado e visualização

  • 'le_secure': Define se o emparelhamento «LE Secure» é obrigatório. O valor por defeito é falso (ou seja, permite «Legacy Pairing»).

Tratamento de Eventos

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

Regista um callback para eventos do stack BLE. O handler recebe dois argumentos: event (que será um dos códigos abaixo) e data (que é um tuplo de valores específicos do evento).

Nota: Como otimização para evitar alocações desnecessárias, as entradas addr, adv_data, char_data, notify_data e uuid nos tuplos são instâncias de memoryview somente de leitura que apontam para o ringbuffer interno do bluetooth, sendo válidas apenas durante a invocação da função de tratamento de IRQ. Se o seu programa precisar de guardar um destes valores para acesso após o retorno do tratador de IRQ (por exemplo, guardando-o numa instância de classe ou numa variável global), é necessário fazer uma cópia dos dados, utilizando bytes() ou bluetooth.UUID(), da seguinte forma:

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 pesquisa pode inspecionar adv_data para decidir se é o dispositivo correto, copiando apenas depois os dados do endereço para utilização noutro ponto do programa. Para imprimir dados dentro do tratador de IRQ, será necessário print(bytes(addr)).

Um tratador tipicamente despacha com base no código do evento e desempacota o tuplo de payload específico 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
        ...

Todos os códigos de evento, o payload que entregam e uma breve descrição sã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

Tuplo de payload

_IRQ_CENTRAL_CONNECT

1

Um central ligou-se a este periférico.

(conn_handle, addr_type, addr)

_IRQ_CENTRAL_DISCONNECT

2

Um central desligou-se deste periférico.

(conn_handle, addr_type, addr)

_IRQ_GATTS_WRITE

3

Um cliente ligado escreveu numa característica ou descritor local. Utilize gatts_read para obter o novo valor.

(conn_handle, attr_handle)

_IRQ_GATTS_READ_REQUEST

4

Um cliente ligado emitiu uma leitura. Devolva um código de erro não nulo da tabela abaixo para recusar a leitura, ou 0 / None para a aceitar.

(conn_handle, attr_handle)

_IRQ_SCAN_RESULT

5

Um pacote de publicidade único foi recebido durante uma pesquisa ativa.

(addr_type, addr, adv_type, rssi, adv_data)

_IRQ_SCAN_DONE

6

A pesquisa atual terminou, 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 ligado desligou-se.

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

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

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

(conn_handle, status)

_IRQ_GATTC_READ_RESULT

15

Um gattc_read emitido anteriormente devolveu dados.

(conn_handle, value_handle, char_data)

_IRQ_GATTC_READ_DONE

16

Um gattc_read emitido anteriormente terminou.

(conn_handle, value_handle, status)

_IRQ_GATTC_WRITE_DONE

17

Um gattc_write emitido anteriormente foi reconhecido.

(conn_handle, value_handle, status)

_IRQ_GATTC_NOTIFY

18

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

(conn_handle, value_handle, notify_data)

_IRQ_GATTC_INDICATE

19

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

(conn_handle, value_handle, notify_data)

_IRQ_GATTS_INDICATE_DONE

20

Uma indicação enviada anteriormente foi reconhecida pelo cliente (ou expirou o tempo limite).

(conn_handle, value_handle, status)

_IRQ_MTU_EXCHANGED

21

Uma troca de MTU ATT foi concluída (iniciada por qualquer lado).

(conn_handle, mtu)

_IRQ_L2CAP_ACCEPT

22

Um dispositivo remoto solicitou uma ligação L2CAP num PSM em que este dispositivo está à escuta. Devolva um inteiro não nulo para recusar, ou 0 / None para aceitar.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_CONNECT

23

Um canal L2CAP está agora estabelecido, seja por aceitação de um pedido de entrada ou por conclusão de um l2cap_connect de saída.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_DISCONNECT

24

Um canal L2CAP foi desligado. status é 0 para um desligamento limpo, ou não nulo se uma tentativa de ligação de saída falhou.

(conn_handle, cid, psm, status)

_IRQ_L2CAP_RECV

25

Chegaram dados num canal L2CAP. Chame l2cap_recvinto para os ler.

(conn_handle, cid)

_IRQ_L2CAP_SEND_READY

26

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

(conn_handle, cid, status)

_IRQ_CONNECTION_UPDATE

27

O dispositivo remoto atualizou os parâmetros de ligação (intervalo, latência, timeout de supervisão).

(conn_handle, conn_interval, conn_latency, supervision_timeout, status)

_IRQ_ENCRYPTION_UPDATE

28

O estado de encriptação de uma ligação mudou, tipicamente após a conclusão do emparelhamento ou vinculação.

(conn_handle, encrypted, authenticated, bonded, key_size)

_IRQ_GET_SECRET

29

O stack está a solicitar um segredo de vinculação armazenado. Se key for None, devolve o indexº valor armazenado de sec_type; caso contrário, devolve o valor associado ao par (sec_type, key) fornecido. Devolve None se nada estiver armazenado.

(sec_type, index, key)

_IRQ_SET_SECRET

30

O stack está a pedir à aplicação para persistir um segredo de vinculação. Devolva True após o armazenamento.

(sec_type, key, value)

_IRQ_PASSKEY_ACTION

31

É necessária uma ação de passkey como parte do emparelhamento. Responda utilizando 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

Aceitar 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

A ligação não está encriptada.

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

Pedir ao utilizador para introduzir o passkey mostrado no dispositivo remoto.

_PASSKEY_ACTION_DISPLAY

3

Mostrar um passkey de 6 dígitos para o dispositivo remoto introduzir.

_PASSKEY_ACTION_NUMERIC_COMPARISON

4

Confirmar que o passkey corresponde ao mostrado no dispositivo remoto.

Para poupar espaço no firmware, estas constantes não estão incluídas no módulo bluetooth. Adicione ao seu programa as que precisar das listas acima.

Papel de Transmissor (Anunciante)

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

Inicia a publicidade no intervalo especificado (em microssegundos). Este intervalo será arredondado para baixo ao múltiplo de 625 µs mais próximo. Para parar a publicidade, 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 todas as transmissões, e resp_data é enviado em resposta a uma pesquisa ativa.

Nota: se adv_data (ou resp_data) for None, os dados passados na chamada anterior a gap_advertise serão reutilizados. Isto permite que um transmissor retome a publicidade apenas com gap_advertise(interval_us). Para limpar o payload de publicidade, passe bytes vazio, isto é, 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 pesquisa com a duração especificada (em milissegundos).

Para pesquisar indefinidamente, defina duration_ms como 0.

Para parar a pesquisa, defina duration_ms como None.

Utilize interval_us e window_us para configurar opcionalmente o ciclo de trabalho. O scanner funcionará durante window_us microssegundos a cada interval_us microssegundos, durante um total de duration_ms milissegundos. O intervalo e a janela por defeito são 1,28 segundos e 11,25 milissegundos, respetivamente (pesquisa em segundo plano).

Para cada resultado de pesquisa, o evento _IRQ_SCAN_RESULT será gerado, com 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 público do dispositivo.

0x01

RANDOM

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

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

Valor

Nome

Significado

0x00

ADV_IND

Publicidade não direcionada ligável e pesquisável.

0x01

ADV_DIRECT_IND

Publicidade direcionada ligável.

0x02

ADV_SCAN_IND

Publicidade não direcionada pesquisável.

0x03

ADV_NONCONN_IND

Publicidade não direcionada não ligável.

0x04

SCAN_RSP

Resposta de pesquisa.

active pode ser definido como True se quiser receber respostas de pesquisa nos resultados.

Quando a pesquisa for parada (seja por conclusão da duração ou por paragem explícita), o evento _IRQ_SCAN_DONE será gerado.

Papel de Central

Um dispositivo central pode ligar-se a periféricos que descobriu utilizando 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

Ligar a um periférico.

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

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

Em caso de sucesso, o evento _IRQ_PERIPHERAL_CONNECT será gerado. Ao cancelar uma tentativa de ligação, o evento _IRQ_PERIPHERAL_DISCONNECT será gerado.

O dispositivo aguardará até scan_duration_ms para receber um payload de publicidade do dispositivo.

O intervalo de ligação pode ser configurado em microssegundos usando min_conn_interval_us e/ou max_conn_interval_us. Caso contrário, será escolhido um intervalo por defeito, tipicamente entre 30000 e 50000 microssegundos. Um intervalo mais curto aumentará o débito, à custa do consumo de energia.

Papel de Periférico

Espera-se que um dispositivo periférico envie publicidade ligável (consulte gap_advertise). Normalmente actuará como servidor GATT, tendo previamente registado serviços e características com gatts_register_services.

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

Papéis de Central e Periférico

gap_disconnect(conn_handle: int, /) bool

Desliga o handle de ligação especificado. Pode ser um central que se ligou a este dispositivo (se a agir como periférico) ou um periférico ao qual este dispositivo se ligou anteriormente (se a agir como central).

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

Devolve False se o handle de ligação não estava ligado, e True caso contrário.

Servidor GATT

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

Estes valores são armazenados localmente e acedidos através do seu «value handle», gerado durante o registo do serviço. Também podem ser lidos ou escritos por um dispositivo cliente remoto. Adicionalmente, um servidor pode «notificar» uma característica a um cliente ligado através de um handle de ligação.

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

As características e descritores têm um tamanho máximo por defeito de 20 bytes (o MTU ATT por defeito de 23 bytes menos um cabeçalho ATT de 3 bytes; um MTU negociado superior não aumenta automaticamente este limite). Qualquer escrita feita por um cliente será truncada para este comprimento. No entanto, qualquer escrita local aumentará o tamanho máximo; portanto, se pretender permitir escritas maiores por parte de um cliente numa dada característica, utilize gatts_write após o registo. 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, em que cada serviço é um tuplo de dois elementos contendo um UUID e uma lista de características.

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

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

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

O valor de retorno é uma lista (um elemento por serviço) de tuplos (cada elemento é um value handle). Os handles de características e descritores são nivelados no mesmo tuplo, pela ordem em que são definidos.

O exemplo seguinte regista 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 utilizados com gatts_read, gatts_write, gatts_notify e gatts_indicate.

Nota: A publicidade deve ser parada antes de registar 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 aguardar resposta.

_FLAG_WRITE

0x0008

O cliente pode escrever com resposta de confirmação.

_FLAG_NOTIFY

0x0010

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

_FLAG_INDICATE

0x0020

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

_FLAG_AUTHENTICATED_SIGNED_WRITE

0x0040

O cliente pode emitir escritas assinadas.

_FLAG_AUX_WRITE

0x0100

Propriedades estendidas: escritas em fila/fiáveis são permitidas.

_FLAG_READ_ENCRYPTED

0x0200

A leitura requer uma ligação encriptada.

_FLAG_READ_AUTHENTICATED

0x0400

A leitura requer uma ligação autenticada (com proteção MITM).

_FLAG_READ_AUTHORIZED

0x0800

A leitura requer autorização ao nível da aplicação.

_FLAG_WRITE_ENCRYPTED

0x1000

A escrita requer uma ligação encriptada.

_FLAG_WRITE_AUTHENTICATED

0x2000

A escrita requer uma ligação autenticada (com proteção MITM).

_FLAG_WRITE_AUTHORIZED

0x4000

A escrita requer autorização ao nível da aplicação.

Tal como as constantes de eventos acima, estas flags não são fornecidas pelo módulo bluetooth; copie as que precisar para o seu programa.

gatts_read(value_handle: int, /) bytes

Lê o valor local para este handle (que tanto pode ter sido escrito por gatts_write como por um cliente remoto).

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

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

Se send_update for True, todos os clientes subscritos serão notificados (ou indicados, consoante o que estejam subscritos e as operações que a característica suporta) acerca desta escrita.

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

Envia um pedido de notificação a um cliente ligado.

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

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

Nota: A notificação será enviada independentemente do estado de subscrição do cliente a esta característica.

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

Envia um pedido de indicação a um cliente ligado.

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

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

Após o reconhecimento (ou falha, por exemplo, timeout), o evento _IRQ_GATTS_INDICATE_DONE será gerado.

Nota: A indicação será enviada independentemente do estado de subscrição do cliente a esta 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. Isto limitará o maior write possível que pode ser recebido. O valor por defeito é 20 bytes (MTU ATT por defeito de 23 menos o cabeçalho ATT de 3 bytes).

Definir append como True fará com que todas as escritas remotas sejam adicionadas ao, em vez de substituírem o, valor atual. No máximo len bytes podem ser armazenados desta forma. Ao utilizar gatts_read, o valor será limpo após a leitura. Esta funcionalidade é útil ao implementar algo como o Nordic UART Service.

Cliente GATT

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

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

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

Consulta os serviços de um servidor ligado.

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 as características de um servidor ligado 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 o intervalo completo de handles de atributos GATT, pesquisando 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 os descritores de um servidor ligado 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 num servidor ligado 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 num servidor ligado 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 para o servidor remoto mas nenhuma confirmação será devolvida e nenhum evento será gerado.

  • mode=1 é uma escrita com resposta: o servidor remoto é solicitado a enviar uma resposta/reconhecimento 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 ligado, utilizando o MTU preferido definido com BLE.config(mtu=value).

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

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

Canais L2CAP Orientados a Ligação

Esta funcionalidade permite a troca de dados semelhante a sockets entre dois dispositivos BLE. Uma vez ligados os dispositivos via GAP, qualquer dispositivo pode aguardar que o outro se ligue num PSM (Protocol/Service Multiplexer) numérico.

Apenas um canal L2CAP pode estar ativo em dado momento (ou seja, não é possível ligar enquanto se está à escuta).

Os canais L2CAP ativos são identificados pelo handle de ligação em que foram estabelecidos e por um CID (channel ID).

Os canais orientados a ligação têm controlo de fluxo baseado em créditos incorporado. Ao contrário do ATT, onde os dispositivos negoceiam um MTU partilhado, tanto o dispositivo que escuta como o que se liga definem um 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 aguardar pedidos de canal L2CAP de entrada no psm especificado com o MTU local definido como mtu.

Quando um dispositivo remoto inicia uma ligação, o evento _IRQ_L2CAP_ACCEPT será gerado, dando ao servidor que escuta a oportunidade de rejeitar a ligação de entrada (devolvendo um inteiro não nulo).

Uma vez aceite a ligação, o evento _IRQ_L2CAP_CONNECT será gerado, permitindo ao servidor obter o CID e os MTU local e remoto.

Nota: Não é atualmente possível parar de escutar.

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

Liga a um par que está à escuta no psm especificado com o MTU local definido como mtu.

Em caso de ligação bem-sucedida, o evento _IRQ_L2CAP_CONNECT será gerado, permitindo ao cliente obter o CID e os MTU local e remoto (peer).

Uma ligação sem sucesso gerará o evento _IRQ_L2CAP_DISCONNECT com um status não nulo.

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

Desliga um canal L2CAP ativo com o conn_handle e 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 o MTU remoto (peer) e não deve exceder o dobro do MTU local.

Isto devolverá False se o canal estiver agora «bloqueado», 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, tipicamente após 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 para o buf fornecido (que deve suportar o protocolo de buffer, por exemplo, bytearray ou memoryview).

Devolve o número de bytes lidos do canal.

Se buf for None, devolve o número de bytes disponíveis.

Nota: Após receber o evento _IRQ_L2CAP_RECV, a aplicação deve continuar a chamar l2cap_recvinto até que não haja mais bytes disponíveis no buffer de receção (tipicamente até ao tamanho do MTU remoto (peer)).

Enquanto o buffer de receção não estiver vazio, o dispositivo remoto não receberá mais créditos de canal e não conseguirá enviar mais dados.

Emparelhamento e Vinculação

O emparelhamento permite que uma ligação seja encriptada e autenticada através da troca de segredos (com proteção MITM opcional via autenticação por passkey).

A vinculação é o processo de armazenar esses segredos em armazenamento não volátil. Quando vinculado, um dispositivo consegue resolver um endereço privado resolúvel (RPA) de outro dispositivo com base na chave de resolução de identidade (IRK) armazenada. Para suportar a vinculação, uma aplicação deve implementar os eventos _IRQ_GET_SECRET e _IRQ_SET_SECRET.

gap_pair(conn_handle: int, /) None

Inicia o emparelhamento com o dispositivo remoto.

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

Em caso de emparelhamento 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 action especificados. O significado de passkey depende de action (que por sua vez depende da capacidade de I/O configurada):

Ação

Resposta de passkey necessária

_PASSKEY_ACTION_INPUT

O passkey que o utilizador lê do dispositivo remoto.

_PASSKEY_ACTION_DISPLAY

Um passkey aleatório de 6 dígitos gerado localmente e mostrado ao utilizador.

_PASSKEY_ACTION_NUMERIC_COMPARISON

1 para aceitar o passkey mostrado no evento _IRQ_PASSKEY_ACTION, ou 0 para cancelar o emparelhamento.

class UUID

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

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

Largura de UUID

Tipos de value aceites

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 hífens

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

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