11.8. Modul aioble#

Bluetooth Core specifikacija daje rječnik koji se preslikava na dva MicroPython modula.

  • bluetoothniskorazinska veza s BLE kontrolerom. Sinkrona, vođena događajima putem povratnog poziva u stilu IRQ-a, i strukturirana oko bajtnih međuspremnika, ručki i golih GATT primitiva. Izlaže protokol onakvim kakav jest, a ne onakvim kakvim ga Python aplikacije žele koristiti.

  • aioble – viši omotač, napisan u Pythonu povrh bluetooth, koji svaku udaljenu operaciju pretvara u asyncio korutinu, a svaki BLE objekt (usluge, karakteristike, veze, rezultate skeniranja, L2CAP kanale) u ergonomsku Python klasu. Skeniranja postaju asinkroni iteratori; veze postaju asinkroni upravitelji konteksta; obavijesti postaju čekljive.

11.8.1. Kada posegnuti za niskorazinskim modulom#

bluetooth je i dalje pravi odgovor za dva uska slučaja:

  • Pišete vrstu koda od koje je aioble sam izgrađen – novi obrazac kojemu treba kontrola protokola na razini IRQ-a.

  • Izvodite se na hardverskoj platformi gdje aioble paket nije dostupan, a tanak sloj oko kontrolera jedina je opcija.

Za svaku aplikaciju kamere, aioble je pravi odgovor.

11.8.2. Dijelovi aioble programa#

Svaka aplikacija temeljena na aioble ima mali skup pokretnih dijelova, bez obzira na to koje uloge igra.

  • Dugotrajna asyncio petlja događaja. Sve u aioble je korutina, pa je aplikacija strukturirana kao jedan ili više zadataka na jednoj petlji događaja. Pogledajte Asyncio za petlju, zadatke i iznimke u detalje.

  • Radio koji je uključen. aioble implicitno aktivira BLE radio pri prvoj upotrebi, ali se njime može i eksplicitno upravljati pomoću aioble.config() (koja prosljeđuje bluetooth.BLE.config() nakon što osigura da je radio uključen) te ga ugasiti pomoću aioble.stop().

  • Jedna ili više uloga u tijeku istovremeno. Na strani periferije: registrirani skup GATT usluga (pogledajte aioble.register_services()) i pokrenuta aioble.advertise() korutina. Na centralnoj strani: pokrenuti aioble.scan() iterator ili neriješeni aioble.Device.connect(). Radio multipleksira posao; aplikacija vidi svaku ulogu kao neovisan zadatak.

11.8.3. Minimalna periferija#

Najmanji koristan aioble program – periferija koja oglašava jednu karakteristiku samo za čitanje – kratak je:

import aioble
import asyncio
import bluetooth

SERVICE_UUID = bluetooth.UUID(0x181A)            # Environmental Sensing
TEMP_UUID = bluetooth.UUID(0x2A6E)               # Temperature

service = aioble.Service(SERVICE_UUID)
temp = aioble.Characteristic(service, TEMP_UUID, read=True)
aioble.register_services(service)

async def main():
    while True:
        conn = await aioble.advertise(
            interval_us=250000,
            name="openmv-temp",
            services=[SERVICE_UUID],
        )
        async with conn:
            await conn.disconnected()

asyncio.run(main())

Centralni uređaj koji ne radi ništa više od povezivanja i jednokratnog čitanja jednako je kratak:

import aioble
import asyncio
import bluetooth

SERVICE_UUID = bluetooth.UUID(0x181A)
TEMP_UUID = bluetooth.UUID(0x2A6E)

async def main():
    device = None
    async with aioble.scan(duration_ms=5000, active=True) as scanner:
        async for result in scanner:
            if SERVICE_UUID in result.services():
                device = result.device
                break
    if device is None:
        return

    async with await device.connect() as conn:
        service = await conn.service(SERVICE_UUID)
        char = await service.characteristic(TEMP_UUID)
        print(await char.read())

asyncio.run(main())

Oba programa imaju oko petnaest redaka i pokrivaju cijeli tijek od „radio je isključen” do „koristan posao obavljen”.

11.8.4. Isključivanje radija#

Na kameri napajanoj baterijom BLE radio je najveći diskrecijski potrošač u proračunu. Bitne su dvije ručice.

