Skip to content

Commit d63d821

Browse files
committed
aioble/multitests: Add test for subscription and notification.
This replicates the failure described in #453 (which is fixed by #459. Also adds a test for subscription. Signed-off-by: Jim Mussared <[email protected]>
1 parent 9169ca6 commit d63d821

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Test notification-specific behavior.
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+
CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444")
18+
19+
20+
# Acting in peripheral role.
21+
async def instance0_task():
22+
service = aioble.Service(SERVICE_UUID)
23+
characteristic = aioble.Characteristic(
24+
service, CHAR_UUID, read=True, notify=True
25+
)
26+
aioble.register_services(service)
27+
28+
multitest.globals(BDADDR=aioble.config("mac"))
29+
multitest.next()
30+
31+
# Wait for central to connect to us.
32+
print("advertise")
33+
connection = await aioble.advertise(
34+
20_000, adv_data=b"\x02\x01\x06\x04\xffMPY", timeout_ms=TIMEOUT_MS
35+
)
36+
print("connected")
37+
38+
# Send a subscribed-write (but client isn't subscribed, won't send anything).
39+
multitest.wait("discovery")
40+
await asyncio.sleep_ms(100)
41+
characteristic.write("before-subscribe", send_update=True)
42+
43+
# Send a subscribed-write (now client is subscribed, client should get notified).
44+
multitest.wait("subscribed")
45+
await asyncio.sleep_ms(100)
46+
characteristic.write("after-subscribe", send_update=True)
47+
48+
# Send a subscribed-write (now client is unsubscribed, won't send anything).
49+
multitest.wait("unsubscribed")
50+
await asyncio.sleep_ms(100)
51+
characteristic.write("after-unsubscribe", send_update=True)
52+
53+
# Send 5 direct notifications.
54+
multitest.wait("start-direct")
55+
for i in range(5):
56+
# Send 1 notification each time, except for 3 quick notifications the third time.
57+
# The client should only see the last one.
58+
for j in range(3 if i == 2 else 1):
59+
if j > 0:
60+
await asyncio.sleep_ms(100)
61+
msg = "direct-{}-{}".format(i, j)
62+
print("notify", msg)
63+
characteristic.notify(connection, msg)
64+
65+
# Tell client to wait for notification.
66+
multitest.broadcast("notified")
67+
# Wait until client is ready for next notification.
68+
multitest.wait("next")
69+
70+
# Wait for the central to disconnect.
71+
await connection.disconnected(timeout_ms=TIMEOUT_MS)
72+
print("disconnected")
73+
74+
75+
def instance0():
76+
try:
77+
asyncio.run(instance0_task())
78+
finally:
79+
aioble.stop()
80+
81+
82+
# Acting in central role.
83+
async def instance1_task():
84+
multitest.next()
85+
86+
# Connect to peripheral and then disconnect.
87+
print("connect")
88+
device = aioble.Device(*BDADDR)
89+
connection = await device.connect(timeout_ms=TIMEOUT_MS)
90+
91+
# Discover characteristics.
92+
service = await connection.service(SERVICE_UUID)
93+
print("service", service.uuid)
94+
characteristic = await service.characteristic(CHAR_UUID)
95+
print("characteristic", characteristic.uuid)
96+
97+
98+
# Expect to not receive a notification (not subscribed).
99+
multitest.broadcast("discovery")
100+
try:
101+
await characteristic.notified(timeout_ms=500)
102+
print("fail")
103+
return
104+
except asyncio.TimeoutError:
105+
print("no notification")
106+
107+
# Subscribe and expect a notification.
108+
await characteristic.subscribe(notify=True)
109+
multitest.broadcast("subscribed")
110+
value = await characteristic.notified()
111+
print("notified", value)
112+
113+
# Unsubscribe, and expect not to receive a notification.
114+
await characteristic.subscribe(notify=False)
115+
multitest.broadcast("unsubscribed")
116+
try:
117+
await characteristic.notified(timeout_ms=500)
118+
print("fail")
119+
return
120+
except asyncio.TimeoutError:
121+
print("no notification")
122+
123+
# Receive 5 notifications.
124+
multitest.broadcast("start-direct")
125+
for i in range(5):
126+
multitest.wait("notified")
127+
await asyncio.sleep_ms(200)
128+
value = await characteristic.notified()
129+
print("notified", value)
130+
131+
# Expect that after receiving a notification we don't get another one
132+
# until we broadcast to the server.
133+
try:
134+
value = await characteristic.notified(timeout_ms=100)
135+
print("unexpected notify", value)
136+
except asyncio.TimeoutError:
137+
pass
138+
139+
multitest.broadcast("next")
140+
141+
# Disconnect from peripheral.
142+
print("disconnect")
143+
await connection.disconnect(timeout_ms=TIMEOUT_MS)
144+
print("disconnected")
145+
146+
147+
def instance1():
148+
try:
149+
asyncio.run(instance1_task())
150+
finally:
151+
aioble.stop()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--- instance0 ---
2+
advertise
3+
connected
4+
notify direct-0-0
5+
notify direct-1-0
6+
notify direct-2-0
7+
notify direct-2-1
8+
notify direct-2-2
9+
notify direct-3-0
10+
notify direct-4-0
11+
disconnected
12+
--- instance1 ---
13+
connect
14+
service UUID('a5a5a5a5-ffff-9999-1111-5a5a5a5a5a5a')
15+
characteristic UUID('00000000-1111-2222-3333-444444444444')
16+
no notification
17+
notified b'after-subscribe'
18+
no notification
19+
notified b'direct-0-0'
20+
notified b'direct-1-0'
21+
notified b'direct-2-2'
22+
notified b'direct-3-0'
23+
notified b'direct-4-0'
24+
disconnect
25+
disconnected

0 commit comments

Comments
 (0)