bluetooth — Bluetooth de bajo nivel

Este módulo proporciona una interfaz con el controlador Bluetooth integrado. Admite Bluetooth Low Energy (BLE) en los roles Central, Periférico, Difusor (Broadcaster) y Observador, así como servidor y cliente GATT y canales L2CAP orientados a conexión. Un dispositivo puede operar en varios roles simultáneamente. También se admiten el emparejamiento y el vinculado (bonding).

Esta API está pensada para coincidir con el protocolo Bluetooth de bajo nivel y proporcionar bloques de construcción para abstracciones de más alto nivel, como tipos de dispositivos específicos.

Truco

Para la mayoría de las aplicaciones, es preferible usar la biblioteca de más alto nivel aioble, que proporciona un envoltorio basado en asyncio alrededor de este módulo. Consulte aioble — BLE asíncrono.

class BLE

class bluetooth.BLE

Devuelve el objeto singleton BLE.

Configuración

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

Opcionalmente cambia el estado activo de la radio BLE y devuelve el estado actual.

La radio debe activarse antes de usar cualquier otro método de esta clase.

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

Obtiene o establece valores de configuración de la interfaz BLE. Para obtener un valor, el nombre del parámetro debe indicarse entre comillas como una cadena, y solo se consulta un parámetro a la vez. Para establecer valores, use la sintaxis de palabras clave, y se pueden establecer uno o más parámetros a la vez.

Los valores actualmente admitidos son:

  • 'mac': La dirección actual en uso, según el modo de dirección actual. Esto devuelve una tupla de (addr_type, addr).

    Consulte gap_scan para más detalles sobre el tipo de dirección.

    Esto solo puede consultarse mientras la interfaz está actualmente activa.

  • 'addr_mode': Establece el modo de dirección. Los valores son:

    Valor

    Nombre

    Comportamiento

    0x00

    PUBLIC

    Usa la dirección pública del controlador.

    0x01

    RANDOM

    Usa una dirección estática generada.

    0x02

    RPA

    Usa direcciones privadas resolubles.

    0x03

    NRPA

    Usa direcciones privadas no resolubles.

    De forma predeterminada, la interfaz usará una dirección PUBLIC si está disponible; en caso contrario, usará una dirección RANDOM.

  • 'gap_name': Obtiene/establece el nombre del dispositivo GAP usado por el servicio Generic Access (UUID 0x1800), característica Device Name (UUID 0x2a00). Esto se puede establecer en cualquier momento y cambiar varias veces.

  • 'rxbuf': Obtiene/establece el tamaño en bytes del búfer interno usado para almacenar los eventos entrantes. Este búfer es global para todo el controlador BLE y, por tanto, gestiona los datos entrantes de todos los eventos, incluidas todas las características. Aumentarlo permite gestionar mejor los datos entrantes en ráfagas (por ejemplo, resultados de escaneo) y recibir valores de característica más grandes.

  • 'mtu': Obtiene/establece la MTU que se usará durante un intercambio de MTU de ATT. La MTU resultante será el mínimo entre esta y la MTU del dispositivo remoto. El intercambio de MTU de ATT no se realizará automáticamente (a menos que el dispositivo remoto lo inicie) y debe iniciarse manualmente con gattc_exchange_mtu. Use el evento _IRQ_MTU_EXCHANGED para descubrir la MTU de una conexión determinada.

  • 'bond': Establece si se habilitará el vinculado (bonding) durante el emparejamiento. Cuando está habilitado, las solicitudes de emparejamiento establecerán el indicador «bond» y las claves serán almacenadas por ambos dispositivos.

  • 'mitm': Establece si se requiere protección MITM para el emparejamiento.

  • 'io': Establece las capacidades de E/S de este dispositivo.

    Las opciones disponibles son:

    Constante

    Valor

    Capacidad

    _IO_CAPABILITY_DISPLAY_ONLY

    0

    Solo pantalla

    _IO_CAPABILITY_DISPLAY_YESNO

    1

    Pantalla con entrada sí/no

    _IO_CAPABILITY_KEYBOARD_ONLY

    2

    Solo teclado

    _IO_CAPABILITY_NO_INPUT_OUTPUT

    3

    Sin entrada ni salida

    _IO_CAPABILITY_KEYBOARD_DISPLAY

    4

    Teclado y pantalla

  • 'le_secure': Establece si se requiere el emparejamiento «LE Secure». El valor predeterminado es falso (es decir, permite el «Legacy Pairing»).

