This library provides an object-oriented, asyncio-based wrapper for MicroPython's bluetooth API.
Note: aioble requires MicroPython v1.17 or higher.
Broadcaster (advertiser) role:
- Generate advertising and scan response payloads for common fields.
- Automatically split payload over advertising and scan response.
- Start advertising (indefinitely or for duration).
Peripheral role:
- Wait for connection from central.
- Wait for MTU exchange.
Observer (scanner) role:
- Scan for devices (passive + active).
- Combine advertising and scan response payloads for the same device.
- Parse common fields from advertising payloads.
Central role:
- Connect to peripheral.
- Initiate MTU exchange.
GATT Client:
- Discover services, characteristics, and descriptors (optionally by UUID).
- Read / write / write-with-response characters and descriptors.
- Subscribe to notifications and indications on characteristics (via the CCCD).
- Wait for notifications and indications.
GATT Server:
- Register services, characteristics, and descriptors.
- Wait for writes on characteristics and descriptors.
- Intercept read requests.
- Send notifications and indications (and wait on response).
L2CAP:
- Accept and connect L2CAP Connection-oriented-channels.
- Manage channel flow control.
Security:
- JSON-backed key/secret management.
- Initiate pairing.
- Query encryption/authentication state.
All remote operations (connect, disconnect, client read/write, server indicate, l2cap recv/send, pair) are awaitable and support timeouts.
You can install any combination of the following packages.
aioble-central
-- Central (and Observer) role functionality including scanning and connecting.aioble-client
-- GATT client, typically used by central role devices but can also be used on peripherals.aioble-l2cap
-- L2CAP Connection-oriented-channels support.aioble-peripheral
-- Peripheral (and Broadcaster) role functionality including advertising.aioble-security
-- Pairing and bonding support.aioble-server
-- GATT server, typically used by peripheral role devices but can also be used on centrals.
Alternatively, install the aioble
package, which will install everything.
async with aioble.scan(duration_ms=5000) as scanner:
async for result in scanner:
print(result, result.name(), result.rssi, result.services())
Active scan (includes "scan response" data) for nearby devices for 5 seconds with the highest duty cycle: (Observer)
async with aioble.scan(duration_ms=5000, interval_us=30000, window_us=30000, active=True) as scanner:
async for result in scanner:
print(result, result.name(), result.rssi, result.services())
# Either from scan result
device = result.device
# Or with known address
device = aioble.Device(aioble.PUBLIC, "aa:bb:cc:dd:ee:ff")
try:
connection = await device.connect(timeout_ms=2000)
except asyncio.TimeoutError:
print('Timeout')
_ENV_SENSE_UUID = bluetooth.UUID(0x181A)
_ENV_SENSE_TEMP_UUID = bluetooth.UUID(0x2A6E)
_GENERIC_THERMOMETER = const(768)
_ADV_INTERVAL_US = const(250000)
temp_service = aioble.Service(_ENV_SENSE_UUID)
temp_char = aioble.Characteristic(temp_service, _ENV_SENSE_TEMP_UUID, read=True, notify=True)
aioble.register_services(temp_service)
while True:
connection = await aioble.advertise(
_ADV_INTERVAL_US,
name="temp-sense",
services=[_ENV_SENSE_UUID],
appearance=_GENERIC_THERMOMETER,
manufacturer=(0xabcd, b"1234"),
)
print("Connection from", device)
# Write the local value.
temp_char.write(b'data')
# Write the local value and notify/indicate subscribers.
temp_char.write(b'data', send_update=True)
# Notify with the current value.
temp_char.notify(connection)
# Notify with a custom value.
temp_char.notify(connection, b'optional data')
# Indicate with current value.
await temp_char.indicate(connection, timeout_ms=2000)
# Indicate with custom value.
await temp_char.indicate(connection, b'optional data', timeout_ms=2000)
This will raise GattError
if the indication is not acknowledged.
# Normal characteristic, returns the connection that did the write.
connection = await char.written(timeout_ms=2000)
# Characteristic with capture enabled, also returns the value.
char = Characteristic(..., capture=True)
connection, data = await char.written(timeout_ms=2000)
temp_service = await connection.service(_ENV_SENSE_UUID)
temp_char = await temp_service.characteristic(_ENV_SENSE_TEMP_UUID)
data = await temp_char.read(timeout_ms=1000)
# Notification
data = await temp_char.notified(timeout_ms=1000)
# Indication
data = await temp_char.indicated(timeout_ms=1000)
# Subscribe for notification.
await temp_char.subscribe(notify=True)
while True:
data = await temp_char.notified()
# Subscribe for indication.
await temp_char.subscribe(indicate=True)
while True:
data = await temp_char.indicated()
channel = await connection.l2cap_accept(_L2CAP_PSN, _L2CAP_MTU)
buf = bytearray(64)
n = channel.recvinto(buf)
channel.send(b'response')
channel = await connection.l2cap_connect(_L2CAP_PSN, _L2CAP_MTU)
channel.send(b'request')
buf = bytearray(64)
n = channel.recvinto(buf)
See the examples
directory for some example applications.
- temp_sensor.py: Temperature sensor peripheral.
- temp_client.py: Connects to the temp sensor.
- l2cap_file_server.py: Simple file server peripheral. (WIP)
- l2cap_file_client.py: Client for the file server. (WIP)
The multitests
directory provides tests that can be run with MicroPython's run-multitests.py
script. These are based on the existing multi_bluetooth
tests that are in the main repo.