micropython-lib/micropython/bluetooth/aioble/multitests/ble_pair.py

149 wiersze
3.8 KiB
Python

# Test BLE GAP pairing and bonding with aioble
import sys
# ruff: noqa: E402
sys.path.append("")
from micropython import const
import machine
import time
import asyncio
import aioble
import bluetooth
TIMEOUT_MS = 5000
SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A")
CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444")
_FLAG_READ = const(0x0002)
_FLAG_READ_ENCRYPTED = const(0x0200)
# For aioble, we need to directly use the low-level bluetooth API for encrypted characteristics
class EncryptedCharacteristic(aioble.Characteristic):
def __init__(self, service, uuid, **kwargs):
super().__init__(service, uuid, read=True, **kwargs)
# Override flags to add encryption requirement
self.flags |= _FLAG_READ_ENCRYPTED
# Acting in peripheral role.
async def instance0_task():
# Clear any existing bond state
import os
try:
os.remove("ble_secrets.json")
except:
pass
service = aioble.Service(SERVICE_UUID)
characteristic = EncryptedCharacteristic(service, CHAR_UUID)
aioble.register_services(service)
multitest.globals(BDADDR=aioble.config("mac"))
multitest.next()
# Write initial characteristic value.
characteristic.write("encrypted_data")
# Wait for central to connect to us.
print("advertise")
connection = await aioble.advertise(
20_000, adv_data=b"\x02\x01\x06\x04\xffMPY", timeout_ms=TIMEOUT_MS
)
print("connected")
# Wait for pairing to complete
print("wait_for_pairing")
start_time = time.ticks_ms()
while not connection.encrypted and time.ticks_diff(time.ticks_ms(), start_time) < TIMEOUT_MS:
await asyncio.sleep_ms(100)
# Give a small delay for bonding state to stabilize
await asyncio.sleep_ms(200)
if connection.encrypted:
print(
"paired encrypted=1 authenticated={} bonded={}".format(
1 if connection.authenticated else 0, 1 if connection.bonded else 0
)
)
else:
print("pairing_timeout")
# Wait for the central to disconnect.
await connection.disconnected(timeout_ms=TIMEOUT_MS)
print("disconnected")
def instance0():
try:
asyncio.run(instance0_task())
finally:
aioble.stop()
# Acting in central role.
async def instance1_task():
multitest.next()
# Clear any existing bond state
import os
try:
os.remove("ble_secrets.json")
except:
pass
# Connect to peripheral.
print("connect")
device = aioble.Device(*BDADDR)
connection = await device.connect(timeout_ms=TIMEOUT_MS)
# Discover characteristics (before pairing).
service = await connection.service(SERVICE_UUID)
print("service", service.uuid)
characteristic = await service.characteristic(CHAR_UUID)
print("characteristic", characteristic.uuid)
# Pair with the peripheral.
print("pair")
await connection.pair(
bond=False, # Don't bond for this test
le_secure=True,
mitm=False,
timeout_ms=TIMEOUT_MS,
)
# Give a small delay for bonding state to stabilize
await asyncio.sleep_ms(200)
print(
"paired encrypted={} authenticated={} bonded={}".format(
1 if connection.encrypted else 0,
1 if connection.authenticated else 0,
1 if connection.bonded else 0,
)
)
# Read the peripheral's characteristic, should be encrypted.
print("read_encrypted")
data = await characteristic.read(timeout_ms=TIMEOUT_MS)
print("read", data)
# Disconnect from peripheral.
print("disconnect")
await connection.disconnect(timeout_ms=TIMEOUT_MS)
print("disconnected")
def instance1():
try:
asyncio.run(instance1_task())
finally:
aioble.stop()