Gestión de eventos

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

Registra una función de retorno (callback) para los eventos de la pila BLE. El handler recibe dos argumentos: event (que será uno de los códigos siguientes) y data (que es una tupla de valores específica del evento).

Nota: Como optimización para evitar asignaciones de memoria innecesarias, las entradas addr, adv_data, char_data, notify_data y uuid de las tuplas son instancias de memoryview de solo lectura que apuntan al búfer circular interno de bluetooth, y solo son válidas durante la invocación de la función gestora del IRQ. Si su programa necesita guardar uno de estos valores para acceder a él después de que la función gestora del IRQ haya retornado (por ejemplo, guardándolo en una instancia de clase o en una variable global), entonces necesita tomar una copia de los datos, ya sea usando bytes() o bluetooth.UUID(), de esta manera:

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

Por ejemplo, la función gestora del IRQ para un resultado de escaneo podría inspeccionar adv_data para decidir si es el dispositivo correcto, y solo entonces copiar los datos de la dirección para usarlos en otra parte del programa. Y para imprimir datos desde dentro de la función gestora del IRQ, será necesario print(bytes(addr)).

Una función gestora normalmente actúa según el código del evento y desempaqueta la tupla de carga útil específica del 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
        ...

A continuación se listan todos los códigos de evento, la carga útil que entregan y una breve descripción. Para los eventos cuyo campo status se menciona, status es 0 en caso de éxito y un valor distinto de cero específico de la implementación en caso de fallo.

Constante

Valor

Evento

Tupla de carga útil

_IRQ_CENTRAL_CONNECT

1

Un central se ha conectado a este periférico.

(conn_handle, addr_type, addr)

_IRQ_CENTRAL_DISCONNECT

2

Un central se ha desconectado de este periférico.

(conn_handle, addr_type, addr)

_IRQ_GATTS_WRITE

3

Un cliente conectado ha escrito en una característica o descriptor local. Use gatts_read para obtener el nuevo valor.

(conn_handle, attr_handle)

_IRQ_GATTS_READ_REQUEST

4

Un cliente conectado ha emitido una lectura. Devuelva un código de error distinto de cero de la tabla siguiente para denegar la lectura, o 0 / None para aceptarla.

(conn_handle, attr_handle)

_IRQ_SCAN_RESULT

5

Se recibió un único paquete de publicidad durante un escaneo activo.

(addr_type, addr, adv_type, rssi, adv_data)

_IRQ_SCAN_DONE

6

El escaneo actual ha finalizado, ya sea porque transcurrió la duración configurada o porque se llamó a gap_scan(None).

()

_IRQ_PERIPHERAL_CONNECT

7

Una llamada previa a gap_connect ha tenido éxito.

(conn_handle, addr_type, addr)

_IRQ_PERIPHERAL_DISCONNECT

8

Un periférico conectado se ha desconectado.

(conn_handle, addr_type, addr)

_IRQ_GATTC_SERVICE_RESULT

9

Se encontró un servicio mediante gattc_discover_services.

(conn_handle, start_handle, end_handle, uuid)

_IRQ_GATTC_SERVICE_DONE

10

El descubrimiento de servicios ha finalizado.

(conn_handle, status)

_IRQ_GATTC_CHARACTERISTIC_RESULT

11

Se encontró una característica mediante gattc_discover_characteristics.

(conn_handle, end_handle, value_handle, properties, uuid)

