11.14. Penutup

Anda telah menelusuri Bluetooth Low Energy dari radio hingga Python API yang digunakan untuk menggerakkannya:

  • Motivasinya -- BLE adalah jawabannya ketika kamera ingin berbicara dengan sesuatu yang dekat tanpa infrastruktur di antaranya. Sebuah ponsel di ruangan yang sama, perangkat wearable di pergelangan tangan, sebuah beacon di dinding. Jangkauan pendek, tidak perlu bergabung dengan jaringan, hampir tidak menggunakan daya.

  • Radio -- 2,4 GHz, 40 saluran: tiga untuk advertising, 37 untuk data koneksi, dilompati dalam urutan pseudo-acak dengan penghindaran adaptif saluran yang bising. Paket singkat, radio yang sebagian besar dalam kondisi tidur.

  • Link layer -- pembingkaian paket, pengalamatan, penjadwalan koneksi, transmisi ulang, dan enkripsi link layer. Tidak ada yang dikonfigurasi dari Python; semuanya terlihat melalui parameter koneksi dan MTU.

  • Generic Access Profile (GAP) -- penemuan dan manajemen koneksi. Empat peran: peripheral dan broadcaster (advertise), central dan observer (scan). Payload advertising membawa nama lokal, UUID layanan, tampilan, dan data khusus pabrikan -- 31 byte ditambah respons scan opsional 31 byte. Interval koneksi, latensi peripheral, dan supervision timeout mengatur bagaimana koneksi terbuka terasa.

  • Generic Attribute Profile (GATT) -- pohon layanan, masing-masing memegang karakteristik, masing-masing secara opsional memegang deskriptor, diidentifikasi oleh UUID (16-bit untuk standar Bluetooth-SIG, 128-bit untuk yang kustom). Lima operasi: read dan write (pull, diprakarsai klien), notify dan indicate (push, diprakarsai server, dilanggani melalui Client Characteristic Configuration Descriptor). Ukuran payload dibatasi oleh MTU yang dinegosiasikan.

  • Python API -- aioble mengubah setiap pola BLE menjadi coroutine asyncio. Peripheral adalah aioble.advertise() yang berputar pada koneksi, dengan objek Service / Characteristic yang dibuat sekali dan di-commit oleh aioble.register_services(). Central adalah aioble.scan() untuk menemukan peer, connect() untuk membuka link, service() dan characteristic() untuk menelusuri pohon GATT jarak jauh, kemudian read() / write() / subscribe() / notified() untuk data aktual. Pemutusan koneksi muncul sebagai aioble.DeviceDisconnectedError di dalam coroutine yang sedang menunggu.

  • Saluran L2CAP -- pintu keluar untuk stream byte massal yang tidak cocok dengan model key/value GATT. aioble.DeviceConnection.l2cap_accept() / l2cap_connect() membuka saluran per-aplikasi di atas koneksi GAP, dengan send / recv yang dikontrol aliran kredit dan MTU yang lebih besar dari yang bisa dibawa GATT.

  • Pairing dan enkripsi -- link BLE bersifat publik secara default. aioble.DeviceConnection.pair() memulai pertukaran kunci yang menghasilkan link terenkripsi; bond=True (default) menyimpan kunci sehingga koneksi berikutnya melewati handshake. Tanpa mitm=True dan kemampuan IO yang dapat digunakan, enkripsi melindungi dari penyadap pasif tetapi tidak terhadap redirect aktif selama pairing asli.

Itu sudah cukup untuk menulis aplikasi kamera yang menerbitkan status sebagai peripheral, membaca data sensor sebagai central, mendorong nilai langsung ke ponsel melalui BLE, mengamankan link dengan langkah pair-and-bond, dan -- untuk kasus transfer massal yang jarang -- meninggalkan GATT menuju saluran L2CAP.

11.14.1. Pemecahan masalah

