11.8. Modul aioble

Spesifikasi Inti Bluetooth memberikan kosakata yang memetakan ke dua modul MicroPython.

  • bluetooth -- binding tingkat rendah ke controller BLE. Sinkron, berbasis event melalui callback bergaya IRQ, dan terstruktur di sekitar buffer byte, handle, dan primitif GATT dasar. Ia mengekspos protokol sebagaimana adanya, bukan sebagaimana yang diinginkan oleh aplikasi Python untuk dikonsumsi.

  • aioble -- pembungkus tingkat lebih tinggi, ditulis dalam Python di atas bluetooth, yang mengubah setiap operasi jarak jauh menjadi coroutine asyncio dan setiap objek BLE (layanan, karakteristik, koneksi, hasil pemindaian, saluran L2CAP) menjadi kelas Python yang ergonomis. Pemindaian menjadi async iterator; koneksi menjadi async context manager; notifikasi menjadi awaitable.

11.8.1. Kapan Menggunakan Modul Tingkat Rendah

bluetooth masih merupakan jawaban yang tepat untuk dua kasus sempit:

  • Anda sedang menulis jenis kode yang menjadi dasar pembangunan aioble itu sendiri -- pola baru yang membutuhkan kontrol tingkat IRQ atas protokol.

  • Anda menjalankan pada target hardware di mana paket aioble tidak tersedia, dan shim tipis di sekitar controller adalah satu-satunya pilihan.

Untuk setiap aplikasi kamera, aioble adalah jawaban yang tepat.

11.8.2. Komponen Program aioble

Setiap aplikasi berbasis aioble memiliki sekumpulan komponen yang bergerak, terlepas dari peran apa yang dimainkannya.

  • Event loop asyncio yang berjalan lama. Semua yang ada di aioble adalah coroutine, sehingga aplikasi terstruktur sebagai satu atau lebih task pada satu event loop. Lihat Asyncio untuk detail tentang loop, task, dan pengecualian.

  • Radio yang aktif. aioble mengaktifkan radio BLE secara implisit saat pertama kali digunakan, tetapi juga dapat dikontrol secara eksplisit dengan aioble.config() (yang meneruskan ke bluetooth.BLE.config() setelah memastikan radio aktif) dan dimatikan dengan aioble.stop().

  • Satu atau lebih peran yang berjalan sekaligus. Di sisi periferal: sekumpulan layanan GATT yang terdaftar (lihat aioble.register_services()) dan coroutine aioble.advertise() yang berjalan. Di sisi central: iterator aioble.scan() yang berjalan atau aioble.Device.connect() yang tertunda. Radio memultipleks pekerjaan; aplikasi melihat setiap peran sebagai task yang independen.

11.8.3. Periferal Minimal

Program aioble paling sederhana yang berguna -- sebuah periferal yang mengiklankan satu karakteristik hanya-baca -- sangat singkat:

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 yang tidak lebih dari sekadar terhubung dan membaca sekali juga sama singkatnya:

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

Kedua program terdiri dari sekitar lima belas baris dan mencakup seluruh alur dari "radio mati" hingga "pekerjaan berguna selesai".

11.8.4. Mematikan Radio

Pada kamera bertenaga baterai, radio BLE adalah pemakai daya diskresioner terbesar. Dua pengaturan penting.

Yang pertama bersifat implisit: aioble mengaktifkan radio saat pertama kali digunakan, dan radio tidur di antara event yang dijadwalkan (burst periklanan, event koneksi, jendela pemindaian) secara otomatis. Memilih interval yang lebih panjang pada aioble.advertise() / aioble.scan() dan menyepakati interval koneksi yang lebih panjang pada saat connect() membuat radio mati lebih banyak dari waktu ke waktu secara proporsional. Tabel periklanan di Periklanan dan Pemindaian adalah panduan praktisnya.

Yang kedua adalah penonaktifan eksplisit

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() menonaktifkan radio BLE yang mendasarinya dan meruntuhkan semua yang sedang berjalan -- koneksi terbuka terputus, pemindai dan pengiklan dibatalkan, saluran L2CAP ditutup. Coroutine yang menunggu operasi tersebut akan memunculkan pengecualian biasa mereka (DeviceDisconnectedError dan sejenisnya), yang merupakan mekanisme pembersihan untuk blok async with di sekitarnya. Memanggil coroutine aioble mana pun setelahnya akan mengaktifkan radio lagi dari kondisi dingin.

Pola khas untuk kamera sensor bertenaga baterai berkala adalah:

  • Bangun berdasarkan jadwal (timer, sensor gerak, tombol).

  • Jalankan rangkaian pekerjaan BLE -- iklankan, terima koneksi, dorong nilai, putuskan koneksi.

  • Panggil aioble.stop() dan tidur hingga bangun berikutnya.

11.8.5. Apa yang Tidak Dilakukan aioble

aioble secara sengaja mencakup GATT, GAP, dan L2CAP -- lapisan yang digunakan oleh aplikasi. Tiga hal berada di luar cakupan:

  • Apa pun di bawah lapisan tautan. Pemilihan saluran, frequency hopping, pengakuan paket, dan enkripsi lapisan tautan semuanya terjadi di dalam port BLE dan silicon controller; aioble tidak mengekspos hook pada tingkat itu.

  • Bluetooth Klasik. aioble hanya untuk BLE. Tautan audio, RFCOMM, A2DP, dan fitur profil klasik lainnya bukan bagian dari API.

  • Bluetooth Mesh. Lapisan jaringan mesh milik Bluetooth SIG (tumpukan terpisah di atas periklanan BLE) tidak diimplementasikan pada kamera. Kamera dapat mengiklankan dan mengamati, tetapi tidak dapat berpartisipasi dalam peran relay / friend / proxy pada jaringan mesh.

11.8.6. Pengecualian

Empat jenis pengecualian berasal dari aioble. Masing-masing dipicu dari dalam coroutine yang sedang menunggu sebuah operasi ketika terjadi kesalahan; blok async with terurai dengan bersih ketika pengecualian merambat.

  • aioble.DeviceDisconnectedError -- tautan BLE ke peer terputus saat operasi GATT (read, write, notified, indicated, subscribe, exchange_mtu, ...) sedang berlangsung. Dimunculkan di dalam coroutine mana pun yang sedang menunggu. Pengecualian yang paling umum sejauh ini; tangkap di kode mana pun yang harus terhubung kembali saat kehilangan koneksi.

  • aioble.GattError -- operasi GATT berhasil menjangkau peer tetapi selesai dengan status ATT yang tidak nol (write-with-response ditolak, indicate tidak diakui, read-not-permitted, ...). Kode status ada pada atribut _status pengecualian.

  • aioble.L2CAPDisconnectedError -- saluran L2CAP terputus saat send(), recvinto(), atau flush() sedang berlangsung. Salah satu sisi mungkin telah menutup saluran, atau koneksi GAP yang mendasarinya menghilang.

  • aioble.L2CAPConnectionError -- dimunculkan oleh l2cap_connect() ketika pendengar menolak atau controller gagal dalam pengaturan saluran. Kode status Bluetooth adalah argumen posisional pertama.

Operasi yang mengambil timeout_ms eksplisit (panggilan connect / discovery / read / write / pair, ditambah timeout() sebagai pembungkus) juga memunculkan asyncio.TimeoutError dari asyncio ketika batas waktu habis sebelum operasi selesai.