_IRQ_GATTC_CHARACTERISTIC_DONE

12

El descubrimiento de características ha finalizado.

(conn_handle, status)

_IRQ_GATTC_DESCRIPTOR_RESULT

13

Se encontró un descriptor mediante gattc_discover_descriptors.

(conn_handle, dsc_handle, uuid)

_IRQ_GATTC_DESCRIPTOR_DONE

14

El descubrimiento de descriptores ha finalizado.

(conn_handle, status)

_IRQ_GATTC_READ_RESULT

15

Una llamada previa a gattc_read ha devuelto datos.

(conn_handle, value_handle, char_data)

_IRQ_GATTC_READ_DONE

16

Una llamada previa a gattc_read ha finalizado.

(conn_handle, value_handle, status)

_IRQ_GATTC_WRITE_DONE

17

Una llamada previa a gattc_write ha sido confirmada.

(conn_handle, value_handle, status)

_IRQ_GATTC_NOTIFY

18

Un servidor remoto ha enviado una notificación (sin confirmación).

(conn_handle, value_handle, notify_data)

_IRQ_GATTC_INDICATE

19

Un servidor remoto ha enviado una indicación (con confirmación).

(conn_handle, value_handle, notify_data)

_IRQ_GATTS_INDICATE_DONE

20

Una indicación enviada previamente ha sido confirmada por el cliente (o ha expirado).

(conn_handle, value_handle, status)

_IRQ_MTU_EXCHANGED

21

Se ha completado un intercambio de MTU de ATT (iniciado por cualquiera de los dos lados).

(conn_handle, mtu)

_IRQ_L2CAP_ACCEPT

22

Un dispositivo remoto ha solicitado una conexión L2CAP en un PSM en el que este dispositivo está escuchando. Devuelva un entero distinto de cero para rechazar, o 0 / None para aceptar.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_CONNECT

23

Un canal L2CAP está ahora establecido, ya sea aceptando una solicitud entrante o completando una llamada saliente a l2cap_connect.

(conn_handle, cid, psm, our_mtu, peer_mtu)

_IRQ_L2CAP_DISCONNECT

24

Un canal L2CAP se ha desconectado. status es 0 para una desconexión limpia, o distinto de cero si un intento de conexión saliente falló.

(conn_handle, cid, psm, status)

_IRQ_L2CAP_RECV

25

Han llegado datos a un canal L2CAP. Llame a l2cap_recvinto para leerlos.

(conn_handle, cid)

_IRQ_L2CAP_SEND_READY

26

Una llamada previa a l2cap_send que devolvió False se ha vaciado y el canal está listo de nuevo. Un status distinto de cero significa que el búfer de transmisión se desbordó y la aplicación debe reenviar los datos.

(conn_handle, cid, status)

_IRQ_CONNECTION_UPDATE

27

El dispositivo remoto ha actualizado los parámetros de conexión (intervalo, latencia, tiempo de espera de supervisión).

(conn_handle, conn_interval, conn_latency, supervision_timeout, status)

_IRQ_ENCRYPTION_UPDATE

28

El estado de cifrado de una conexión ha cambiado, normalmente después de que se completa el emparejamiento o el vinculado.

(conn_handle, encrypted, authenticated, bonded, key_size)

_IRQ_GET_SECRET

29

La pila está solicitando un secreto de vinculado almacenado. Si key es None, devuelva el index-ésimo valor almacenado de sec_type; en caso contrario, devuelva el valor asociado al par (sec_type, key) dado. Devuelva None si no hay nada almacenado.

(sec_type, index, key)

_IRQ_SET_SECRET

30

La pila pide a la aplicación que persista un secreto de vinculado. Devuelva True una vez almacenado.

(sec_type, key, value)

_IRQ_PASSKEY_ACTION

31

Se requiere una acción de clave de acceso (passkey) como parte del emparejamiento. Responda usando gap_passkey; consulte la tabla de acciones de clave de acceso más abajo para conocer las posibles acciones.

