aioble — BLE asíncrono¶
aioble es un envoltorio de alto nivel compatible con asyncio alrededor del módulo bluetooth. Proporciona corrutinas limpias para escanear, conectar, anunciar, servicios GATT y canales L2CAP.
Todas las operaciones remotas (conectar, desconectar, lectura/escritura del cliente, indicación del servidor, recepción/envío de l2cap, emparejamiento) son awaitable y admiten tiempos de espera.
Roles admitidos:
Broadcaster (anunciante) — genera cargas útiles de anuncio y de respuesta de escaneo para campos comunes, divide automáticamente la carga útil entre el anuncio y la respuesta de escaneo, anuncia indefinidamente o durante una duración fija.
Peripheral — espera la conexión de un central, espera el intercambio de MTU.
Observer (escáner) — escaneo pasivo y activo, combina las cargas útiles de anuncio y de respuesta de escaneo del mismo dispositivo, analiza los campos comunes de las cargas útiles de anuncio.
Central — se conecta a un periférico, inicia el intercambio de MTU.
Cliente GATT — descubre servicios / características / descriptores (opcionalmente por UUID); lee / escribe / escribe-con-respuesta en características y descriptores; se suscribe a notificaciones e indicaciones (a través del CCCD); espera notificaciones e indicaciones.
Servidor GATT — registra servicios / características / descriptores; espera escrituras en características y descriptores; intercepta solicitudes de lectura; envía notificaciones e indicaciones (y espera la respuesta).
L2CAP — acepta y conecta canales L2CAP orientados a conexión, gestiona el control de flujo del canal.
Seguridad — gestión de claves/secretos respaldada por JSON, inicia el emparejamiento, consulta el estado de cifrado / autenticación.
Ejemplos¶
Escanea dispositivos BLE cercanos e imprime cada uno a medida que se detecta:
import aioble
import asyncio
async def find_devices():
async with aioble.scan(duration_ms=5000, active=True) as scanner:
async for result in scanner:
print(result.device.addr_hex(), result.rssi, result.name())
asyncio.run(find_devices())
Conéctate como central a un periférico que anuncia el servicio Heart Rate y suscríbete a sus notificaciones de medición:
import aioble
import asyncio
import bluetooth
_HR_SERVICE = bluetooth.UUID(0x180D)
_HR_MEASUREMENT = bluetooth.UUID(0x2A37)
async def connect_and_read():
device = None
async with aioble.scan(duration_ms=5000, active=True) as scanner:
async for result in scanner:
if _HR_SERVICE in result.services():
device = result.device
break
if device is None:
return
async with await device.connect() as conn:
service = await conn.service(_HR_SERVICE)
char = await service.characteristic(_HR_MEASUREMENT)
await char.subscribe(notify=True)
while True:
data = await char.notified()
print("notify:", data)
asyncio.run(connect_and_read())
Actúa como peripheral: registra un servicio GATT, anúncialo y envía notificaciones a quien se conecte:
import aioble
import asyncio
import bluetooth
import struct
_ENV_SERVICE = bluetooth.UUID(0x181A)
_TEMP_CHAR = bluetooth.UUID(0x2A6E)
def encode_temperature(deg_c):
# Bluetooth Temperature (0x2A6E) is sint16 little-endian, 0.01 degC units.
return struct.pack("<h", round(deg_c * 100))
service = aioble.Service(_ENV_SERVICE)
temp_char = aioble.Characteristic(service, _TEMP_CHAR, read=True, notify=True)
aioble.register_services(service)
async def peripheral_task():
while True:
connection = await aioble.advertise(
interval_us=250000,
name="openmv-sensor",
services=[_ENV_SERVICE],
appearance=0x0300,
)
print("connected:", connection.device.addr_hex())
async with connection:
while connection.is_connected():
temp_char.write(encode_temperature(23.68), send_update=True)
await asyncio.sleep(1)
asyncio.run(peripheral_task())
Funciones a nivel de módulo¶
- aioble.config(*args, **kwargs) Any¶
Reenvía a
bluetooth.BLE.config(), asegurándose primero de que la radio BLE esté activa.- args
Nombre de un único parámetro opcional a consultar.
- kwargs
Argumentos de palabra clave para establecer valores de configuración.
- aioble.stop() None¶
Desactiva la radio BLE subyacente y ejecuta los manejadores de apagado de submódulos registrados. Después de llamar a esto, los escáneres, anunciantes, conexiones y canales L2CAP se desmontan todos.
- aioble.scan(duration_ms: int, interval_us: int | None = None, window_us: int | None = None, active: bool = False) scan¶
Devuelve un gestor de contexto asíncrono / iterador asíncrono
scanque produce instancias deScanResultpor cada dispositivo único descubierto (o por cada nueva pieza de datos de anuncio de un dispositivo conocido).- duration_ms
Cuánto tiempo escanear, en milisegundos. Pasa
0para escanear indefinidamente hasta que el gestor de contexto salga.- interval_us
Intervalo de escaneo en microsegundos. El valor predeterminado es 1.280.000.
- window_us
Ventana de escaneo en microsegundos (debe ser menor o igual que interval_us). El valor predeterminado es 11.250.
- active
Si es
True, realiza un escaneo activo (solicita datos de respuesta de escaneo). El valor predeterminado esFalse.
- aioble.advertise(interval_us: int, adv_data: bytes | None = None, resp_data: bytes | None = None, connectable: bool = True, limited_disc: bool = False, br_edr: bool = False, name: str | None = None, services: list | None = None, appearance: int = 0, manufacturer: tuple | None = None, timeout_ms: int | None = None) DeviceConnection¶
Corrutina asíncrona que comienza a anunciar y espera una conexión central entrante. Devuelve una
DeviceConnectionque representa el central conectado, o lanzaasyncio.TimeoutErrorsi se agota el tiempo de espera.- interval_us
Intervalo de anuncio, en microsegundos.
- adv_data
Carga útil de anuncio en bruto. Si no se establece, adv_data se construye a partir de los argumentos de palabra clave restantes.
- resp_data
Carga útil de respuesta de escaneo en bruto. Se rellena automáticamente con el desbordamiento de adv_data si es necesario.
- connectable
Si es
True, este es un anuncio conectable.- limited_disc
Usa la bandera de descubrimiento limitado en lugar de la general.
- br_edr
Establece la bandera de soporte de BR/EDR.
- name
Nombre local completo opcional a incrustar.
- services
Iterable de
bluetooth.UUIDa anunciar.- appearance
Valor de apariencia de 16 bits (consulta los números asignados de Bluetooth).
- manufacturer
Tupla de
(company_id, data_bytes)a anunciar como datos específicos del fabricante.- timeout_ms
Deja de anunciar después de tantos milisegundos sin una conexión.
Nonesignifica anunciar hasta que se conecte.
Constantes a nivel de módulo¶
- aioble.ADDR_PUBLIC¶
Tipo de dirección de dispositivo BLE pública (
0).
- aioble.ADDR_RANDOM¶
Tipo de dirección de dispositivo BLE aleatoria (
1).
Excepciones¶
- exception aioble.GattError¶
Se lanza cuando una operación GATT remota (lectura / escritura / indicación) se completa con un estado distinto de cero. El código de estado está disponible en el atributo
_status.
- exception aioble.DeviceDisconnectedError¶
Se lanza dentro de una operación asíncrona (p. ej. read, write, notified) cuando la conexión subyacente se cae mientras se espera.
- exception aioble.L2CAPDisconnectedError¶
Se lanza cuando se intenta una operación de envío/recepción/vaciado de un canal L2CAP sobre (o es interrumpida por) un canal desconectado.
- exception aioble.L2CAPConnectionError¶
La lanza
DeviceConnection.l2cap_connectcuando falla el establecimiento del canal. El código de estado de Bluetooth es el primer argumento.
Clases¶
- class aioble.Device(addr_type: int, addr: bytes | str)¶
Representa un dispositivo BLE remoto por dirección. Dos instancias de
Devicese consideran iguales si coinciden tanto addr_type como addr. Se usa como manejador para iniciar conexiones.- addr_type
- addr
Dirección de seis bytes como
bytes, o una cadena hexadecimal separada por dos puntos (p. ej."aa:bb:cc:dd:ee:ff").
- addr_type¶
El tipo de dirección con el que se construyó el dispositivo.
- addr¶
La dirección de dispositivo en bruto de seis bytes.
- addr_hex() str¶
Devuelve la dirección formateada como una cadena hexadecimal separada por dos puntos.
- connect(timeout_ms: int = 10000, scan_duration_ms: int | None = None, min_conn_interval_us: int | None = None, max_conn_interval_us: int | None = None) Awaitable[DeviceConnection]¶
Asíncrono. Inicia una conexión GAP a este dispositivo y devuelve la
DeviceConnectionresultante. Cancela cualquier escaneo en progreso.- timeout_ms
Cuánto tiempo esperar a que se complete la conexión.
- scan_duration_ms
Duración inicial del escaneo antes de conectar (específico del controlador).
- min_conn_interval_us / max_conn_interval_us
Límites opcionales del intervalo de conexión, en microsegundos.
- class aioble.DeviceConnection¶
Una conexión GAP activa a un
Device. La devuelvenDevice.connect()oadvertise. Admite su uso como gestor de contextoasync withque se desconecta automáticamente al salir.No la construyas directamente.
- encrypted¶
Trueuna vez que el enlace está cifrado (p. ej. después del emparejamiento).
- authenticated¶
Truesi el enlace fue autenticado (emparejamiento protegido contra MITM).
- bonded¶
Truesi el emparejamiento produjo claves de vinculación (bonding).
- key_size¶
Tamaño de la clave de cifrado negociada en bytes, o
Falsesi no está cifrada.
- mtu¶
MTU de ATT negociada después de
exchange_mtu, oNonehasta que se establezca.
- disconnect(timeout_ms: int = 2000) Awaitable[None]¶
Asíncrono. Desconecta y espera la IRQ de desconexión.
- timeout_ms
Tiempo máximo a esperar para la desconexión.
- disconnected(timeout_ms: int | None = None, disconnect: bool = False) Awaitable[None]¶
Asíncrono. Espera a que la conexión sea terminada por cualquiera de las partes. Si disconnect es
True, desconecta activamente primero.- timeout_ms
Tiempo máximo a esperar.
Nonesignifica esperar para siempre.- disconnect
Si es
True, inicia la desconexión.
- timeout(timeout_ms: int | None) DeviceTimeout¶
Devuelve un gestor de contexto que cancela su cuerpo si transcurre el tiempo de espera (lanzando
asyncio.TimeoutError) o si el dispositivo se desconecta (lanzandoDeviceDisconnectedError).- timeout_ms
Tiempo de espera en milisegundos, o
Nonepara sin tiempo de espera.
- exchange_mtu(mtu: int | None = None, timeout_ms: int = 1000) Awaitable[int]¶
Asíncrono. Inicia un intercambio de MTU de ATT y devuelve la MTU negociada.
- mtu
MTU preferida opcional a establecer en la interfaz BLE subyacente antes del intercambio.
- timeout_ms
Tiempo de espera para el intercambio.
- service(uuid: bluetooth.UUID, timeout_ms: int = 2000) Awaitable[ClientService | None]¶
Asíncrono. Descubre un único servicio remoto que coincida con uuid, o
Nonesi no se encuentra.
- services(uuid: bluetooth.UUID | None = None, timeout_ms: int = 2000) ClientDiscover¶
Devuelve un iterador asíncrono de objetos
ClientServiceremotos. Úsalo conasync fory ejecuta el bucle hasta completarlo.- uuid
Filtro de UUID opcional.
Nonedevuelve todos los servicios.- timeout_ms
Tiempo de espera por descubrimiento.
- pair(bond: bool = True, le_secure: bool = True, mitm: bool = False, io: int = 3, timeout_ms: int = 20000) Awaitable[None]¶
Asíncrono. Inicia el emparejamiento en esta conexión. Actualiza los atributos
encrypted/authenticated/bonded/key_sizecuando se completa.- bond
Conserva las claves de emparejamiento.
- le_secure
Usa LE Secure Connections.
- mitm
Requiere protección contra ataques de intermediario (man-in-the-middle).
- io
Constante de capacidad de E/S (p. ej.
3para sin entrada/salida).- timeout_ms
Tiempo de espera del emparejamiento.
- l2cap_accept(psm: int, mtu: int, timeout_ms: int | None = None) Awaitable[L2CAPChannel]¶
Asíncrono. Escucha en el PSM dado y devuelve un
L2CAPChanneluna vez que el remoto lo abre.- psm
Multiplexor de Protocolo/Servicio (PSM) en el que escuchar.
- mtu
Tamaño máximo de recepción, en bytes.
- timeout_ms
Tiempo máximo a esperar a que el remoto se conecte.
- l2cap_connect(psm: int, mtu: int, timeout_ms: int = 1000) Awaitable[L2CAPChannel]¶
Asíncrono. Abre un canal L2CAP al remoto en el PSM dado.
- psm
Multiplexor de Protocolo/Servicio (PSM) al que conectar.
- mtu
Tamaño máximo de recepción, en bytes.
- timeout_ms
Tiempo de espera de la conexión.
- class aioble.ScanResult¶
Un único dispositivo descubierto durante
scan. La misma instancia se vuelve a producir a medida que llegan nuevos datos de anuncio.No la construyas directamente.
- rssi¶
Último RSSI reportado, en dBm.
- adv_data¶
Carga útil de anuncio en bruto (
bytesoNone).
- resp_data¶
Carga útil de respuesta de escaneo en bruto (
bytesoNone), si el escaneo activo está habilitado.
- connectable¶
Truesi el anuncio más reciente era conectable.
- name() str | None¶
Decodifica el nombre local anunciado completo (o abreviado) de la carga útil, o
Nonesi no está presente.
- services() Iterator[bluetooth.UUID]¶
Generador que produce cada
bluetooth.UUIDanunciado en los campos de lista de servicios de 16/32/128 bits.
- class aioble.Service(uuid: bluetooth.UUID)¶
Un servicio GATT local. Construye un servicio con una o más instancias de
Characteristic, luego pásalo aregister_services.- uuid
El UUID del servicio.
- uuid¶
El UUID del servicio.
- characteristics¶
Lista de objetos
Characteristicvinculados a este servicio.
- class aioble.Characteristic(service: Service, uuid: bluetooth.UUID, read: bool = False, write: bool = False, write_no_response: bool = False, notify: bool = False, indicate: bool = False, initial: bytes | None = None, capture: bool = False)¶
Una característica GATT local. Construir una la añade automáticamente a service.
- service
El
Servicepropietario.- uuid
El UUID de la característica.
- read, write, write_no_response, notify, indicate
Booleanos que seleccionan las operaciones GATT admitidas.
- initial
Valor inicial opcional (
bytes).- capture
Si es
True, los valores escritos se ponen en cola (hasta 10 de profundidad) para que las escrituras rápidas consecutivas no se pierdan. Cada llamada awrittendevuelve entonces una tupla(connection, data).
- uuid¶
El UUID de la característica.
- flags¶
Máscara de bits de las banderas de propiedad GATT construidas a partir del constructor.
- descriptors¶
Lista de objetos
Descriptorvinculados a esta característica.
- write(data: bytes, send_update: bool = False) None¶
Actualiza el valor en la base de datos GATT local.
- data
Bytes del nuevo valor.
- send_update
Si es
True, también notifica/indica a cada conexión suscrita.
- notify(connection: DeviceConnection, data: bytes | None = None) None¶
Envía una Notify GATT a connection.
- connection
La conexión de cliente de destino.
- data
Carga útil a enviar. Si es
None, se envía el valor local actual.
- indicate(connection: DeviceConnection, data: bytes | None = None, timeout_ms: int = 1000) Awaitable[None]¶
Asíncrono. Envía una Indicate GATT a connection y espera la confirmación del cliente. Lanza
GattErrorante un estado distinto de cero.- connection
La conexión de cliente de destino.
- data
Carga útil a indicar, o
Nonepara enviar el valor local.- timeout_ms
Tiempo máximo a esperar la confirmación.
- written(timeout_ms: int | None = None) Awaitable[DeviceConnection | tuple[DeviceConnection, bytes]]¶
Asíncrono. Espera una escritura remota. Devuelve la
DeviceConnectionque escribe, o(connection, data)si la característica se creó concapture=True.- timeout_ms
Tiempo máximo a esperar.
Noneespera para siempre.
- on_read(connection: DeviceConnection) int¶
Hook sobrescribible invocado de forma síncrona cuando se recibe una lectura remota. Devuelve
0para permitir la lectura o un código de error ATT distinto de cero para rechazarla. La implementación predeterminada devuelve0.
- class aioble.BufferedCharacteristic(service: Service, uuid: bluetooth.UUID, max_len: int = 20, append: bool = False, **kwargs)¶
Una
Characteristiccuyo búfer GATT de respaldo puede configurarse. Útil para recibir valores más grandes que el tamaño de atributo predeterminado, o para poner en cola escrituras consecutivas.- max_len
Tamaño del búfer, en bytes.
- append
Si es
True, las escrituras secuenciales se añaden al búfer en lugar de sobrescribirlo.
Otros argumentos se reenvían a
Characteristic.
- class aioble.Descriptor(characteristic: Characteristic, uuid: bluetooth.UUID, read: bool = False, write: bool = False, initial: bytes | None = None)¶
Un descriptor GATT local. Construir uno lo añade automáticamente a characteristic. Hereda
read,writeywrittendeCharacteristic.- characteristic
La
Characteristicpropietaria.- uuid
El UUID del descriptor.
- read, write
Booleanos que seleccionan las operaciones GATT admitidas.
- initial
Valor inicial opcional (
bytes).
- class aioble.ClientService¶
Un servicio GATT remoto descubierto en un par. Lo devuelve
DeviceConnection.service()o se itera desdeDeviceConnection.services().No la construyas directamente.
- connection¶
La
DeviceConnectionpropietaria.
- uuid¶
El UUID del servicio remoto.
- characteristic(uuid: bluetooth.UUID, timeout_ms: int = 2000) Awaitable[ClientCharacteristic | None]¶
Asíncrono. Descubre una única característica por UUID, o
Nonesi no se encuentra.
- characteristics(uuid: bluetooth.UUID | None = None, timeout_ms: int = 2000) ClientDiscover¶
Devuelve un iterador asíncrono de objetos
ClientCharacteristic. Úsalo conasync fory ejecuta el bucle hasta completarlo.- uuid
Filtro de UUID opcional.
- timeout_ms
Tiempo de espera por descubrimiento.
- class aioble.ClientCharacteristic¶
Una característica GATT remota descubierta en un par. La devuelve
ClientService.characteristic()o se itera desdeClientService.characteristics().No la construyas directamente.
- service¶
El
ClientServicepropietario.
- uuid¶
El UUID de la característica.
- properties¶
Máscara de bits de las operaciones GATT admitidas según las reporta el par.
- read(timeout_ms: int = 1000) Awaitable[bytes]¶
Asíncrono. Emite una Read GATT y devuelve el valor. Lanza
GattErrorante un estado distinto de cero.- timeout_ms
Tiempo de espera de lectura.
- write(data: bytes, response: bool | None = None, timeout_ms: int = 1000) Awaitable[None]¶
Asíncrono. Emite una Write GATT.
- data
Valor a escribir.
- response
Truepara requerir una respuesta de escritura (y lanzarGattErroren caso de fallo).Falsepara escritura-sin-respuesta.None(predeterminado) selecciona automáticamente según lo que anuncie el par.- timeout_ms
Tiempo de espera de escritura (solo relevante si response es
True).
- notified(timeout_ms: int | None = None) Awaitable[bytes]¶
Asíncrono. Espera la siguiente notificación en esta característica y devuelve su carga útil. Regresa inmediatamente si ya hay una notificación en cola.
- timeout_ms
Tiempo máximo a esperar.
Noneespera para siempre.
- indicated(timeout_ms: int | None = None) Awaitable[bytes]¶
Asíncrono. Espera la siguiente indicación en esta característica y devuelve su carga útil.
- timeout_ms
Tiempo máximo a esperar.
- subscribe(notify: bool = True, indicate: bool = False) Awaitable[None]¶
Asíncrono. Escribe el Client Characteristic Configuration Descriptor (CCCD) para suscribirse (o cancelar la suscripción) a notificaciones y/o indicaciones.
- notify
Habilita las notificaciones.
- indicate
Habilita las indicaciones.
- descriptor(uuid: bluetooth.UUID, timeout_ms: int = 2000) Awaitable[ClientDescriptor | None]¶
Asíncrono. Descubre un único descriptor por UUID, o
Nonesi no se encuentra.
- descriptors(timeout_ms: int = 2000) ClientDiscover¶
Devuelve un iterador asíncrono de objetos
ClientDescriptor. Úsalo conasync fory ejecuta el bucle hasta completarlo.
- class aioble.ClientDescriptor¶
Un descriptor GATT remoto descubierto en un par. Hereda
readywritedeClientCharacteristic.No la construyas directamente.
- characteristic¶
La
ClientCharacteristicpropietaria.
- uuid¶
El UUID del descriptor.
- class aioble.L2CAPChannel¶
Un canal L2CAP activo orientado a conexión. Lo devuelve
DeviceConnection.l2cap_accept()oDeviceConnection.l2cap_connect(). Admite su uso como gestor de contextoasync withque se desconecta automáticamente al salir.No la construyas directamente.
- our_mtu¶
Tamaño máximo, en bytes, que el par puede enviarnos en un solo SDU.
- peer_mtu¶
Tamaño máximo, en bytes, que podemos enviar al par en un solo SDU.
- available() bool¶
Devuelve de forma síncrona
Truesi hay datos de recepción almacenados en búfer listos (es decir,recvintono se bloqueará).
- recvinto(buf: bytearray, timeout_ms: int | None = None) Awaitable[int]¶
Asíncrono. Recibe en buf, devolviendo el número de bytes leídos. Espera nuevos datos si el canal está vacío.
- buf
Búfer preasignado a rellenar.
- timeout_ms
Tiempo máximo a esperar.
Noneespera para siempre.
- send(buf: bytes, timeout_ms: int | None = None, chunk_size: int | None = None) Awaitable[None]¶
Asíncrono. Envía buf por el canal, fragmentando las cargas útiles más grandes en trozos del tamaño de la MTU. Espera créditos de control de flujo según sea necesario.
- buf
Objeto de tipo bytes a enviar.
- timeout_ms
Tiempo máximo a esperar por trozo.
- chunk_size
Anulación opcional para el tamaño de trozo por llamada. Limitado a
min(our_mtu * 2, peer_mtu).
- flush(timeout_ms: int | None = None) Awaitable[None]¶
Asíncrono. Espera hasta que cualquier
sendestancado haya sido drenado por el controlador.- timeout_ms
Tiempo máximo a esperar.