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.