(conn_handle, action, passkey)

Para el evento _IRQ_GATTS_READ_REQUEST, los códigos de retorno disponibles son:

Constante

Valor

Significado

_GATTS_NO_ERROR

0x00

Acepta la lectura.

_GATTS_ERROR_READ_NOT_PERMITTED

0x02

Lectura no permitida.

_GATTS_ERROR_WRITE_NOT_PERMITTED

0x03

Escritura no permitida.

_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION

0x05

El cliente no está autenticado.

_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION

0x08

El cliente no está autorizado.

_GATTS_ERROR_INSUFFICIENT_ENCRYPTION

0x0f

El enlace no está cifrado.

Para el evento _IRQ_PASSKEY_ACTION, las acciones disponibles son:

Constante

Valor

Significado

_PASSKEY_ACTION_NONE

0

No se requiere ninguna acción.

_PASSKEY_ACTION_INPUT

2

Pide al usuario que introduzca la clave de acceso mostrada en el dispositivo remoto.

_PASSKEY_ACTION_DISPLAY

3

Muestra una clave de acceso de 6 dígitos para que la introduzca el dispositivo remoto.

_PASSKEY_ACTION_NUMERIC_COMPARISON

4

Confirma que la clave de acceso coincide con la mostrada en el dispositivo remoto.

Para ahorrar espacio en el firmware, estas constantes no están incluidas en el módulo bluetooth. Añada las que necesite, tomándolas de las listas anteriores, a su programa.

Rol de difusor (Advertiser)

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

Inicia la publicidad al intervalo especificado (en microsegundos). Este intervalo se redondeará hacia abajo al múltiplo de 625us más cercano. Para detener la publicidad, establezca interval_us en None.

adv_data y resp_data pueden ser de cualquier tipo que implemente el protocolo de búfer (p. ej., bytes, bytearray, str). adv_data se incluye en todas las difusiones, y resp_data se envía como respuesta a un escaneo activo.

Nota: si adv_data (o resp_data) es None, entonces se reutilizarán los datos pasados a la llamada anterior a gap_advertise. Esto permite que un difusor reanude la publicidad simplemente con gap_advertise(interval_us). Para borrar la carga útil de la publicidad, pase un bytes vacío, es decir, b''.

Rol de observador (Scanner)

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

Ejecuta una operación de escaneo que dura el tiempo especificado (en milisegundos).

Para escanear indefinidamente, establezca duration_ms en 0.

Para detener el escaneo, establezca duration_ms en None.

Use interval_us y window_us para configurar opcionalmente el ciclo de trabajo. El escáner se ejecutará durante window_us microsegundos cada interval_us microsegundos durante un total de duration_ms milisegundos. El intervalo y la ventana predeterminados son 1,28 segundos y 11,25 milisegundos respectivamente (escaneo en segundo plano).

Para cada resultado de escaneo se generará el evento _IRQ_SCAN_RESULT, con los datos de evento (addr_type, addr, adv_type, rssi, adv_data).

Los valores de addr_type indican direcciones públicas o aleatorias:

Valor

Nombre

Significado

0x00

PUBLIC

Dirección pública del dispositivo.

0x01

RANDOM

Dirección aleatoria (estática, RPA o NRPA; el tipo está codificado en la propia dirección).

Los valores de adv_type corresponden a la especificación Bluetooth:

Valor

Nombre

Significado

0x00

ADV_IND

Publicidad no dirigida conectable y escaneable.

0x01

ADV_DIRECT_IND

Publicidad dirigida conectable.

0x02

ADV_SCAN_IND

Publicidad no dirigida escaneable.

0x03

ADV_NONCONN_IND

Publicidad no dirigida no conectable.

0x04

SCAN_RSP

Respuesta de escaneo.

active se puede establecer en True si desea recibir respuestas de escaneo en los resultados.

Cuando el escaneo se detiene (ya sea porque finaliza la duración o cuando se detiene explícitamente), se generará el evento _IRQ_SCAN_DONE.

