11.6. บริการและลักษณะเด่น¶
เมื่อ GAP เชื่อมต่ออุปกรณ์สองตัวเข้าหากันแล้ว ชั้นที่อยู่เหนือขึ้นไป -- Generic Attribute Profile หรือ GATT -- จะต้องกำหนดความหมายให้กับไบต์ที่ไหลผ่านการเชื่อมต่อนั้น ทางเลือกของ BLE ที่นี่นับว่าผิดธรรมดา ในขณะที่ TCP เปิดเผยสตรีมไบต์ดิบและปล่อยให้แอปพลิเคชันคิดค้นการจัดเฟรมเอง GATT กลับเปิดเผย ฐานข้อมูลคีย์/ค่าขนาดเล็ก ที่ฝั่งหนึ่งเป็นผู้โฮสต์และอีกฝั่งหนึ่งอ่าน เขียน หรือสมัครรับข้อมูล
ฐานข้อมูลนั้นคือสิ่งที่นักออกแบบแอปพลิเคชันใช้เวลาส่วนใหญ่ในการคิดเกี่ยวกับ BLE สิ่งที่กล้องเผยแพร่ไปยังโทรศัพท์ สิ่งที่กล้องติดตามบน sensor ระยะไกล วิธีที่แป้นพิมพ์ Bluetooth แจ้งให้โฮสต์รู้ว่าปุ่มไหนถูกกด -- ล้วนเป็นค่าลักษณะเด่นในฐานข้อมูล GATT บางส่วนที่ใดที่หนึ่ง
11.6.1. แกนบทบาทสองแกน ไม่ใช่หนึ่ง¶
แหล่งที่มาของความสับสนที่พบบ่อย: peripheral / central และ server / client เป็น แกนอิสระสองแกน ไม่ใช่คำไวพจน์
Peripheral และ central เป็นบทบาท GAP ที่กำหนดระหว่างการเชื่อมต่อ Peripheral จะโฆษณาและถูกเชื่อมต่อเข้าหา ส่วน central จะสแกนและเริ่มต้นการเชื่อมต่อ บทบาทนี้ถูกกำหนดตายตัวทันทีที่ลิงก์ขึ้นมาและไม่เปลี่ยนแปลง
Server และ client เป็นบทบาท GATT ที่กำหนดตามการดำเนินการของลักษณะเด่นแต่ละรายการ Server เป็นผู้โฮสต์ลักษณะเด่น ส่วน client จะอ่าน เขียน หรือสมัครรับข้อมูล
สองแกนนี้แยกออกจากกันตามข้อกำหนด Peripheral โดยปกติ จะเป็น server (สายรัดวัดอัตราการเต้นของหัวใจเผยแพร่ค่าที่อ่านได้) และ central โดยปกติ จะเป็น client (โทรศัพท์อ่านค่าเหล่านั้น) แต่ BLE อนุญาตให้ใช้การผสมผสานใดก็ได้ -- peripheral อาจค้นพบลักษณะเด่นบน central ที่เพิ่งเชื่อมต่อมา หรือการเชื่อมต่อเดียวอาจโฮสต์บริการทั้งสองฝั่งพร้อมกันได้
แอปพลิเคชันกล้องส่วนใหญ่ยึดตามการจับคู่แบบดั้งเดิม (peripheral + server หรือ central + client) ดังนั้นส่วนที่เหลือของหัวข้อนี้จึงถือว่าทั้งสองเป็นแกนเดียวเมื่อกรณีที่อธิบายเป็นกรณีดั้งเดิม เมื่อความแตกต่างมีความสำคัญ ทั้งสองคำจะถูกสะกดออกมาอย่างชัดเจน
11.6.2. ภายในฐานข้อมูล¶
ฐานข้อมูล GATT เป็นโครงสร้างต้นไม้ ใบของต้นไม้บรรจุไบต์จริง กิ่งก้านจัดกลุ่มใบที่เกี่ยวข้องกันเป็นหน่วยที่มีความหมายต่อมนุษย์
ฐานข้อมูล GATT โดย Service จัดกลุ่ม characteristic ลักษณะเด่น characteristic บรรจุไบต์ของแอปพลิเคชัน และ descriptor บรรจุข้อมูลเมตาเกี่ยวกับ characteristic¶
มีโหนดสามประเภท:
service คือกลุ่มเชิงตรรกะของค่าที่เกี่ยวข้องกัน Bluetooth SIG เผยแพร่คำจำกัดความบริการมาตรฐานสำหรับกรณีการใช้งานทั่วไป -- Battery Service สำหรับระดับแบตเตอรี่ Environmental Sensing สำหรับอุณหภูมิ / ความชื้น / ความดัน Heart Rate สำหรับเครื่องวัดอัตราการเต้นของหัวใจ -- เพื่อให้แอปทั่วไปบนโทรศัพท์สามารถจดจำบริการที่ไม่เคยเห็นมาก่อนได้ แอปพลิเคชันยังสามารถกำหนดบริการของตัวเองสำหรับสิ่งที่ SIG ยังไม่ได้กำหนดมาตรฐานได้
characteristic คือค่าที่มีชื่อหนึ่งค่าภายใน service Battery service มี characteristic เดียว -- Battery Level ซึ่งเป็นเปอร์เซ็นต์หนึ่งไบต์ Environmental Sensing มี characteristic แยกสำหรับอุณหภูมิ ความชื้น ความดัน และอื่นๆ characteristic คือหน่วยของการดำเนินการ GATT -- คุณอ่าน characteristic คุณเขียน characteristic คุณสมัครรับข้อมูล characteristic
descriptor คือข้อมูลเมตาที่แนบกับ characteristic บาง descriptor ถูกกำหนดมาตรฐาน -- Client Characteristic Configuration Descriptor (CCCD) เป็นที่รู้จักมากที่สุด เพราะการเขียนลงไปคือวิธีที่ client แจ้ง server ว่า "ส่งการแจ้งเตือนให้ฉันสำหรับ characteristic นี้" ส่วนอื่นๆ เป็นแบบผู้ใช้กำหนดเองและบรรจุสิ่งต่างๆ เช่น รูปแบบการนำเสนอหรือคุณสมบัติขยาย
GATT server (โดยทั่วไปคือ peripheral) ประกาศฐานข้อมูลของตนครั้งเดียวเมื่อเริ่มต้นและฐานข้อมูลจะไม่เปลี่ยนแปลงขณะทำงาน GATT client (โดยทั่วไปคือ central) ค้นพบ สิ่งที่อยู่ในฐานข้อมูลหลังจากเชื่อมต่อ -- เดินผ่านต้นไม้ อ่าน UUID ของบริการที่พบ จากนั้น characteristic ภายในแต่ละบริการ
11.6.3. UUID¶
ทุก service, characteristic, และ descriptor มี UUID (Universally Unique IDentifier) ที่ระบุ ประเภทของสิ่งนั้น UUID มีสามขนาด:
16 บิต สงวนไว้สำหรับมาตรฐานที่กำหนดโดย Bluetooth SIG Battery Service คือ
0x180FBattery Level (characteristic) คือ0x2A19รายการทั้งหมดเผยแพร่บนเว็บไซต์หมายเลขที่กำหนดของ Bluetooth SIG ที่ https://www.bluetooth.com/specifications/assigned-numbers/32 บิต จุดกึ่งกลางที่ไม่ค่อยถูกใช้
128 บิต สิ่งที่ทุกคนอื่นใช้ -- ผู้ขายหรือแอปพลิเคชันสร้างขึ้นแบบสุ่มและใช้สำหรับบริการหรือ characteristic แบบกำหนดเองของตน กล้องที่กำหนดโปรโตคอลของตัวเองอยู่ที่นี่
คลาส bluetooth.UUID รับค่าทั้งสามขนาด:
import bluetooth
BATTERY_SERVICE = bluetooth.UUID(0x180F)
CUSTOM_SERVICE = bluetooth.UUID("12345678-1234-5678-9abc-def012345678")
UUID 16 บิตเข้ารหัสในเพย์โหลดโฆษณาขนาดเล็ก ซึ่งเป็นหนึ่งในเหตุผลที่บริการมาตรฐานนั้นดีกว่าเมื่อมีอยู่ -- สายรัดอัตราการเต้นหัวใจที่โฆษณา 0x180D (Heart Rate) ใช้สองไบต์ UUID แบบกำหนดเองใช้สิบหก สำหรับแอปพลิเคชันที่ไม่ต้องการความสามารถในการทำงานร่วมกันกับมาตรฐาน UUID 128 บิตที่สร้างขึ้นคือคำตอบที่ถูกต้อง
11.6.4. ประโยชน์ของบริการมาตรฐาน SIG¶
เหตุผลในการใช้บริการมาตรฐานนั้นตรงไปตรงมา: แอปที่มีอยู่แล้วรู้วิธีคุยกับมันแล้ว อุปกรณ์ที่โฆษณา Heart Rate service (0x180D) และเปิดเผย Heart Rate Measurement characteristic (0x2A37) ทำงานได้กับแอปฟิตเนสทุกแอปในโลกโดยไม่ต้องมีใครเขียนโค้ดใหม่ อุปกรณ์ที่ใช้ข้อมูลเดียวกันแต่ด้วย UUID แบบกำหนดเองต้องมีแอปคู่ของตัวเองและเอกสารโปรโตคอลของตัวเอง
มาตรฐานเหล่านี้มีต้นทุน รูปแบบไบต์ภายใน characteristic แต่ละรายการถูกระบุไว้ -- SIG ตัดสินใจว่า Heart Rate Measurement เป็นฟิลด์แฟล็กหนึ่งไบต์ตามด้วยค่าอัตราการเต้นหัวใจ 8 บิตหรือ 16 บิต และอาจตามด้วยช่วง R-R -- อุปกรณ์ที่สอดคล้องต้องปฏิบัติตามรูปแบบเหล่านั้น บริการแบบกำหนดเองไม่มีข้อจำกัดนั้น
คำตอบเชิงปฏิบัติสำหรับกล้อง: ใช้บริการมาตรฐานเมื่อมีอยู่สำหรับประเภทข้อมูลที่คุณมี (Battery Service, Environmental Sensing) และกำหนดแบบกำหนดเองด้วย UUID 128 บิตสำหรับสิ่งที่เฉพาะเจาะจงกับแอปพลิเคชันของคุณ
11.6.5. ออบเจกต์ฝั่ง server และฝั่ง client¶
สำหรับบล็อกการสร้างแนวคิดเดียวกัน (service, characteristic, descriptor) ทุกไลบรารี GATT เปิดเผยชุดออบเจกต์คู่ขนานสองชุด:
ออบเจกต์ ฝั่ง server -- สิ่งที่ peripheral ประกาศว่าโฮสต์ ใน
aioble:aioble.Service,aioble.Characteristic,aioble.Descriptorสิ่งเหล่านี้ถูกสร้างขึ้นก่อนการโฆษณาเริ่มต้นและลงทะเบียนด้วยaioble.register_services()ออบเจกต์ ฝั่ง client -- สิ่งที่ central ค้นพบบน peer หลังจากเชื่อมต่อ ใน
aioble:aioble.ClientService,aioble.ClientCharacteristic,aioble.ClientDescriptorสิ่งเหล่านี้เดินผ่านaioble.DeviceConnection.service()/services()หลังจากเชื่อมต่อ