11.14. Tổng kết¶
Bạn đã đi qua Bluetooth Low Energy từ tầng radio cho đến API Python được sử dụng để điều khiển nó:
Động lực -- BLE là câu trả lời khi camera muốn giao tiếp với thứ gì đó ở gần mà không cần cơ sở hạ tầng trung gian. Một chiếc điện thoại trong cùng phòng, một thiết bị đeo trên cổ tay, một beacon trên tường. Tầm ngắn, không cần mạng để tham gia, gần như không tốn năng lượng.
Tầng radio -- 2.4 GHz, 40 kênh: ba kênh để quảng bá, 37 kênh cho dữ liệu kết nối, nhảy tần theo chuỗi giả ngẫu nhiên với cơ chế tránh thích nghi các kênh ồn. Các gói tin ngắn, radio hầu hết ở trạng thái ngủ.
Tầng liên kết -- đóng khung gói tin, địa chỉ hóa, lập lịch kết nối, truyền lại, và mã hóa tầng liên kết. Không có gì trong số này được cấu hình từ Python; tất cả đều thể hiện qua các tham số kết nối và MTU.
Generic Access Profile (GAP) -- khám phá và quản lý kết nối. Bốn vai trò: peripheral và broadcaster (quảng bá), central và observer (quét). Các payload quảng bá mang tên cục bộ, UUID dịch vụ, giao diện, và dữ liệu đặc thù nhà sản xuất -- 31 byte cộng với phản hồi quét tùy chọn 31 byte. Khoảng thời gian kết nối, độ trễ peripheral, và thời gian giám sát quyết định cảm giác của một kết nối đang mở.
Generic Attribute Profile (GATT) -- một cây các dịch vụ, mỗi dịch vụ chứa các đặc trưng, mỗi đặc trưng tùy chọn chứa các mô tả, được xác định bằng UUID (16-bit cho các tiêu chuẩn Bluetooth-SIG, 128-bit cho các UUID tùy chỉnh). Năm thao tác: đọc và ghi (kéo, do client khởi tạo), thông báo và chỉ dẫn (đẩy, do server khởi tạo, đăng ký thông qua Client Characteristic Configuration Descriptor). Kích thước payload bị giới hạn bởi MTU đã thương lượng.
API Python --
aioblebiến mọi pattern BLE thành một coroutine asyncio. Một peripheral làaioble.advertise()lặp qua các kết nối, với các đối tượngService/Characteristicđược xây dựng một lần và đăng ký bằngaioble.register_services(). Một central làaioble.scan()để tìm thiết bị đồng đẳng,connect()để mở liên kết,service()vàcharacteristic()để duyệt cây GATT từ xa, sau đóread()/write()/subscribe()/notified()cho dữ liệu thực tế. Các ngắt kết nối xuất hiện dưới dạngaioble.DeviceDisconnectedErrorbên trong coroutine đang chờ.Kênh L2CAP -- lối thoát cho các luồng byte dạng khối không phù hợp với mô hình key/value của GATT.
aioble.DeviceConnection.l2cap_accept()/l2cap_connect()mở một kênh theo ứng dụng trên đầu kết nối GAP, với send/recv được kiểm soát bằng luồng tín dụng và MTU lớn hơn so với GATT có thể mang.Ghép nối và mã hóa -- Các liên kết BLE mặc định là công khai.
aioble.DeviceConnection.pair()khởi tạo một quá trình trao đổi khóa tạo ra một liên kết đã mã hóa;bond=True(mặc định) lưu trữ các khóa để các kết nối tiếp theo bỏ qua quá trình bắt tay. Không cómitm=Truevà khả năng IO có thể sử dụng, mã hóa bảo vệ chống lại kẻ nghe lén thụ động nhưng không bảo vệ chống lại chuyển hướng chủ động trong lần ghép nối ban đầu.
Điều đó đủ để viết các ứng dụng camera phát trạng thái dưới dạng peripheral, đọc dữ liệu cảm biến dưới dạng central, đẩy các giá trị trực tiếp đến điện thoại qua BLE, bảo mật liên kết bằng bước ghép nối và liên kết, và -- cho trường hợp hiếm gặp cần truyền khối lượng lớn -- bước ra khỏi GATT vào một kênh L2CAP.
11.14.1. Xử lý sự cố¶
Các lỗi BLE hầu hết là sự không khớp giữa những gì hai bên mong đợi, và một công cụ kiểm tra phía điện thoại là cách nhanh nhất để xem kỳ vọng của ai đang sai. Công cụ tiêu chuẩn là nRF Connect for Mobile (Nordic Semiconductor, miễn phí trên Android và iOS): nó quét, kết nối, duyệt cơ sở dữ liệu GATT, đọc và ghi các đặc trưng, và đăng ký nhận thông báo -- vì vậy hành vi phía camera có thể được kiểm tra độc lập, mà không cần viết ứng dụng đồng hành.
Các chế độ lỗi thông thường:
"Thiết bị của tôi xuất hiện trong máy quét nhưng không thể kết nối." Thường thì packet quảng bá có
connectable=False(chế độ broadcaster), hoặc một kết nối trước đó vẫn đang mở và cam đã vượt quaaioble.advertise(). Thêm các câu lệnh print xung quanh lệnh gọi advertise để xác nhận."exchange_mtu(512) đã chạy nhưng thông báo của tôi vẫn bị giới hạn ở 20 byte." MTU đã thương lượng là
min(local, peer)-- điện thoại hoặc thư viện central có thể chưa yêu cầu MTU lớn hơn ở phía của nó, trong trường hợp đó kết nối vẫn ở mức 23. Kiểm tramtusau khiexchange_mtu()trả về. Cũng lưu ý rằngexchange_mtu()chỉ hoạt động một lần mỗi kết nối; hãy gọi nó trước thao tác lớn đầu tiên."Ghép nối thất bại với lỗi chung." Hai nguyên nhân thường gặp: sự không khớp khả năng IO (yêu cầu
mitm=Truetrên một cam khai báoio=3/ không có đầu vào không có đầu ra -- không có cách nào để xác nhận mã số, vì vậy bộ máy ghép nối dừng lại), và thời gian đồng hồ trên cam sai lệch lớn khi thiết bị đồng đẳng yêu cầu nó. Đặt đồng hồ bằngntptime.settime()trước lần ghép nối đầu tiên."Thông báo không bao giờ đến được client." Hai điều cần kiểm tra, theo thứ tự: (a) đặc trưng có được khai báo với
notify=Truekhông? -- bit thuộc tính phải được đặt ở phía server; (b) client có gọisubscribe()không? -- nếu không ghi Client Characteristic Configuration Descriptor (CCCD), server được thông báo rằng không có client nào muốn nhận thông báo và sẽ im lặng loại bỏ chúng."Tên được quảng bá bị cắt ngắn hoặc thiếu." Payload quảng bá là 31 byte, và các trường flags + service-UUID + appearance đều chiếm byte từ trên xuống. Một
name=dài cộng với nhiều UUID dịch vụ sẽ tràn. Hãy rút ngắn tên hoặc sử dụng quét chủ động để phản hồi quét (thêm 31 byte) mang phần tràn. nRF Connect hiển thị cả hai nửa riêng biệt, giúp việc phân chia trở nên rõ ràng."L2CAP connect raise ngay lập tức." Thường là sự không khớp PSM -- cả hai bên phải đồng ý về cùng một số PSM ngoài băng tần. Một
L2CAPConnectionErrormang mã trạng thái Bluetooth làm đối số đầu tiên của nó; trạng thái2("PSM không được hỗ trợ") là dấu hiệu rõ ràng."Các kết nối đã liên kết vẫn kích hoạt quá trình bắt tay ghép nối đầy đủ mỗi lần kết nối lại."
aioble.security.load_secrets()không được gọi khi khởi động. Nếu không có nó, các khóa đã lưu nằm trên flash nhưng không bao giờ được tải vào bộ nhớ, vì vậy danh tính của thiết bị đồng đẳng không được biết và quá trình ghép nối chạy lại từ đầu mỗi lần.
Khi tất cả đều thất bại, module bluetooth cấp thấp hơn hiển thị một hàm gọi lại IRQ kích hoạt cho mọi sự kiện cơ bản; đăng ký nó ngắn gọn và in các sự kiện tương đương với một dấu vết Wireshark cho phía cam.
11.14.2. Sử dụng tài liệu tham khảo này sau này¶
Hãy coi các chương Bluetooth như tài liệu tham khảo; quay lại để tìm bố cục chính xác của payload quảng bá của một peripheral hoặc luồng quét và đăng ký của central là mục đích sử dụng. Các trang tham khảo aioble --- Async BLE và bluetooth --- Bluetooth cấp thấp liệt kê mọi phương thức, cờ và hằng số ở một nơi khi câu hỏi chỉ là "tên chính xác của lệnh gọi này là gì".