Rol central

Un dispositivo central puede conectarse a los periféricos que ha descubierto usando el rol de observador (consulte gap_scan) o con una dirección conocida.

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 a un periférico.

Consulte gap_scan para más detalles sobre los tipos de dirección.

Para cancelar anticipadamente un intento de conexión pendiente, llame a gap_connect(None).

En caso de éxito, se generará el evento _IRQ_PERIPHERAL_CONNECT. Si se cancela un intento de conexión, se generará el evento _IRQ_PERIPHERAL_DISCONNECT.

El dispositivo esperará hasta scan_duration_ms para recibir una carga útil de publicidad del dispositivo.

El intervalo de conexión se puede configurar en microsegundos usando uno o ambos de min_conn_interval_us y max_conn_interval_us. En caso contrario, se elegirá un intervalo predeterminado, normalmente entre 30000 y 50000 microsegundos. Un intervalo más corto aumentará el rendimiento, a expensas del consumo de energía.

Rol periférico

Se espera que un dispositivo periférico envíe publicidad conectable (consulte gap_advertise). Normalmente actuará como servidor GATT, habiendo registrado primero servicios y características usando gatts_register_services.

Cuando un central se conecta, se generará el evento _IRQ_CENTRAL_CONNECT.

Roles central y periférico

gap_disconnect(conn_handle: int, /) bool

Desconecta el identificador de conexión especificado. Este puede ser un central que se ha conectado a este dispositivo (si actúa como periférico) o un periférico al que este dispositivo se conectó previamente (si actúa como central).

En caso de éxito, se generará el evento _IRQ_PERIPHERAL_DISCONNECT o _IRQ_CENTRAL_DISCONNECT.

Devuelve False si el identificador de conexión no estaba conectado, y True en caso contrario.

Servidor GATT

Un servidor GATT tiene un conjunto de servicios registrados. Cada servicio puede contener características, cada una de las cuales tiene un valor. Las características también pueden contener descriptores, que a su vez tienen valores.

Estos valores se almacenan localmente y se acceden mediante su «value handle» que se genera durante el registro del servicio. También pueden ser leídos o escritos por un dispositivo cliente remoto. Además, un servidor puede «notificar» una característica a un cliente conectado mediante un identificador de conexión.

Un dispositivo en rol central o periférico puede funcionar como servidor GATT; sin embargo, en la mayoría de los casos será más común que un dispositivo periférico actúe como servidor.

Las características y los descriptores tienen un tamaño máximo predeterminado de 20 bytes (la MTU de ATT predeterminada de 23 bytes menos una cabecera ATT de 3 bytes; una MTU negociada más grande no eleva por sí sola este límite). Cualquier cosa que un cliente les escriba se truncará a esta longitud. Sin embargo, cualquier escritura local aumentará el tamaño máximo, así que si desea permitir escrituras más grandes desde un cliente a una característica dada, use gatts_write después del registro. P. ej., gatts_write(char_handle, bytes(100)).

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

Configura el servidor con los servicios especificados, reemplazando cualquier servicio existente.

services_definition es una lista de servicios, donde cada servicio es una tupla de dos elementos que contiene un UUID y una lista de características.

Cada característica es una tupla de dos o tres elementos que contiene un UUID, un valor de flags y, opcionalmente, una lista de descriptores.

Cada descriptor es una tupla de dos elementos que contiene un UUID y un valor de flags.

Los flags son una combinación con OR a nivel de bits de los flags definidos a continuación. Estos establecen tanto el comportamiento de la característica (o descriptor) como los requisitos de seguridad y privacidad.

El valor de retorno es una lista (un elemento por servicio) de tuplas (cada elemento es un value handle). Los identificadores de características y descriptores se aplanan en la misma tupla, en el orden en que están definidos.

El siguiente ejemplo registra dos servicios (Heart Rate y 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),
)

