11.8. aioble-moduuli

Bluetooth Core -määrittely antaa sanaston, joka kuvautuu kahteen MicroPython-moduuliin.

  • bluetoothmatalan tason sidos BLE-ohjaimeen. Synkroninen, tapahtumaohjattu IRQ-tyylisen takaisinkutsun kautta ja rakennettu tavupuskureiden, kahvojen ja paljaiden GATT-primitiivien ympärille. Se paljastaa protokollan sellaisena kuin se on, ei sellaisena kuin Python-sovellukset haluavat sitä käyttää.

  • aioble – korkeamman tason kääre, kirjoitettu Pythonilla bluetooth-moduulin päälle, joka muuttaa jokaisen etäoperaation asyncio-korutiiniksi ja jokaisen BLE-olion (palvelut, ominaisuudet, yhteydet, skannaustulokset, L2CAP-kanavat) ergonomiseksi Python-luokaksi. Skannauksista tulee asynkronisia iteraattoreita; yhteyksistä asynkronisia kontekstinhallintoja; ilmoituksista odotettavia.

11.8.1. Milloin matalamman tason moduulia kannattaa käyttää

bluetooth on yhä oikea vastaus kahteen kapeaan tapaukseen:

  • Kirjoitat sellaista koodia, josta aioble itse on rakennettu – uusi malli, joka tarvitsee IRQ-tason hallintaa protokollasta.

  • Ajat laitteistokohteella, jossa aioble-paketti ei ole saatavilla, ja ohut välikerros ohjaimen ympärillä on ainoa vaihtoehto.

Jokaiseen kamerasovellukseen aioble on oikea vastaus.

11.8.2. aioble-ohjelman osat

Jokaisella aioble-pohjaisella sovelluksella on pieni joukko liikkuvia osia riippumatta siitä, mitä rooleja se toteuttaa.

  • Pitkäkestoinen asyncio-tapahtumasilmukka. Kaikki aioble-moduulissa on korutiini, joten sovellus on rakennettu yhdeksi tai useammaksi tehtäväksi yhdessä tapahtumasilmukassa. Katso Asyncio saadaksesi yksityiskohtaiset tiedot silmukasta, tehtävistä ja poikkeuksista.

  • Päällä oleva radio. aioble aktivoi BLE-radion implisiittisesti ensimmäisellä käytöllä, mutta sitä voi myös ohjata eksplisiittisesti funktiolla aioble.config() (joka välittää kutsun bluetooth.BLE.config()-metodille varmistettuaan, että radio on päällä) ja sammuttaa funktiolla aioble.stop().

  • Yksi tai useampi rooli käynnissä kerralla. Peripheral-puolella: rekisteröity joukko GATT-palveluja (katso aioble.register_services()) ja käynnissä oleva aioble.advertise()-korutiini. Central-puolella: käynnissä oleva aioble.scan()-iteraattori tai vireillä oleva aioble.Device.connect(). Radio multipleksoi työn; sovellus näkee jokaisen roolin itsenäisenä tehtävänä.

11.8.3. Minimaalinen peripheraali

Pienin hyödyllinen aioble-ohjelma – peripheraali, joka mainostaa yhtä vain luettavaa ominaisuutta – on lyhyt:

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())

Central, joka ei tee muuta kuin yhdistää ja lukee kerran, on yhtä lyhyt:

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())

Molemmat ohjelmat ovat noin viidentoista rivin mittaisia ja ne kattavat koko virran tilasta ”radio on pois päältä” tilaan ”hyödyllinen työ tehty”.

11.8.4. Radion sammuttaminen

Akkukäyttöisessä kamerassa BLE-radio on suurin harkinnanvarainen kuorma budjetissa. Kaksi nuppia on tärkeää.

Ensimmäinen on implisiittinen: aioble aktivoi radion ensimmäisellä käytöllä, ja radio nukkuu automaattisesti aikataulutettujen tapahtumien (mainospurskeet, yhteystapahtumat, skannausikkunat) välillä. Pidempien välien valitseminen funktioissa aioble.advertise() / aioble.scan() ja pidemmästä yhteysvälistä sopiminen connect()-hetkellä pitää radion pois päältä suhteellisesti suuremman osan ajasta. Mainostaulukko sivulla Mainostus ja skannaus on käytännön opas tähän.