Prva je implicitna: aioble aktivira radio pri prvoj upotrebi, a radio automatski spava između zakazanih događaja (praskovi oglašavanja, događaji veze, prozori skeniranja). Odabir duljih intervala na aioble.advertise() / aioble.scan() i dogovor o duljem intervalu veze u trenutku connect() razmjerno više vremena drži radio isključenim. Tablica oglašavanja u Oglašavanje i skeniranje ovdje je praktični vodič.

Druga je eksplicitno isključivanje:

import aioble

await do_burst_of_ble_work()
aioble.stop()                             # radio deactivated; in-flight tasks unwound
await asyncio.sleep(60)                   # sleep with the radio off
# ... next aioble call brings the radio back up automatically

aioble.stop() deaktivira temeljni BLE radio i ruši sve što je u tijeku – otvorene veze prekidaju se, skeneri i oglašivači otkazuju, L2CAP kanali zatvaraju. Korutine koje su čekale na te operacije podižu svoje uobičajene iznimke (DeviceDisconnectedError i srodne), što je mehanizam čišćenja za koji su okolni async with blokovi i napisani. Pozivanje bilo koje aioble korutine nakon toga ponovno aktivira radio iz hladnog stanja.

Tipičan obrazac za povremenu senzorsku kameru napajanu baterijom je:

  • Buđenje po rasporedu (mjerač vremena, senzor pokreta, tipka).

  • Pokretanje praska BLE posla – oglašavanje, prihvaćanje veze, slanje vrijednosti, prekid veze.

  • Pozivanje aioble.stop() i spavanje do sljedećeg buđenja.

11.8.5. Što aioble ne radi#

aioble namjerno pokriva GATT, GAP i L2CAP – slojeve koje aplikacija koristi. Tri dijela izvan su opsega:

  • Bilo što ispod sloja veze. Odabir kanala, frekvencijsko preskakanje, potvrde paketa i šifriranje na sloju veze sve se odvija unutar BLE porta i silicija kontrolera; aioble ne izlaže kuke na toj razini.

  • Klasični Bluetooth. aioble je samo za BLE. Audio veze, RFCOMM, A2DP i druge značajke klasičnog profila nisu dio API-ja.

  • Bluetooth Mesh. Sloj mrežne arhitekture mreže Bluetooth SIG-a (zaseban stog povrh BLE oglašavanja) nije implementiran na kameri. Kamera može oglašavati i promatrati, ali ne može sudjelovati u ulogama releja / prijatelja / proxyja mrežne mreže.

11.8.6. Iznimke#

Iz aioble izlaze četiri tipa iznimki. Svaka se pokreće iznutra iz korutine koja je čekala operaciju kada je nešto pošlo po zlu; async with blokovi čisto se razmotavaju kada se one šire.

  • aioble.DeviceDisconnectedError – BLE veza s ravnopravnim uređajem prekinula se dok je GATT operacija (read, write, notified, indicated, subscribe, exchange_mtu, …) bila u tijeku. Podiže se unutar one korutine koja je čekala. Daleko najčešća iznimka; uhvatite je u svakom kodu koji bi se trebao ponovno povezati pri gubitku.

  • aioble.GattError – GATT operacija dosegnula je ravnopravni uređaj, ali je završila s ATT statusom različitim od nule (zapisivanje s odgovorom odbijeno, indiciranje nije potvrđeno, čitanje nije dopušteno, …). Statusni kod nalazi se na atributu _status iznimke.

  • aioble.L2CAPDisconnectedError – L2CAP kanal prekinuo se dok je send(), recvinto() ili flush() bila u tijeku. Ili je jedna strana zatvorila kanal, ili je nestala temeljna GAP veza.

  • aioble.L2CAPConnectionError – podiže je l2cap_connect() kada je slušatelj odbio ili kada kontroler nije uspio postaviti kanal. Bluetooth statusni kod je prvi pozicijski argument.

Operacije koje uzimaju eksplicitni timeout_ms (pozivi za povezivanje / otkrivanje / čitanje / pisanje / uparivanje, plus timeout() kao omotač) dodatno podižu asyncio.TimeoutError iz asyncio kada rok istekne prije nego što se operacija završi.