Los tres value handles (hr, tx, rx) se pueden usar con gatts_read, gatts_write, gatts_notify e gatts_indicate.

Nota: La publicidad debe detenerse antes de registrar servicios.

Los flags disponibles para características y descriptores son:

Constante

Valor

Significado

_FLAG_BROADCAST

0x0001

La característica puede difundirse.

_FLAG_READ

0x0002

El cliente puede leer el valor.

_FLAG_WRITE_NO_RESPONSE

0x0004

El cliente puede escribir sin esperar una respuesta.

_FLAG_WRITE

0x0008

El cliente puede escribir con una respuesta confirmada.

_FLAG_NOTIFY

0x0010

El servidor puede enviar notificaciones (sin confirmación).

_FLAG_INDICATE

0x0020

El servidor puede enviar indicaciones (con confirmación).

_FLAG_AUTHENTICATED_SIGNED_WRITE

0x0040

El cliente puede emitir escrituras firmadas.

_FLAG_AUX_WRITE

0x0100

Propiedades extendidas: se permiten escrituras en cola/fiables.

_FLAG_READ_ENCRYPTED

0x0200

La lectura requiere un enlace cifrado.

_FLAG_READ_AUTHENTICATED

0x0400

La lectura requiere un enlace autenticado (con protección MITM).

_FLAG_READ_AUTHORIZED

0x0800

La lectura requiere autorización a nivel de aplicación.

_FLAG_WRITE_ENCRYPTED

0x1000

La escritura requiere un enlace cifrado.

_FLAG_WRITE_AUTHENTICATED

0x2000

La escritura requiere un enlace autenticado (con protección MITM).

_FLAG_WRITE_AUTHORIZED

0x4000

La escritura requiere autorización a nivel de aplicación.

Al igual que con las constantes de evento anteriores, estos flags no son proporcionados por el módulo bluetooth; copie los que necesite en su programa.

gatts_read(value_handle: int, /) bytes

Lee el valor local de este handle (que ha sido escrito por gatts_write o por un cliente remoto).

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

Escribe el valor local de este handle, que puede ser leído por un cliente.

Si send_update es True, entonces se notificará (o indicará, según a qué estén suscritos y qué operaciones admita la característica) a los clientes suscritos sobre esta escritura.

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

Envía una solicitud de notificación a un cliente conectado.

Si data es None (el valor predeterminado), entonces se enviará el valor local actual (establecido con gatts_write).

En caso contrario, si data no es None, entonces ese valor se envía al cliente como parte de la notificación. El valor local no se modificará.

Nota: La notificación se enviará independientemente del estado de suscripción del cliente a esta característica.

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

Envía una solicitud de indicación a un cliente conectado.

Si data es None (el valor predeterminado), entonces se enviará el valor local actual (establecido con gatts_write).

En caso contrario, si data no es None, entonces ese valor se envía al cliente como parte de la indicación. El valor local no se modificará.

Tras la confirmación (o el fallo, p. ej., un tiempo de espera agotado), se generará el evento _IRQ_GATTS_INDICATE_DONE.

Nota: La indicación se enviará independientemente del estado de suscripción del cliente a esta característica.

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

Establece el tamaño del búfer interno para un valor en bytes. Esto limitará la mayor escritura posible que se puede recibir. El valor predeterminado es 20 bytes (MTU de ATT predeterminada de 23 menos la cabecera ATT de 3 bytes).

Establecer append en True hará que todas las escrituras remotas se añadan al valor actual, en lugar de reemplazarlo. Como máximo se pueden almacenar en búfer len bytes de esta manera. Cuando use gatts_read, el valor se borrará después de la lectura. Esta característica es útil al implementar algo como el Nordic UART Service.

Cliente GATT

Un cliente GATT puede descubrir y leer/escribir características en un servidor GATT remoto.

Es más común que un dispositivo en rol central actúe como cliente GATT; sin embargo, también es posible que un periférico actúe como cliente para descubrir información sobre el central que se ha conectado a él (p. ej., para leer el nombre del dispositivo del servicio de información del dispositivo).

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