Toinen on eksplisiittinen sammutus:

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() deaktivoi taustalla olevan BLE-radion ja purkaa kaiken kesken olevan – avoimet yhteydet katkeavat, skannerit ja mainostajat peruuntuvat, L2CAP-kanavat sulkeutuvat. Korutiinit, jotka odottivat noita operaatioita, nostavat tavanomaiset poikkeuksensa (DeviceDisconnectedError ja kumppanit), mikä on se siivousmekanismi, jota varten ympäröivät async with -lohkot on kirjoitettu. Minkä tahansa aioble-korutiinin kutsuminen jälkeenpäin aktivoi radion uudelleen kylmästä.

Tyypillinen malli jaksoittaiselle akkukäyttöiselle sensorikameralle on:

  • Herää aikataulun mukaan (ajastin, liikesensori, painike).

  • Aja BLE-työn purske – mainosta, hyväksy yhteys, työnnä arvo, katkaise yhteys.

  • Kutsu aioble.stop() ja nuku seuraavaan heräämiseen asti.

11.8.5. Mitä aioble ei tee

aioble kattaa tarkoituksella GATT:n, GAP:n ja L2CAP:in – ne kerrokset, joita sovellus käyttää. Kolme osaa on rajattu ulkopuolelle:

  • Mikä tahansa linkkikerroksen alapuolella. Kanavan valinta, taajuushyppely, pakettien kuittaukset ja linkkikerroksen salaus tapahtuvat kaikki BLE-portin ja ohjainpiin sisällä; aioble ei paljasta koukkuja tällä tasolla.

  • Klassinen Bluetooth. aioble on vain BLE. Audioyhteydet, RFCOMM, A2DP ja muut klassisen profiilin ominaisuudet eivät ole osa APIa.

  • Bluetooth Mesh. Bluetooth SIG:n mesh-verkkokerros (erillinen pino BLE-mainostuksen päällä) ei ole toteutettu kamerassa. Kamera voi mainostaa ja tarkkailla, mutta se ei voi osallistua mesh-verkon relay- / friend- / proxy-rooleihin.

11.8.6. Poikkeukset

Neljä poikkeustyyppiä tulee ulos aioble-moduulista. Jokainen laukeaa sellaisen korutiinin sisältä, joka oli odottamassa operaatiota, kun jokin meni pieleen; async with -lohkot purkautuvat siististi, kun ne etenevät.

  • aioble.DeviceDisconnectedError – BLE-linkki vertaislaitteeseen katkesi kesken GATT-operaation (read, write, notified, indicated, subscribe, exchange_mtu, …). Nostetaan sen korutiinin sisällä, joka oli odottamassa. Ylivoimaisesti yleisin poikkeus; nappaa se kaikessa koodissa, jonka tulisi yhdistää uudelleen menetyksen yhteydessä.

  • aioble.GattError – GATT-operaatio tavoitti vertaislaitteen mutta valmistui nollasta poikkeavalla ATT-tilalla (write-with-response hylätty, indicate ei kuitattu, read-not-permitted, …). Tilakoodi on poikkeuksen _status-attribuutissa.

  • aioble.L2CAPDisconnectedError – L2CAP-kanava katkesi kesken send()-, recvinto()- tai flush()-operaation. Joko jompikumpi puoli on sulkenut kanavan, tai taustalla oleva GAP-yhteys katosi.

  • aioble.L2CAPConnectionError – nostetaan l2cap_connect()-metodista, kun kuuntelija kieltäytyi tai ohjain epäonnistui kanavan muodostuksessa. Bluetooth-tilakoodi on ensimmäinen positionaalinen argumentti.

Operaatiot, jotka ottavat eksplisiittisen timeout_ms-arvon (connect- / discovery- / read- / write- / pair-kutsut sekä timeout() käärewrapperina) nostavat lisäksi asyncio.TimeoutError-poikkeuksen asyncio-moduulista, kun määräaika kuluu loppuun ennen operaation valmistumista.