Skip to content

Commit c4a30fb

Browse files
committed
aioble: Add asyncio-based wrapper for ubluetooth.
Signed-off-by: Jim Mussared <[email protected]>
1 parent f7f38ff commit c4a30fb

21 files changed

+2884
-0
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
aioble
2+
======
3+
4+
This library provides an object-oriented, asyncio-based wrapper for MicroPython's [ubluetooth](https://docs.micropython.org/en/latest/library/ubluetooth.html) API.
5+
6+
**Note**: aioble requires MicroPython v1.15 or higher.
7+
8+
Features
9+
--------
10+
11+
Broadcaster (advertiser) role:
12+
* Generate advertising and scan response payloads for common fields.
13+
* Automatically split payload over advertising and scan response.
14+
* Start advertising (indefinitely or for duration).
15+
16+
Peripheral role:
17+
* Wait for connection from central.
18+
* Wait for MTU exchange.
19+
20+
Observer (scanner) role:
21+
* Scan for devices (passive + active).
22+
* Combine advertising and scan response payloads for the same device.
23+
* Parse common fields from advertising payloads.
24+
25+
Central role:
26+
* Connect to peripheral.
27+
* Initiate MTU exchange.
28+
29+
GATT Client:
30+
* Discover services, characteristics, and descriptors (optionally by UUID).
31+
* Read / write / write-with-response characters and descriptors.
32+
* Subscribe to notifications and indications on characteristics (via the CCCD).
33+
* Wait for notifications and indications.
34+
35+
GATT Server:
36+
* Register services, characteristics, and descriptors.
37+
* Wait for writes on characteristics and descriptors.
38+
* Intercept read requests.
39+
* Send notifications and indications (and wait on response).
40+
41+
L2CAP:
42+
* Accept and connect L2CAP Connection-oriented-channels.
43+
* Manage channel flow control.
44+
45+
Security:
46+
* JSON-backed key/secret management.
47+
* Initiate pairing.
48+
* Query encryption/authentication state.
49+
50+
All remote operations (connect, disconnect, client read/write, server indicate, l2cap recv/send, pair) are awaitable and support timeouts.
51+
52+
Usage
53+
-----
54+
55+
Scan for nearby devices: (Observer)
56+
57+
```py
58+
async with aioble.scan() as scanner:
59+
async for result in scanner:
60+
if result.name():
61+
print(result, result.name(), result.rssi, result.services())
62+
```
63+
64+
Connect to a peripheral device: (Central)
65+
66+
```py
67+
# Either from scan result
68+
device = result.device
69+
# Or with known address
70+
device = aioble.Device(aioble.PUBLIC, "aa:bb:cc:dd:ee:ff")
71+
72+
try:
73+
connection = await device.connect(timeout_ms=2000)
74+
except asyncio.TimeoutError:
75+
print('Timeout')
76+
```
77+
78+
Register services and wait for connection: (Peripheral, Server)
79+
80+
```py
81+
_ENV_SENSE_UUID = bluetooth.UUID(0x181A)
82+
_ENV_SENSE_TEMP_UUID = bluetooth.UUID(0x2A6E)
83+
_GENERIC_THERMOMETER = const(768)
84+
85+
_ADV_INTERVAL_MS = const(250000)
86+
87+
temp_service = aioble.Service(_ENV_SENSE_UUID)
88+
temp_char = aioble.Characteristic(temp_service, _ENV_SENSE_TEMP_UUID, read=True, notify=True)
89+
90+
aioble.register_services(temp_service)
91+
92+
while True:
93+
connection = await aioble.advertise(
94+
_ADV_INTERVAL_MS,
95+
name="temp-sense",
96+
services=[_ENV_SENSE_UUID],
97+
appearance=_GENERIC_THERMOMETER,
98+
manufacturer=(0xabcd, b"1234"),
99+
)
100+
print("Connection from", device)
101+
```
102+
103+
Update characteristic value: (Server)
104+
105+
```py
106+
temp_char.write(b'data')
107+
108+
temp_char.notify(b'optional data')
109+
110+
await temp_char.indicate(timeout_ms=2000)
111+
```
112+
113+
Query the value of a characteristic: (Client)
114+
115+
```py
116+
temp_service = await connection.service(_ENV_SENSE_UUID)
117+
temp_char = await temp_service.characteristic(_ENV_SENSE_TEMP_UUID)
118+
119+
data = await temp_char.read(timeout_ms=1000)
120+
121+
temp_char.subscribe(notify=True)
122+
while True:
123+
data = await temp_char.notified()
124+
```
125+
126+
Examples
127+
--------
128+
129+
See the `examples` directory for some example applications.
130+
131+
* temp_sensor.py: Temperature sensor peripheral.
132+
* temp_client.py: Connects to the temp sensor.
133+
* l2cap_file_server.py: Simple file server peripheral. (WIP)
134+
* l2cap_file_client.py: Client for the file server. (WIP)
135+
136+
Tests
137+
-----
138+
139+
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.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# MicroPython aioble module
2+
# MIT license; Copyright (c) 2021 Jim Mussared
3+
4+
from micropython import const
5+
6+
from .device import Device, DeviceDisconnectedError
7+
from .core import log_info, log_warn, log_error, GattError, config, stop
8+
9+
try:
10+
from .peripheral import advertise
11+
except:
12+
log_info("Peripheral support disabled")
13+
14+
try:
15+
from .central import scan
16+
except:
17+
log_info("Central support disabled")
18+
19+
try:
20+
from .server import (
21+
Service,
22+
Characteristic,
23+
BufferedCharacteristic,
24+
Descriptor,
25+
register_services,
26+
)
27+
except:
28+
log_info("GATT server support disabled")
29+
30+
31+
ADDR_PUBLIC = const(0)
32+
ADDR_RANDOM = const(1)

0 commit comments

Comments
 (0)