Consulta a un servidor conectado por sus servicios.

Opcionalmente, especifique un uuid de servicio para consultar solo por ese servicio.

Para cada servicio descubierto, se generará el evento _IRQ_GATTC_SERVICE_RESULT, seguido de _IRQ_GATTC_SERVICE_DONE al finalizar.

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

Consulta a un servidor conectado por las características en el rango especificado.

Opcionalmente, especifique un uuid de característica para consultar solo por esa característica.

Pasar start_handle=1 y end_handle=0xffff cubre todo el rango de identificadores de atributos GATT, por lo que esta combinación busca efectivamente en todos los servicios del dispositivo remoto.

Para cada característica descubierta, se generará el evento _IRQ_GATTC_CHARACTERISTIC_RESULT, seguido de _IRQ_GATTC_CHARACTERISTIC_DONE al finalizar.

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

Consulta a un servidor conectado por los descriptores en el rango especificado.

Para cada descriptor descubierto, se generará el evento _IRQ_GATTC_DESCRIPTOR_RESULT, seguido de _IRQ_GATTC_DESCRIPTOR_DONE al finalizar.

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

Emite una lectura remota a un servidor conectado para el identificador de característica o descriptor especificado.

Cuando hay un valor disponible, se generará el evento _IRQ_GATTC_READ_RESULT, seguido de _IRQ_GATTC_READ_DONE al finalizar.

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

Emite una escritura remota a un servidor conectado para el identificador de característica o descriptor especificado.

El argumento mode especifica el comportamiento de la escritura, siendo los valores actualmente admitidos:

  • mode=0 (predeterminado) es una escritura sin respuesta: la escritura se enviará al servidor remoto pero no se devolverá ninguna confirmación, y no se generará ningún evento.

  • mode=1 es una escritura con respuesta: se solicita al servidor remoto que envíe una respuesta/confirmación de que recibió los datos.

Si se recibe una respuesta del servidor remoto, se generará el evento _IRQ_GATTC_WRITE_DONE.

gattc_exchange_mtu(conn_handle: int, /) None

Inicia el intercambio de MTU con un servidor conectado, usando la MTU preferida establecida mediante BLE.config(mtu=value).

El evento _IRQ_MTU_EXCHANGED se generará cuando se complete el intercambio de MTU.

El intercambio de MTU normalmente lo inicia el central; NimBLE admite ambos roles.

Canales L2CAP orientados a conexión

Esta característica permite el intercambio de datos similar a sockets entre dos dispositivos BLE. Una vez que los dispositivos están conectados vía GAP, cualquiera de ellos puede escuchar a la espera de que el otro se conecte en un PSM numérico (Protocol/Service Multiplexer).

Solo puede haber un canal L2CAP activo a la vez (es decir, no se puede conectar mientras se está escuchando).

Los canales L2CAP activos se identifican por el identificador de conexión sobre el que se establecieron y por un CID (identificador de canal).

Los canales orientados a conexión tienen un control de flujo basado en créditos incorporado. A diferencia de ATT, donde los dispositivos negocian una MTU compartida, tanto el dispositivo que escucha como el que se conecta establecen cada uno una MTU independiente que limita la cantidad máxima de datos pendientes que el dispositivo remoto puede enviar antes de que se consuman por completo en l2cap_recvinto.

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

Empieza a escuchar a la espera de solicitudes de canal L2CAP entrantes en el psm especificado, con la MTU local establecida en mtu.

Cuando un dispositivo remoto inicia una conexión, se generará el evento _IRQ_L2CAP_ACCEPT, que da al servidor que escucha la oportunidad de rechazar la conexión entrante (devolviendo un entero distinto de cero).

Una vez que se acepta la conexión, se generará el evento _IRQ_L2CAP_CONNECT, permitiendo al servidor obtener el identificador de canal (CID) y la MTU local y remota.

Nota: Actualmente no es posible dejar de escuchar.

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

