Skip to content

Commit 6ed6afb

Browse files
authored
Merge branch 'micropython:master' into master
2 parents 6f7ba06 + e025c84 commit 6ed6afb

File tree

10 files changed

+244
-18
lines changed

10 files changed

+244
-18
lines changed

micropython/bluetooth/aioble-server/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
metadata(version="0.3.0")
1+
metadata(version="0.4.1")
22

33
require("aioble-core")
44

micropython/bluetooth/aioble/README.md

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Alternatively, install the `aioble` package, which will install everything.
7070
Usage
7171
-----
7272

73-
Passive scan for nearby devices for 5 seconds: (Observer)
73+
#### Passive scan for nearby devices for 5 seconds: (Observer)
7474

7575
```py
7676
async with aioble.scan(duration_ms=5000) as scanner:
@@ -87,7 +87,7 @@ async with aioble.scan(duration_ms=5000, interval_us=30000, window_us=30000, act
8787
print(result, result.name(), result.rssi, result.services())
8888
```
8989

90-
Connect to a peripheral device: (Central)
90+
#### Connect to a peripheral device: (Central)
9191

9292
```py
9393
# Either from scan result
@@ -101,7 +101,7 @@ except asyncio.TimeoutError:
101101
print('Timeout')
102102
```
103103

104-
Register services and wait for connection: (Peripheral, Server)
104+
#### Register services and wait for connection: (Peripheral, Server)
105105

106106
```py
107107
_ENV_SENSE_UUID = bluetooth.UUID(0x181A)
@@ -126,30 +126,95 @@ while True:
126126
print("Connection from", device)
127127
```
128128

129-
Update characteristic value: (Server)
129+
#### Update characteristic value: (Server)
130130

131131
```py
132+
# Write the local value.
132133
temp_char.write(b'data')
134+
```
135+
136+
```py
137+
# Write the local value and notify/indicate subscribers.
138+
temp_char.write(b'data', send_update=True)
139+
```
140+
141+
#### Send notifications: (Server)
133142

134-
temp_char.notify(b'optional data')
143+
```py
144+
# Notify with the current value.
145+
temp_char.notify(connection)
146+
```
135147

136-
await temp_char.indicate(timeout_ms=2000)
148+
```py
149+
# Notify with a custom value.
150+
temp_char.notify(connection, b'optional data')
137151
```
138152

139-
Query the value of a characteristic: (Client)
153+
#### Send indications: (Server)
154+
155+
```py
156+
# Indicate with current value.
157+
await temp_char.indicate(connection, timeout_ms=2000)
158+
```
159+
160+
```py
161+
# Indicate with custom value.
162+
await temp_char.indicate(connection, b'optional data', timeout_ms=2000)
163+
```
164+
165+
This will raise `GattError` if the indication is not acknowledged.
166+
167+
#### Wait for a write from the client: (Server)
168+
169+
```py
170+
# Normal characteristic, returns the connection that did the write.
171+
connection = await char.written(timeout_ms=2000)
172+
```
173+
174+
```py
175+
# Characteristic with capture enabled, also returns the value.
176+
char = Characteristic(..., capture=True)
177+
connection, data = await char.written(timeout_ms=2000)
178+
```
179+
180+
#### Query the value of a characteristic: (Client)
140181

141182
```py
142183
temp_service = await connection.service(_ENV_SENSE_UUID)
143184
temp_char = await temp_service.characteristic(_ENV_SENSE_TEMP_UUID)
144185

145186
data = await temp_char.read(timeout_ms=1000)
187+
```
188+
189+
#### Wait for a notification/indication: (Client)
190+
191+
```py
192+
# Notification
193+
data = await temp_char.notified(timeout_ms=1000)
194+
```
146195

196+
```py
197+
# Indication
198+
data = await temp_char.indicated(timeout_ms=1000)
199+
```
200+
201+
#### Subscribe to a characteristic: (Client)
202+
203+
```py
204+
# Subscribe for notification.
147205
await temp_char.subscribe(notify=True)
148206
while True:
149207
data = await temp_char.notified()
150208
```
151209

152-
Open L2CAP channels: (Listener)
210+
```py
211+
# Subscribe for indication.
212+
await temp_char.subscribe(indicate=True)
213+
while True:
214+
data = await temp_char.indicated()
215+
```
216+
217+
#### Open L2CAP channels: (Listener)
153218

154219
```py
155220
channel = await connection.l2cap_accept(_L2CAP_PSN, _L2CAP_MTU)
@@ -158,7 +223,7 @@ n = channel.recvinto(buf)
158223
channel.send(b'response')
159224
```
160225

