11.6. الخدمات والخصائص¶
بمجرد أن يدخل GAP جهازين في اتصال مفتوح، يتعين على الطبقة الأعلى منه -- Generic Attribute Profile، أي GATT -- أن تمنح البايتات المتدفقة عبر ذلك الاتصال معنى. اختيار BLE هنا غير معتاد. فبينما يكشف TCP عن دفق بايتات خام ويترك للتطبيق مهمة ابتكار تأطيره الخاص، يكشف GATT عن قاعدة بيانات صغيرة من مفتاح/قيمة تستضيفها إحدى الجهتين وتقرأها الأخرى أو تكتب فيها أو تشترك بها.
تلك القاعدة هي ما يقضي مصممو التطبيقات معظم وقتهم في BLE في التفكير فيه. فما تنشره الكاميرا إلى الهاتف، وما تراقبه على مستشعر بعيد، وكيف تخبر لوحة مفاتيح Bluetooth مضيفها بالمفتاح الذي ضُغط -- كلها قيم خصائص في قاعدة بيانات GATT ما في مكان ما.
11.6.1. محوران للأدوار، لا محور واحد¶
مصدر شائع للالتباس: peripheral / central و server / client هما محوران مستقلان، وليسا مترادفين.
Peripheral وcentral هما دورا GAP، يُحدَّدان أثناء الاتصال. فالطرفية (peripheral) تُعلِن ويُتصل بها؛ والمركزي (central) يمسح ويبدأ الاتصال. يُحسم هذا لحظة قيام الرابط ولا يتغير.
Server وclient هما دورا GATT، يُحدَّدان لكل عملية على الخاصية. فالخادم (server) يستضيف الخاصية؛ والعميل (client) يقرؤها أو يكتب فيها أو يشترك بها.
المحوران منفصلان حسب المواصفة. فالطرفية تكون عادةً الخادم (يَنشُر حزام قياس معدل ضربات القلب قراءاته) ويكون المركزي عادةً العميل (يقرؤها الهاتف)، لكن BLE يسمح بأي تركيبة -- فقد تكتشف الطرفية خاصية على المركزي الذي اتصلت به للتو، أو قد يستضيف اتصال واحد خدمات على الجهتين في آن معًا.
تلتزم معظم تطبيقات الكاميرات بالاقتران التقليدي (peripheral + server، أو central + client)، لذا تتعامل بقية هذا القسم معهما كمحور واحد عندما تكون الحالة التقليدية هي ما يُوصَف. وعندما يكون التمييز مهمًا، يُكتب المصطلحان بوضوح.
11.6.2. داخل قاعدة البيانات¶
قاعدة بيانات GATT هي شجرة. تحمل أوراقها البايتات الفعلية. وتجمّع فروعها الأوراق المترابطة في وحدات ذات معنى للإنسان.
قاعدة بيانات GATT. تجمّع الخدمات الخصائص؛ وتحمل الخصائص بايتات التطبيق؛ وتحمل الواصفات بيانات وصفية عن الخاصية.¶
هناك ثلاثة أنواع من العقد:
الخدمة (service) هي مجموعة منطقية من القيم المترابطة. تنشر Bluetooth SIG تعريفات خدمات قياسية لحالات الاستخدام الشائعة -- Battery Service لمستوى البطارية، وEnvironmental Sensing لدرجة الحرارة / الرطوبة / الضغط، وHeart Rate لأجهزة مراقبة معدل ضربات القلب -- بحيث يستطيع تطبيق عام على هاتف أن يتعرف على خدمة لم يرها من قبل قط. كما أن للتطبيق حرية تعريف خدماته الخاصة لأشياء لم تجعلها SIG قياسية.
الخاصية (characteristic) هي قيمة واحدة مُسمّاة داخل خدمة. لخدمة Battery خاصية واحدة -- Battery Level، وهي نسبة مئوية من بايت واحد. ولخدمة Environmental Sensing خصائص منفصلة لدرجة الحرارة والرطوبة والضغط وما إلى ذلك. الخاصية هي وحدة عمليات GATT -- فأنت تقرأ خاصية، وتكتب خاصية، وتشترك في خاصية.
الواصف (descriptor) هو بيانات وصفية مرفقة بخاصية. بعض الواصفات قياسية -- وClient Characteristic Configuration Descriptor (CCCD) هو الأشهر، لأن الكتابة فيه هي الطريقة التي يخبر بها العميل الخادم "أرسل لي إشعارات على هذه الخاصية". وأخرى يُعرّفها المستخدم وتحمل أشياء مثل صيغة العرض أو الخصائص الموسّعة.
يُعلِن خادم GATT (وهو الطرفية عادةً) عن قاعدة بياناته مرة واحدة عند بدء التشغيل ولا تتغير القاعدة أثناء العمل. أما عميل GATT (وهو المركزي عادةً) فإنه يكتشف ما في قاعدة البيانات بعد الاتصال -- متجولًا في الشجرة، قارئًا UUID للخدمات التي يجدها، ثم الخصائص داخل كل منها.
11.6.3. معرّفات UUID¶
لكل خدمة وخاصية وواصف UUID (مُعرّف فريد عالميًا) يحدد نوع الشيء. تأتي معرّفات UUID بثلاثة عروض:
16-بت. محجوزة للمعايير التي تعرّفها Bluetooth SIG. خدمة Battery هي
0x180F. وBattery Level (وهي خاصية) هي0x2A19. القائمة الكاملة منشورة على موقع الأرقام المخصصة لـ Bluetooth SIG على https://www.bluetooth.com/specifications/assigned-numbers/.32-بت. حل وسط نادر الاستخدام.
128-بت. ما يستخدمه الجميع غير ذلك -- إذ يُولِّد مورِّد أو تطبيق واحدًا عشوائيًا ويستخدمه لخدمته أو خاصيته المخصصة. والكاميرات التي تعرّف بروتوكولها الخاص تعيش هنا.
تقبل الفئة 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 (0x180D) ويكشف خاصية Heart Rate Measurement (0x2A37) يعمل مع كل تطبيق لياقة على الكوكب دون أن يكتب أحد شيفرة جديدة. أما جهاز يعيد تنفيذ البيانات نفسها بمعرّفات UUID مخصصة فيحتاج إلى تطبيق مرافق خاص به ووثيقة بروتوكول خاصة به.
للمعايير ثمنها بالطبع. فتنسيقات البايتات داخل كل خاصية محددة -- إذ قررت SIG أن Heart Rate Measurement حقل أعلام بحجم بايت واحد يتبعه إما قيمة معدل ضربات قلب بطول 8-بت أو 16-بت، وقد تتبعها فترات R-R اختياريًا -- ويتعين على جهاز متوافق اتباع تلك التنسيقات. أما الخدمات المخصصة فهي حرة من هذا القيد.
الإجابة العملية للكاميرات: استخدم الخدمة القياسية حين تتوفر واحدة لنوع البيانات التي لديك (Battery Service، Environmental Sensing)، وعرّف خدمة مخصصة بمعرّف UUID بطول 128-بت لأي شيء خاص بتطبيقك.
11.6.5. كائنات جانب الخادم وجانب العميل¶
للبنات المفاهيمية ذاتها (الخدمة، الخاصية، الواصف)، تكشف كل مكتبة GATT عن مجموعتين متوازيتين من الكائنات:
كائنات جانب الخادم -- ما تُعلِن الطرفية أنها تستضيفه. في
aioble:aioble.Serviceوaioble.Characteristicوaioble.Descriptor. تُنشأ هذه قبل بدء الإعلان وتُسجَّل بـaioble.register_services().كائنات جانب العميل -- ما يكتشفه المركزي على النظير بعد الاتصال. في
aioble:aioble.ClientServiceوaioble.ClientCharacteristicوaioble.ClientDescriptor. يُتجوّل في هذه عبرaioble.DeviceConnection.service()/services()بعد الاتصال.