Kegagalan BLE sebagian besar merupakan ketidakcocokan antara apa yang diharapkan oleh kedua sisi, dan inspektor di sisi ponsel adalah cara tercepat untuk melihat siapa yang harapannya meleset. Alat standarnya adalah nRF Connect for Mobile (Nordic Semiconductor, gratis di Android dan iOS): ia melakukan scan, menghubungkan, menelusuri database GATT, membaca dan menulis karakteristik, serta berlangganan notifikasi -- sehingga perilaku sisi kamera dapat diuji secara terpisah, tanpa menulis aplikasi pendamping sama sekali.

Mode kegagalan yang umum:

  • "Perangkat saya muncul di pemindai tetapi tidak mau terhubung." Paling sering paket advertising memiliki connectable=False (mode broadcaster), atau koneksi sebelumnya masih terbuka dan cam sudah melewati aioble.advertise(). Tambahkan pernyataan print di sekitar panggilan advertise untuk mengkonfirmasi.

  • "exchange_mtu(512) sudah berjalan tetapi notifikasi saya masih terbatas pada 20 byte." MTU yang dinegosiasikan adalah min(local, peer) -- ponsel atau pustaka central mungkin tidak meminta MTU yang lebih besar di sisinya, sehingga koneksi tetap di 23. Periksa mtu setelah exchange_mtu() mengembalikan nilai. Juga perlu diingat bahwa exchange_mtu() hanya bekerja sekali per koneksi; panggil sebelum operasi besar pertama.

  • "Pairing gagal dengan error umum." Dua penyebab biasa: ketidakcocokan kemampuan IO (meminta mitm=True pada cam yang mendeklarasikan io=3 / tanpa input tanpa output -- tidak ada cara untuk mengkonfirmasi kode numerik, sehingga mesin pairing berhenti), dan waktu jam dinding yang sangat salah pada cam ketika peer memerlukannya. Atur jam dengan ntptime.settime() sebelum percobaan pairing pertama.

  • "Notifikasi tidak pernah sampai di klien." Dua hal yang perlu diperiksa, secara berurutan: (a) apakah karakteristik dideklarasikan dengan notify=True? -- bit properti harus diset di sisi server; (b) apakah klien memanggil subscribe()? -- tanpa menulis Client Characteristic Configuration Descriptor (CCCD), server diberitahu bahwa tidak ada klien yang menginginkan notifikasi dan secara diam-diam membuangnya.

  • "Nama yang diiklankan terpotong atau hilang." Payload advertising berukuran 31 byte, dan flags + service-UUID + bidang appearance masing-masing mengambil byte dari atas. name= yang panjang ditambah beberapa UUID layanan menyebabkan overflow. Persingkat nama atau gunakan pemindaian aktif sehingga respons scan (31 byte lainnya) membawa overflow tersebut. nRF Connect menampilkan kedua bagian secara terpisah, yang membuat pembagiannya jelas.

  • "L2CAP connect langsung menimbulkan error." Biasanya ketidakcocokan PSM -- kedua sisi harus menyepakati nomor PSM yang sama di luar band. L2CAPConnectionError membawa kode status Bluetooth sebagai argumen pertamanya; status 2 ("PSM not supported") adalah petunjuknya.

  • "Koneksi yang di-bond masih memicu handshake pairing penuh pada setiap reconnect." aioble.security.load_secrets() tidak dipanggil saat startup. Tanpanya, kunci yang tersimpan ada di flash tetapi tidak pernah dimuat ke memori, sehingga identitas peer tidak diketahui dan pairing berjalan dari awal setiap saat.

Ketika semua cara lain gagal, modul bluetooth tingkat rendah mengekspos callback IRQ yang terpicu untuk setiap event yang mendasarinya; berlangganan secara singkat dan mencetak event tersebut adalah setara dengan trace Wireshark untuk sisi cam.

11.14.2. Menggunakan referensi ini nanti

Perlakukan bab-bab Bluetooth sebagai materi referensi; kembali untuk melihat tata letak yang tepat dari payload advertising peripheral atau alur scan-and-subscribe central adalah penggunaan yang dimaksudkan. Halaman referensi aioble --- Async BLE dan bluetooth --- Bluetooth tingkat rendah mencantumkan setiap metode, flag, dan konstanta di satu tempat ketika pertanyaannya hanya "apa nama persis dari panggilan ini".