161-
Open L2CAP channels: (Initiator)
226+
#### Open L2CAP channels: (Initiator)
162227

163228
```py
164229
channel = await connection.l2cap_connect(_L2CAP_PSN, _L2CAP_MTU)

micropython/bluetooth/aioble/aioble/server.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ def notify(self, connection, data=None):
257257
raise ValueError("Not supported")
258258
ble.gatts_notify(connection._conn_handle, self._value_handle, data)
259259

260-
async def indicate(self, connection, timeout_ms=1000):
260+
async def indicate(self, connection, data=None, timeout_ms=1000):
261261
if not (self.flags & _FLAG_INDICATE):
262262
raise ValueError("Not supported")
263263
if self._indicate_connection is not None:
@@ -270,7 +270,7 @@ async def indicate(self, connection, timeout_ms=1000):
270270

271271
try:
272272
with connection.timeout(timeout_ms):
273-
ble.gatts_indicate(connection._conn_handle, self._value_handle)
273+
ble.gatts_indicate(connection._conn_handle, self._value_handle, data)
274274
await self._indicate_event.wait()
275275
if self._indicate_status != 0:
276276
raise GattError(self._indicate_status)
@@ -290,8 +290,8 @@ def _indicate_done(conn_handle, value_handle, status):
290290

291291

292292
class BufferedCharacteristic(Characteristic):
293-
def __init__(self, service, uuid, max_len=20, append=False):
294-
super().__init__(service, uuid, read=True)
293+
def __init__(self, *args, max_len=20, append=False, **kwargs):
294+
super().__init__(*args, **kwargs)
295295
self._max_len = max_len
296296
self._append = append
297297

micropython/bluetooth/aioble/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# code. This allows (for development purposes) all the files to live in the
44
# one directory.
55

6-
metadata(version="0.3.1")
6+
metadata(version="0.4.1")
77

88
# Default installation gives you everything. Install the individual
99
# components (or a combination of them) if you want a more minimal install.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Test characteristic read/write/notify from both GATTS and GATTC.
2+
3+
import sys
4+
5+
sys.path.append("")
6+
7+
from micropython import const
8+
import time, machine
9+
10+
import uasyncio as asyncio
11+
import aioble
12+
import bluetooth
13+
14+
TIMEOUT_MS = 5000
15+
16+
SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A")
17+
CHAR1_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444")
18+
CHAR2_UUID = bluetooth.UUID("00000000-1111-2222-3333-555555555555")
19+
CHAR3_UUID = bluetooth.UUID("00000000-1111-2222-3333-666666666666")
20+
21+
22+
# Acting in peripheral role.
23+
async def instance0_task():
24+
service = aioble.Service(SERVICE_UUID)
25+
characteristic1 = aioble.BufferedCharacteristic(service, CHAR1_UUID, write=True)
26+
characteristic2 = aioble.BufferedCharacteristic(service, CHAR2_UUID, write=True, max_len=40)
27+
characteristic3 = aioble.BufferedCharacteristic(
28+
service, CHAR3_UUID, write=True, max_len=80, append=True
29+
)
30+
aioble.register_services(service)
31+
32+
multitest.globals(BDADDR=aioble.config("mac"))
33+
multitest.next()
34+
35+
# Wait for central to connect to us.
36+
print("advertise")
37+
connection = await aioble.advertise(
38+
20_000, adv_data=b"\x02\x01\x06\x04\xffMPY", timeout_ms=TIMEOUT_MS
39+
)
40+
print("connected")
41+
42+
# The first will just see the second write (truncated).
43+
await characteristic1.written(timeout_ms=TIMEOUT_MS)
44+
await characteristic1.written(timeout_ms=TIMEOUT_MS)
45+
print("written", characteristic1.read())
46+
47+
# The second will just see the second write (still truncated because MTU
48+
# exchange hasn't happened).
49+
await characteristic2.written(timeout_ms=TIMEOUT_MS)
50+
await characteristic2.written(timeout_ms=TIMEOUT_MS)
51+
print("written", characteristic2.read())
52+
53+
# MTU exchange should happen here.
54+
55+
# The second will now see the full second write.
56+
await characteristic2.written(timeout_ms=TIMEOUT_MS)
57+
await characteristic2.written(timeout_ms=TIMEOUT_MS)
58+
print("written", characteristic2.read())
59+
60+
# The third will see the two full writes concatenated.
61+
await characteristic3.written(timeout_ms=TIMEOUT_MS)
62+
await characteristic3.written(timeout_ms=TIMEOUT_MS)
63+
print("written", characteristic3.read())
64+
65+
# Wait for the central to disconnect.
66+
await connection.disconnected(timeout_ms=TIMEOUT_MS)
67+
print("disconnected")
68+
69+
70+
def instance0():
71+
try:
72+
asyncio.run(instance0_task())
73+
finally:
74+
aioble.stop()
75+
76+
77+
# Acting in central role.
78+
async def instance1_task():
79+
multitest.next()
80+
81+
# Connect to peripheral and then disconnect.
82+
print("connect")
83+
device = aioble.Device(*BDADDR)
84+
connection = await device.connect(timeout_ms=TIMEOUT_MS)
85+
86+
# Discover characteristics.
87+
service = await connection.service(SERVICE_UUID)
88+
print("service", service.uuid)
89+
characteristic1 = await service.characteristic(CHAR1_UUID)
90+
print("characteristic1", characteristic1.uuid)
91+
characteristic2 = await service.characteristic(CHAR2_UUID)
92+
print("characteristic2", characteristic2.uuid)
93+
characteristic3 = await service.characteristic(CHAR3_UUID)
94+
print("characteristic3", characteristic3.uuid)
95+
96+
# Write to each characteristic twice, with a long enough value to trigger
97+
# truncation.
98+
print("write1")
99+
await characteristic1.write(
100+
"central1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", response=True, timeout_ms=TIMEOUT_MS
101+
)
102+
await characteristic1.write(
103+
"central1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbb", response=True, timeout_ms=TIMEOUT_MS
104+
)
105+
print("write2a")
106+
await characteristic2.write(
107+
"central2a-aaaaaaaaaaaaaaaaaaaaaaaaaaaa", response=True, timeout_ms=TIMEOUT_MS
108+
)
109+
await characteristic2.write(
110+
"central2a-bbbbbbbbbbbbbbbbbbbbbbbbbbbb", response=True, timeout_ms=TIMEOUT_MS
111+
)
112+
print("exchange mtu")
113+
await connection.exchange_mtu(100)
114+
print("write2b")
115+
await characteristic2.write(
116+
"central2b-aaaaaaaaaaaaaaaaaaaaaaaaaaaa", response=True, timeout_ms=TIMEOUT_MS
117+
)
118+
await characteristic2.write(
119+
"central2b-bbbbbbbbbbbbbbbbbbbbbbbbbbbb", response=True, timeout_ms=TIMEOUT_MS
120+
)
121+
print("write3")
122+
await characteristic3.write(
123+
"central3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", response=True, timeout_ms=TIMEOUT_MS
124+
)
125+
await characteristic3.write(
126+
"central3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbb", response=True, timeout_ms=TIMEOUT_MS
127+
)
128+
129+
# Disconnect from peripheral.
130+
print("disconnect")
131+
await connection.disconnect(timeout_ms=TIMEOUT_MS)
132+
print("disconnected")
133+
134+
135+
def instance1():
136+
try:
137+
asyncio.run(instance1_task())
138+
finally:
139+
aioble.stop()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--- instance0 ---
2+
advertise
3+
connected
4+
written b'central1-bbbbbbbbbbb'
5+
written b'central2a-bbbbbbbbbb'
6+
written b'central2b-bbbbbbbbbbbbbbbbbbbbbbbbbbbb'
7+
written b'central3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaacentral3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
8+
disconnected
9+
--- instance1 ---
10+
connect
11+
service UUID('a5a5a5a5-ffff-9999-1111-5a5a5a5a5a5a')
12+
characteristic1 UUID('00000000-1111-2222-3333-444444444444')
13+
characteristic2 UUID('00000000-1111-2222-3333-555555555555')
14+
characteristic3 UUID('00000000-1111-2222-3333-666666666666')
15+
write1
16+
write2a
17+
exchange mtu
18+
write2b
19+
write3
20+
disconnect
21+
disconnected

python-ecosys/requests/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
metadata(version="0.8.0", pypi="requests")
1+
metadata(version="0.8.1", pypi="requests")
22

33
package("requests")

python-ecosys/requests/requests/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def request(
4545
parse_headers=True,
4646
):
4747
redirect = None # redirection url, None means no redirection
48-
chunked_data = data and getattr(data, "__iter__", None) and not getattr(data, "__len__", None)
48+
chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None)
4949

5050
if auth is not None:
5151
import ubinascii

python-stdlib/__future__/__future__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
with_statement = True
66
print_function = True
77
unicode_literals = True
8+
annotations = True

python-stdlib/__future__/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
metadata(version="0.0.3")
1+
metadata(version="0.1.0")
22

33
module("__future__.py")

0 commit comments

Comments
 (0)