Conecta a un par que está escuchando en el psm especificado, con la MTU local establecida en mtu.

Si la conexión tiene éxito, se generará el evento _IRQ_L2CAP_CONNECT, permitiendo al cliente obtener el CID y la MTU local y remota (del par).

Una conexión fallida generará el evento _IRQ_L2CAP_DISCONNECT con un estado distinto de cero.

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

Desconecta un canal L2CAP activo con el conn_handle y el cid especificados.

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

Envía el buf especificado (que debe admitir el protocolo de búfer) sobre el canal L2CAP identificado por conn_handle y cid.

El búfer debe satisfacer ambos límites: no debe superar la MTU remota (del par) y no debe superar el doble de la MTU local.

Esto devolverá False si el canal está ahora «detenido» (stalled), lo que significa que no se debe volver a llamar a l2cap_send hasta que se reciba el evento _IRQ_L2CAP_SEND_READY (lo que ocurrirá cuando el dispositivo remoto conceda más créditos, normalmente después de haber recibido y procesado los datos).

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

Recibe datos del conn_handle y cid especificados en el buf proporcionado (que debe admitir el protocolo de búfer, p. ej., bytearray o memoryview).

Devuelve el número de bytes leídos del canal.

Si buf es None, entonces devuelve el número de bytes disponibles.

Nota: Después de recibir el evento _IRQ_L2CAP_RECV, la aplicación debe seguir llamando a l2cap_recvinto hasta que no haya más bytes disponibles en el búfer de recepción (normalmente hasta el tamaño de la MTU remota, del par).

Hasta que el búfer de recepción esté vacío, no se concederán más créditos de canal al dispositivo remoto y este no podrá enviar más datos.

Emparejamiento y vinculado

El emparejamiento permite que una conexión sea cifrada y autenticada mediante el intercambio de secretos (con protección MITM opcional vía autenticación por clave de acceso).

El vinculado (bonding) es el proceso de almacenar esos secretos en almacenamiento no volátil. Cuando están vinculados, un dispositivo puede resolver una dirección privada resoluble (RPA) de otro dispositivo basándose en la clave de resolución de identidad (IRK) almacenada. Para admitir el vinculado, una aplicación debe implementar los eventos _IRQ_GET_SECRET y _IRQ_SET_SECRET.

gap_pair(conn_handle: int, /) None

Inicia el emparejamiento con el dispositivo remoto.

Antes de llamar a esto, asegúrese de que las opciones de configuración io, mitm, le_secure y bond estén establecidas (vía config).

Si el emparejamiento tiene éxito, se generará el evento _IRQ_ENCRYPTION_UPDATE.

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

Responde a un evento _IRQ_PASSKEY_ACTION para el conn_handle y la action especificados. El significado de passkey depende de action (que a su vez depende de la capacidad de E/S configurada):

Acción

Respuesta passkey requerida

_PASSKEY_ACTION_INPUT

La clave de acceso que el usuario lee del dispositivo remoto.

_PASSKEY_ACTION_DISPLAY

Una clave de acceso aleatoria de 6 dígitos generada localmente y mostrada al usuario.

_PASSKEY_ACTION_NUMERIC_COMPARISON

1 para aceptar la clave de acceso mostrada en el evento _IRQ_PASSKEY_ACTION, o 0 para cancelar el emparejamiento.

class UUID

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

Crea una instancia de UUID con el value especificado. Bluetooth usa tres anchos de UUID; UUID acepta cualquiera de ellos:

Ancho de UUID

Tipos de value aceptados

Ejemplo

16 bits

int o un búfer de 2 bytes (little-endian)

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

32 bits

búfer de 4 bytes (little-endian)

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

128 bits

búfer de 16 bytes o una cadena con guiones

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

Los UUID de 16 y 32 bits son normalmente identificadores asignados por el SIG (consulte los números asignados de Bluetooth); los UUID de 128 bits suelen ser definidos por el fabricante.