bluetooth --- Bluetooth منخفض المستوى¶
توفر هذه الوحدة واجهة للتحكم في وحدة Bluetooth المدمجة على اللوحة. وهي تدعم Bluetooth Low Energy (BLE) في أدوار Central وPeripheral وBroadcaster وObserver، إضافة إلى GATT Server وClient وقنوات L2CAP الموجهة بالاتصال. ويمكن للجهاز أن يعمل في عدة أدوار في آن واحد. كما أن الإقران (Pairing) والربط (Bonding) مدعومان أيضاً.
صُممت هذه الواجهة (API) لتطابق بروتوكول Bluetooth منخفض المستوى ولتوفر لبنات بناء لتجريدات أعلى مستوى مثل أنواع أجهزة محددة.
نصيحة
بالنسبة لمعظم التطبيقات، يُفضّل استخدام مكتبة aioble الأعلى مستوى، والتي توفر غلافاً قائماً على asyncio حول هذه الوحدة. راجع aioble --- BLE غير المتزامن.
class BLE¶
- class bluetooth.BLE¶
تُرجع كائن BLE الوحيد (singleton).
التهيئة
- active(active: bool | None = None, /) bool¶
تغيّر اختيارياً حالة تنشيط راديو BLE، وتُرجع الحالة الحالية.
يجب تنشيط الراديو قبل استخدام أي من الدوال الأخرى في هذا الصنف.
- config(param: str, /) Any¶
- config(*, **kwargs: Any) None
للحصول على قيم تهيئة واجهة BLE أو ضبطها. للحصول على قيمة، يجب وضع اسم المعامل بين علامتي اقتباس كسلسلة نصية، ويُستعلم عن معامل واحد فقط في كل مرة. ولضبط القيم استخدم صيغة الكلمات المفتاحية، إذ يمكن ضبط معامل واحد أو أكثر في المرة الواحدة.
القيم المدعومة حالياً هي:
'mac': العنوان المستخدم حالياً، اعتماداً على وضع العنونة الحالي. يُرجع هذا صفّاً (tuple) بالشكل(addr_type, addr).راجع
gap_scanللاطلاع على تفاصيل نوع العنوان.لا يمكن الاستعلام عن هذا إلا عندما تكون الواجهة نشطة حالياً.
'addr_mode': يضبط وضع العنونة. القيم هي:القيمة
الاسم
السلوك
0x00PUBLIC
استخدام العنوان العام (public) للمتحكم.
0x01RANDOM
استخدام عنوان ثابت مُولَّد.
0x02RPA
استخدام عناوين خاصة قابلة للحل (resolvable).
0x03NRPA
استخدام عناوين خاصة غير قابلة للحل (non-resolvable).
بشكل افتراضي، ستستخدم الواجهة عنواناً من نوع PUBLIC إن كان متاحاً، وإلا فستستخدم عنواناً من نوع RANDOM.
'gap_name': للحصول على اسم جهاز GAP المستخدم من قِبل خدمة Generic Access (المعرّف UUID0x1800)، خاصية Device Name (المعرّف UUID0x2a00) أو ضبطه. يمكن ضبط هذا في أي وقت وتغييره عدة مرات.'rxbuf': للحصول على حجم المخزن المؤقت الداخلي المستخدم لتخزين الأحداث الواردة بالبايت أو ضبطه. هذا المخزن المؤقت عام لكامل مُشغِّل BLE، ومن ثَمَّ يتعامل مع البيانات الواردة لجميع الأحداث، بما في ذلك جميع الخصائص. زيادته تتيح تعاملاً أفضل مع البيانات الواردة المتدفقة دفعةً واحدة (مثل نتائج المسح) والقدرة على استقبال قيم خصائص أكبر.'mtu': للحصول على قيمة MTU التي ستُستخدم أثناء تبادل ATT MTU أو ضبطها. ستكون قيمة MTU الناتجة هي الأصغر بين هذه القيمة وقيمة MTU للجهاز البعيد. لن يحدث تبادل ATT MTU تلقائياً (ما لم يبادر الجهاز البعيد بذلك)، ويجب بدؤه يدوياً باستخدامgattc_exchange_mtu. استخدم الحدث_IRQ_MTU_EXCHANGEDلاكتشاف قيمة MTU لاتصال معيّن.'bond': يضبط ما إذا كان الربط (bonding) سيُفعَّل أثناء الإقران. عند تفعيله، ستضبط طلبات الإقران علامة "bond" وسيخزّن كلا الجهازين المفاتيح.'mitm': يضبط ما إذا كانت الحماية من هجمات MITM مطلوبة للإقران.'io': يضبط قدرات الإدخال/الإخراج (I/O) لهذا الجهاز.الخيارات المتاحة هي:
الثابت
القيمة
القدرة
_IO_CAPABILITY_DISPLAY_ONLY0
العرض فقط
_IO_CAPABILITY_DISPLAY_YESNO1
العرض مع إدخال نعم/لا
_IO_CAPABILITY_KEYBOARD_ONLY2
لوحة المفاتيح فقط
_IO_CAPABILITY_NO_INPUT_OUTPUT3
لا إدخال ولا إخراج
_IO_CAPABILITY_KEYBOARD_DISPLAY4
لوحة مفاتيح وشاشة عرض
'le_secure': يضبط ما إذا كان الإقران من نوع "LE Secure" مطلوباً. القيمة الافتراضية هي false (أي السماح بـ "Legacy Pairing").
معالجة الأحداث
- irq(handler: Callable[[int, Tuple], Any | None], /) None¶
تُسجّل دالة رد نداء للأحداث الصادرة من مكدس BLE. تأخذ دالة handler وسيطين، هما
event(وستكون أحد الرموز أدناه) وdata(وهي صفّ (tuple) من القيم خاص بالحدث).ملاحظة: كتحسين لمنع التخصيصات غير الضرورية للذاكرة، فإن المدخلات
addrوadv_dataوchar_dataوnotify_dataوuuidفي الصفوف (tuples) هي نسخ memoryview للقراءة فقط تشير إلى المخزن الحلقي (ringbuffer) الداخلي لوحدةbluetooth، وهي صالحة فقط أثناء استدعاء دالة معالج مقاطعة IRQ. وإذا احتاج برنامجك إلى حفظ إحدى هذه القيم للوصول إليها بعد عودة معالج IRQ (مثلاً بحفظها في نسخة صنف أو في متغير عام)، فعليه أن يأخذ نسخة من البيانات، إما باستخدامbytes()أوbluetooth.UUID()، على هذا النحو:connected_addr = bytes(addr) # equivalently: adv_data, char_data, or notify_data matched_uuid = bluetooth.UUID(uuid)
على سبيل المثال، قد يفحص معالج IRQ الخاص بنتيجة مسح القيمة
adv_dataليقرر ما إذا كان الجهاز هو الجهاز الصحيح، وعندها فقط ينسخ بيانات العنوان لاستخدامها في مكان آخر من البرنامج. ولطباعة البيانات من داخل معالج IRQ، ستكونprint(bytes(addr))مطلوبة.عادةً ما يوزّع المعالج التنفيذ بناءً على رمز الحدث ويفكّ تغليف صفّ الحمولة الخاص بالحدث:
def bt_irq(event, data): if event == _IRQ_CENTRAL_CONNECT: conn_handle, addr_type, addr = data ... elif event == _IRQ_SCAN_RESULT: addr_type, addr, adv_type, rssi, adv_data = data ...
فيما يلي قائمة بكل رمز حدث وما يقدّمه من حمولة ووصف مختصر له. بالنسبة للأحداث التي يُذكر فيها الحقل
status، تكون قيمةstatusهي0عند النجاح وقيمة غير صفرية خاصة بالتنفيذ عند الفشل.الثابت
القيمة
الحدث
صفّ الحمولة (tuple)
_IRQ_CENTRAL_CONNECT1
اتصل جهاز central بهذا الجهاز الطرفي (peripheral).
(conn_handle, addr_type, addr)_IRQ_CENTRAL_DISCONNECT2
انقطع اتصال جهاز central عن هذا الجهاز الطرفي (peripheral).
(conn_handle, addr_type, addr)_IRQ_GATTS_WRITE3
كتب عميل متصل إلى خاصية أو واصف محلي. استخدم
gatts_readلجلب القيمة الجديدة.(conn_handle, attr_handle)_IRQ_GATTS_READ_REQUEST4
أصدر عميل متصل طلب قراءة. أرجِع رمز خطأ غير صفري من الجدول أدناه لرفض القراءة، أو
0/Noneلقبولها.(conn_handle, attr_handle)_IRQ_SCAN_RESULT5
تم استقبال حزمة إعلان (advertising) واحدة أثناء مسح نشط.
(addr_type, addr, adv_type, rssi, adv_data)_IRQ_SCAN_DONE6
انتهى المسح الحالي، إما لأن المدة المُهيّأة انقضت أو لأنه تم استدعاء
gap_scan(None).()_IRQ_PERIPHERAL_CONNECT7
نجح استدعاء سابق لـ
gap_connect.(conn_handle, addr_type, addr)_IRQ_PERIPHERAL_DISCONNECT8
انقطع اتصال جهاز طرفي (peripheral) كان متصلاً.
(conn_handle, addr_type, addr)_IRQ_GATTC_SERVICE_RESULT9
تم العثور على خدمة واحدة بواسطة
gattc_discover_services.(conn_handle, start_handle, end_handle, uuid)_IRQ_GATTC_SERVICE_DONE10
انتهى اكتشاف الخدمات.
(conn_handle, status)_IRQ_GATTC_CHARACTERISTIC_RESULT11
تم العثور على خاصية واحدة بواسطة
gattc_discover_characteristics.(conn_handle, end_handle, value_handle, properties, uuid)_IRQ_GATTC_CHARACTERISTIC_DONE12
انتهى اكتشاف الخصائص.
(conn_handle, status)_IRQ_GATTC_DESCRIPTOR_RESULT13
تم العثور على واصف واحد بواسطة
gattc_discover_descriptors.(conn_handle, dsc_handle, uuid)_IRQ_GATTC_DESCRIPTOR_DONE14
انتهى اكتشاف الواصفات.
(conn_handle, status)_IRQ_GATTC_READ_RESULT15
أعاد استدعاء سابق لـ
gattc_readبيانات.(conn_handle, value_handle, char_data)_IRQ_GATTC_READ_DONE16
انتهى استدعاء سابق لـ
gattc_read.(conn_handle, value_handle, status)_IRQ_GATTC_WRITE_DONE17
تم الإقرار باستلام استدعاء سابق لـ
gattc_write.(conn_handle, value_handle, status)_IRQ_GATTC_NOTIFY18
أرسل خادم بعيد إشعاراً (غير مُقَر باستلامه).
(conn_handle, value_handle, notify_data)_IRQ_GATTC_INDICATE19
أرسل خادم بعيد دلالة (indication) (مُقَر باستلامها).
(conn_handle, value_handle, notify_data)_IRQ_GATTS_INDICATE_DONE20
تم الإقرار باستلام دلالة (indication) أُرسلت سابقاً من قِبل العميل (أو انتهت مهلتها).
(conn_handle, value_handle, status)_IRQ_MTU_EXCHANGED21
اكتمل تبادل ATT MTU (بمبادرة من أي من الطرفين).
(conn_handle, mtu)_IRQ_L2CAP_ACCEPT22
طلب جهاز بعيد إنشاء اتصال L2CAP على معرّف PSM يستمع عليه هذا الجهاز. أرجِع عدداً صحيحاً غير صفري للرفض، أو
0/Noneللقبول.(conn_handle, cid, psm, our_mtu, peer_mtu)_IRQ_L2CAP_CONNECT23
تم إنشاء قناة L2CAP الآن، إما بقبول طلب وارد أو بإكمال استدعاء صادر لـ
l2cap_connect.(conn_handle, cid, psm, our_mtu, peer_mtu)_IRQ_L2CAP_DISCONNECT24
انقطع اتصال قناة L2CAP. تكون قيمة
statusهي0لانقطاع نظيف، أو غير صفرية إذا فشلت محاولة اتصال صادرة.(conn_handle, cid, psm, status)_IRQ_L2CAP_RECV25
وصلت بيانات على قناة L2CAP. استدعِ
l2cap_recvintoلقراءتها.(conn_handle, cid)_IRQ_L2CAP_SEND_READY26
تم تفريغ استدعاء سابق لـ
l2cap_sendكان قد أعادFalse، والقناة جاهزة من جديد. قيمةstatusغير الصفرية تعني أن مخزن الإرسال المؤقت قد فاض ويجب على التطبيق إعادة إرسال البيانات.(conn_handle, cid, status)_IRQ_CONNECTION_UPDATE27
حدّث الجهاز البعيد معاملات الاتصال (الفاصل الزمني، وزمن الاستجابة، ومهلة الإشراف).
(conn_handle, conn_interval, conn_latency, supervision_timeout, status)_IRQ_ENCRYPTION_UPDATE28
تغيّرت حالة التشفير لاتصال ما، عادةً بعد اكتمال الإقران أو الربط.
(conn_handle, encrypted, authenticated, bonded, key_size)_IRQ_GET_SECRET29
يطلب المكدس سرّ ربط (bonding secret) مخزّن. إذا كانت قيمة
keyهيNone، فأرجِع القيمة المخزّنة رقمindexمن النوعsec_type؛ وإلا فأرجِع القيمة المرتبطة بـ(sec_type, key)المعطاة. أرجِعNoneإذا لم يكن هناك شيء مخزّن.(sec_type, index, key)_IRQ_SET_SECRET30
يطلب المكدس من التطبيق حفظ سرّ ربط (bonding secret) بشكل دائم. أرجِع
Trueبمجرد تخزينه.(sec_type, key, value)_IRQ_PASSKEY_ACTION31
إجراء يتعلق بمفتاح المرور (passkey) مطلوب كجزء من الإقران. استجِب باستخدام
gap_passkey؛ راجع جدول إجراءات مفتاح المرور أدناه للاطلاع على الإجراءات الممكنة.(conn_handle, action, passkey)بالنسبة للحدث
_IRQ_GATTS_READ_REQUEST، رموز الإرجاع المتاحة هي:الثابت
القيمة
المعنى
_GATTS_NO_ERROR0x00قبول القراءة.
_GATTS_ERROR_READ_NOT_PERMITTED0x02القراءة غير مسموح بها.
_GATTS_ERROR_WRITE_NOT_PERMITTED0x03الكتابة غير مسموح بها.
_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION0x05العميل غير مُصادَق عليه.
_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION0x08العميل غير مُخوَّل.
_GATTS_ERROR_INSUFFICIENT_ENCRYPTION0x0fالرابط غير مشفّر.
بالنسبة للحدث
_IRQ_PASSKEY_ACTION، الإجراءات المتاحة هي:الثابت
القيمة
المعنى
_PASSKEY_ACTION_NONE0
لا يلزم أي إجراء.
_PASSKEY_ACTION_INPUT2
مطالبة المستخدم بإدخال مفتاح المرور المعروض على الجهاز البعيد.
_PASSKEY_ACTION_DISPLAY3
عرض مفتاح مرور مكوّن من 6 أرقام ليُدخله الجهاز البعيد.
_PASSKEY_ACTION_NUMERIC_COMPARISON4
تأكيد أن مفتاح المرور يطابق المفتاح المعروض على الجهاز البعيد.
بهدف توفير المساحة في البرنامج الثابت، فإن هذه الثوابت غير مضمّنة في وحدة
bluetooth. أضِف ما تحتاجه منها من القوائم أعلاه إلى برنامجك.
دور Broadcaster (المُعلِن)
- gap_advertise(interval_us: int | None, adv_data: bytes | None = None, *, resp_data: bytes | None = None, connectable: bool = True) None¶
يبدأ الإعلان بالفاصل الزمني المحدد (بالميكروثانية). سيُقرَّب هذا الفاصل الزمني نزولاً إلى أقرب مضاعف لـ 625us. لإيقاف الإعلان، اضبط interval_us على
None.يمكن أن تكون adv_data وresp_data من أي نوع يطبّق بروتوكول المخزن المؤقت (buffer protocol) (مثل
bytesوbytearrayوstr). تُضمَّن adv_data في كل عمليات البث، وتُرسَل resp_data رداً على مسح نشط.ملاحظة: إذا كانت adv_data (أو resp_data) هي
None، فستُعاد عندئذٍ استخدام البيانات المُمرَّرة إلى الاستدعاء السابق لـgap_advertise. وهذا يتيح للمُعلِن استئناف الإعلان باستخدامgap_advertise(interval_us)فقط. ولمسح حمولة الإعلان مرّر قيمةbytesفارغة، أيb''.
دور Observer (الماسح)
- gap_scan(duration_ms: int | None, interval_us: int = 1280000, window_us: int = 11250, active: bool = False, /) None¶
يُجري عملية مسح تستمر للمدة المحددة (بالملي ثانية).
للمسح إلى أجل غير مسمى، اضبط duration_ms على
0.لإيقاف المسح، اضبط duration_ms على
None.استخدم interval_us وwindow_us لتهيئة دورة العمل (duty cycle) اختيارياً. سيعمل الماسح لمدة window_us ميكروثانية كل interval_us ميكروثانية لإجمالي duration_ms ملي ثانية. الفاصل الزمني والنافذة الافتراضيان هما 1.28 ثانية و11.25 ملي ثانية على التوالي (المسح في الخلفية).
لكل نتيجة مسح، سيُطلَق الحدث
_IRQ_SCAN_RESULTمع بيانات الحدث(addr_type, addr, adv_type, rssi, adv_data).تشير قيم
addr_typeإلى عناوين عامة (public) أو عشوائية (random):القيمة
الاسم
المعنى
0x00PUBLIC
عنوان جهاز عام (public).
0x01RANDOM
عنوان عشوائي (إما ثابت أو RPA أو NRPA؛ ويُرمَّز النوع داخل العنوان نفسه).
تقابل قيم
adv_typeمواصفة Bluetooth:القيمة
الاسم
المعنى
0x00ADV_IND
إعلان غير موجّه قابل للاتصال والمسح.
0x01ADV_DIRECT_IND
إعلان موجّه قابل للاتصال.
0x02ADV_SCAN_IND
إعلان غير موجّه قابل للمسح.
0x03ADV_NONCONN_IND
إعلان غير موجّه وغير قابل للاتصال.
0x04SCAN_RSP
رد المسح (scan response).
يمكن ضبط
activeعلىTrueإذا كنت ترغب في استقبال ردود المسح في النتائج.عند إيقاف المسح (إما بسبب انتهاء المدة أو عند إيقافه صراحةً)، سيُطلَق الحدث
_IRQ_SCAN_DONE.
دور Central
يمكن لجهاز central أن يتصل بالأجهزة الطرفية (peripherals) التي اكتشفها باستخدام دور observer (راجع
gap_scan) أو بعنوان معروف.- gap_connect(addr_type: int | None, addr: bytes | None = None, scan_duration_ms: int = 2000, min_conn_interval_us: int | None = None, max_conn_interval_us: int | None = None, /) None¶
الاتصال بجهاز طرفي (peripheral).
راجع
gap_scanللاطلاع على تفاصيل أنواع العناوين.لإلغاء محاولة اتصال معلّقة مبكراً، استدعِ
gap_connect(None).عند النجاح، سيُطلَق الحدث
_IRQ_PERIPHERAL_CONNECT. وعند إلغاء محاولة اتصال، سيُطلَق الحدث_IRQ_PERIPHERAL_DISCONNECT.سينتظر الجهاز حتى scan_duration_ms لاستقبال حمولة إعلان من الجهاز.
يمكن تهيئة فاصل الاتصال الزمني بالميكروثانية باستخدام min_conn_interval_us أو max_conn_interval_us أو كليهما. وإلا فسيُختار فاصل زمني افتراضي، عادةً بين 30000 و50000 ميكروثانية. الفاصل الزمني الأقصر سيزيد الإنتاجية، على حساب استهلاك الطاقة.
دور Peripheral
يُتوقع من الجهاز الطرفي (peripheral) أن يرسل إعلانات قابلة للاتصال (راجع
gap_advertise). وعادةً ما يعمل كخادم GATT، بعد أن يكون قد سجّل أولاً الخدمات والخصائص باستخدامgatts_register_services.عندما يتصل جهاز central، سيُطلَق الحدث
_IRQ_CENTRAL_CONNECT.دورا Central وPeripheral
- gap_disconnect(conn_handle: int, /) bool¶
يقطع اتصال معرّف الاتصال (connection handle) المحدد. يمكن أن يكون هذا إما جهاز central متصلاً بهذا الجهاز (إن كان يعمل كجهاز طرفي) أو جهازاً طرفياً (peripheral) اتصل به هذا الجهاز سابقاً (إن كان يعمل كجهاز central).
عند النجاح، سيُطلَق الحدث
_IRQ_PERIPHERAL_DISCONNECTأو_IRQ_CENTRAL_DISCONNECT.يُرجع
Falseإذا لم يكن معرّف الاتصال متصلاً، وTrueخلاف ذلك.
GATT Server
يملك خادم GATT مجموعة من الخدمات المسجّلة. قد تحتوي كل خدمة على خصائص، ولكل منها قيمة. كما يمكن أن تحتوي الخصائص على واصفات، ولهذه الواصفات بدورها قيم.
تُخزَّن هذه القيم محلياً، ويُوصل إليها عبر "معرّف القيمة" (value handle) الخاص بها والذي يُولَّد أثناء تسجيل الخدمة. كما يمكن قراءتها أو الكتابة إليها بواسطة جهاز عميل بعيد. إضافة إلى ذلك، يمكن للخادم أن "يُشعِر" (notify) عميلاً متصلاً بخاصية ما عبر معرّف الاتصال.
يمكن لجهاز في دور central أو peripheral أن يعمل كخادم GATT، إلا أنه في معظم الحالات سيكون من الأكثر شيوعاً أن يعمل الجهاز الطرفي (peripheral) كخادم.
للخصائص والواصفات حجم أقصى افتراضي يبلغ 20 بايت (قيمة ATT MTU الافتراضية البالغة 23 بايت ناقص ترويسة ATT بحجم 3 بايت؛ والتفاوض على قيمة MTU أكبر لا يرفع هذا الحد بذاته). أي شيء يكتبه العميل إليها سيُقتطع إلى هذا الطول. غير أن أي كتابة محلية ستزيد الحجم الأقصى، لذا إذا أردت السماح بكتابات أكبر من عميل إلى خاصية معيّنة، فاستخدم
gatts_writeبعد التسجيل. مثالgatts_write(char_handle, bytes(100)).- gatts_register_services(services_definition: Sequence[Sequence], /) Sequence[Sequence[int]]¶
يُهيّئ الخادم بالخدمات المحددة، مع استبدال أي خدمات موجودة.
services_definition هي قائمة من services، حيث تكون كل service صفّاً (tuple) من عنصرين يحتوي على معرّف UUID وقائمة من characteristics.
كل characteristic هي صفّ (tuple) من عنصرين أو ثلاثة عناصر يحتوي على معرّف UUID وقيمة flags واختيارياً قائمة من descriptors.
كل descriptor هي صفّ (tuple) من عنصرين يحتوي على معرّف UUID وقيمة flags.
قيمة flags هي مزيج بعملية OR على مستوى البتات من الأعلام المعرّفة أدناه. وهي تضبط كلاً من سلوك الخاصية (أو الواصف) ومتطلبات الأمان والخصوصية.
القيمة المُرجَعة هي قائمة (عنصر واحد لكل خدمة) من الصفوف (tuples) (كل عنصر هو معرّف قيمة). تُسطَّح معرّفات الخصائص والواصفات في الصفّ نفسه، بالترتيب الذي عُرّفت به.
يسجّل المثال التالي خدمتين (Heart Rate وNordic UART):
bt = bluetooth.BLE() bt.active(True) # Heart Rate service: one Heart Rate Measurement characteristic. HR_SERVICE = ( bluetooth.UUID(0x180D), ( (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY), ), ) # Nordic UART service: a TX characteristic the client subscribes # to for notifications, and an RX characteristic it writes to. UART_SERVICE = ( bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E'), ( (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY), (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE), ), ) ((hr,), (tx, rx)) = bt.gatts_register_services( (HR_SERVICE, UART_SERVICE), )
يمكن استخدام معرّفات القيم الثلاثة (
hrوtxوrx) معgatts_readوgatts_writeوgatts_notifyوgatts_indicate.ملاحظة: يجب إيقاف الإعلان قبل تسجيل الخدمات.
الأعلام المتاحة للخصائص والواصفات هي:
الثابت
القيمة
المعنى
_FLAG_BROADCAST0x0001يمكن بث الخاصية.
_FLAG_READ0x0002يمكن للعميل قراءة القيمة.
_FLAG_WRITE_NO_RESPONSE0x0004يمكن للعميل الكتابة دون توقّع رد.
_FLAG_WRITE0x0008يمكن للعميل الكتابة مع رد مُقَر باستلامه.
_FLAG_NOTIFY0x0010يمكن للخادم إرسال إشعارات (غير مُقَر باستلامها).
_FLAG_INDICATE0x0020يمكن للخادم إرسال دلالات (indications) (مُقَر باستلامها).
_FLAG_AUTHENTICATED_SIGNED_WRITE0x0040يمكن للعميل إصدار كتابات موقّعة.
_FLAG_AUX_WRITE0x0100خصائص موسّعة: الكتابات المُصفّفة/الموثوقة مسموح بها.
_FLAG_READ_ENCRYPTED0x0200تتطلب القراءة رابطاً مشفّراً.
_FLAG_READ_AUTHENTICATED0x0400تتطلب القراءة رابطاً موثّقاً (محمياً من هجمات MITM).
_FLAG_READ_AUTHORIZED0x0800تتطلب القراءة تخويلاً على مستوى التطبيق.
_FLAG_WRITE_ENCRYPTED0x1000تتطلب الكتابة رابطاً مشفّراً.
_FLAG_WRITE_AUTHENTICATED0x2000تتطلب الكتابة رابطاً موثّقاً (محمياً من هجمات MITM).
_FLAG_WRITE_AUTHORIZED0x4000تتطلب الكتابة تخويلاً على مستوى التطبيق.
كما هو الحال مع ثوابت الأحداث أعلاه، فإن هذه الأعلام غير موفّرة من قِبل وحدة
bluetooth؛ انسخ ما تحتاجه منها إلى برنامجك.
- gatts_read(value_handle: int, /) bytes¶
تقرأ القيمة المحلية لهذا المعرّف (والتي إما كُتبت بواسطة
gatts_writeأو بواسطة عميل بعيد).
- gatts_write(value_handle: int, data: bytes, send_update: bool = False, /) None¶
تكتب القيمة المحلية لهذا المعرّف، والتي يمكن للعميل قراءتها.
إذا كانت قيمة send_update هي
True، فسيُشعَر (notify) أي عملاء مشتركين (أو ستُرسل لهم دلالة indication، حسب ما اشتركوا فيه والعمليات التي تدعمها الخاصية) بهذه الكتابة.
- gatts_notify(conn_handle: int, value_handle: int, data: bytes | None = None, /) None¶
يرسل طلب إشعار (notification) إلى عميل متصل.
إذا كانت قيمة data هي
None(القيمة الافتراضية)، فستُرسل القيمة المحلية الحالية (كما ضُبطت بواسطةgatts_write).وإلا، إذا لم تكن قيمة data هي
None، فستُرسل تلك القيمة إلى العميل كجزء من الإشعار. ولن تُعدَّل القيمة المحلية.ملاحظة: سيُرسل الإشعار بصرف النظر عن حالة اشتراك العميل في هذه الخاصية.
- gatts_indicate(conn_handle: int, value_handle: int, data: bytes | None = None, /) None¶
يرسل طلب دلالة (indication) إلى عميل متصل.
إذا كانت قيمة data هي
None(القيمة الافتراضية)، فستُرسل القيمة المحلية الحالية (كما ضُبطت بواسطةgatts_write).وإلا، إذا لم تكن قيمة data هي
None، فستُرسل تلك القيمة إلى العميل كجزء من الدلالة (indication). ولن تُعدَّل القيمة المحلية.عند الإقرار بالاستلام (أو عند الفشل، مثل انتهاء المهلة)، سيُطلَق الحدث
_IRQ_GATTS_INDICATE_DONE.ملاحظة: ستُرسل الدلالة (indication) بصرف النظر عن حالة اشتراك العميل في هذه الخاصية.
- gatts_set_buffer(value_handle: int, len: int, append: bool = False, /) None¶
يضبط حجم المخزن المؤقت الداخلي لقيمة ما بالبايت. سيحدّ هذا من أكبر كتابة ممكنة يمكن استقبالها. القيمة الافتراضية هي 20 بايت (قيمة ATT MTU الافتراضية البالغة 23 ناقص ترويسة ATT بحجم 3 بايت).
ضبط append على
Trueسيجعل جميع الكتابات البعيدة تُلحَق بالقيمة الحالية بدلاً من استبدالها. ويمكن تخزين len بايت كحد أقصى مؤقتاً بهذه الطريقة. وعند استخدامgatts_read، ستُمسح القيمة بعد القراءة. هذه الميزة مفيدة عند تنفيذ شيء مثل خدمة Nordic UART.
GATT Client
يمكن لعميل GATT اكتشاف الخصائص الموجودة على خادم GATT بعيد وقراءتها/الكتابة إليها.
من الأكثر شيوعاً أن يعمل جهاز في دور central كعميل GATT، إلا أنه من الممكن أيضاً أن يعمل جهاز طرفي (peripheral) كعميل لاكتشاف معلومات حول جهاز central الذي اتصل به (مثلاً لقراءة اسم الجهاز من خدمة معلومات الجهاز).
- gattc_discover_services(conn_handle: int, uuid: UUID | None = None, /) None¶
يستعلم من خادم متصل عن خدماته.
حدّد اختيارياً معرّف uuid لخدمة للاستعلام عن تلك الخدمة فقط.
لكل خدمة مكتشفة، سيُطلَق الحدث
_IRQ_GATTC_SERVICE_RESULT، متبوعاً بـ_IRQ_GATTC_SERVICE_DONEعند الاكتمال.
- gattc_discover_characteristics(conn_handle: int, start_handle: int, end_handle: int, uuid: UUID | None = None, /) None¶
يستعلم من خادم متصل عن الخصائص في النطاق المحدد.
حدّد اختيارياً معرّف uuid لخاصية للاستعلام عن تلك الخاصية فقط.
تمرير
start_handle=1وend_handle=0xffffيغطي كامل نطاق معرّفات سمات GATT، لذا فإن هذا المزيج يبحث فعلياً في كل خدمة على الجهاز البعيد.لكل خاصية مكتشفة، سيُطلَق الحدث
_IRQ_GATTC_CHARACTERISTIC_RESULT، متبوعاً بـ_IRQ_GATTC_CHARACTERISTIC_DONEعند الاكتمال.
- gattc_discover_descriptors(conn_handle: int, start_handle: int, end_handle: int, /) None¶
يستعلم من خادم متصل عن الواصفات في النطاق المحدد.
لكل واصف مكتشف، سيُطلَق الحدث
_IRQ_GATTC_DESCRIPTOR_RESULT، متبوعاً بـ_IRQ_GATTC_DESCRIPTOR_DONEعند الاكتمال.
- gattc_read(conn_handle: int, value_handle: int, /) None¶
يصدر طلب قراءة بعيدة إلى خادم متصل لمعرّف الخاصية أو الواصف المحدد.
عندما تتوفر قيمة، سيُطلَق الحدث
_IRQ_GATTC_READ_RESULT، متبوعاً بـ_IRQ_GATTC_READ_DONEعند الاكتمال.
- gattc_write(conn_handle: int, value_handle: int, data: bytes, mode: int = 0, /) None¶
يصدر طلب كتابة بعيدة إلى خادم متصل لمعرّف الخاصية أو الواصف المحدد.
يحدد الوسيط mode سلوك الكتابة، والقيم المدعومة حالياً هي:
mode=0(الافتراضي) هي كتابة بلا رد: ستُرسل الكتابة إلى الخادم البعيد لكن لن يُعاد أي تأكيد، ولن يُطلَق أي حدث.mode=1هي كتابة مع رد: يُطلب من الخادم البعيد إرسال رد/إقرار بأنه استلم البيانات.
إذا وُرد رد من الخادم البعيد، فسيُطلَق الحدث
_IRQ_GATTC_WRITE_DONE.
- gattc_exchange_mtu(conn_handle: int, /) None¶
يبدأ تبادل MTU مع خادم متصل، باستخدام قيمة MTU المُفضَّلة المضبوطة عبر
BLE.config(mtu=value).سيُطلَق الحدث
_IRQ_MTU_EXCHANGEDعند اكتمال تبادل MTU.عادةً ما يبدأ تبادل MTU جهاز central؛ ويدعم NimBLE كلا الدورين.
قنوات L2CAP الموجهة بالاتصال (Connection-Oriented Channels)
تتيح هذه الميزة تبادل البيانات بطريقة شبيهة بالمقابس (sockets) بين جهازي BLE. بمجرد اتصال الجهازين عبر GAP، يمكن لأي من الجهازين أن يستمع لاتصال الآخر على معرّف PSM رقمي (Protocol/Service Multiplexer).
يمكن أن تكون قناة L2CAP واحدة فقط نشطة في أي وقت معيّن (أي لا يمكنك الاتصال أثناء الاستماع).
تُعرَّف قنوات L2CAP النشطة بواسطة معرّف الاتصال الذي أُنشئت عليه ومعرّف قناة CID (channel ID).
تملك القنوات الموجهة بالاتصال تحكماً مدمجاً في تدفق البيانات قائماً على الأرصدة (credit-based flow control). على عكس ATT، حيث تتفاوض الأجهزة على قيمة MTU مشتركة، يضبط كل من الجهاز المستمِع والجهاز المتصل قيمة MTU مستقلة تحدّ من أقصى كمية بيانات معلّقة يمكن للجهاز البعيد إرسالها قبل استهلاكها بالكامل في
l2cap_recvinto.- l2cap_listen(psm: int, mtu: int, /) None¶
يبدأ الاستماع لطلبات قنوات L2CAP الواردة على معرّف psm المحدد مع ضبط قيمة MTU المحلية على mtu.
عندما يبادر جهاز بعيد بالاتصال، سيُطلَق الحدث
_IRQ_L2CAP_ACCEPT، الذي يمنح الخادم المستمِع فرصة لرفض الاتصال الوارد (بإرجاع عدد صحيح غير صفري).بمجرد قبول الاتصال، سيُطلَق الحدث
_IRQ_L2CAP_CONNECT، مما يتيح للخادم الحصول على معرّف القناة (CID) وقيمتي MTU المحلية والبعيدة.ملاحظة: ليس من الممكن حالياً إيقاف الاستماع.
- l2cap_connect(conn_handle: int, psm: int, mtu: int, /) None¶
يتصل بنظير مستمِع على معرّف psm المحدد مع ضبط قيمة MTU المحلية على mtu.
عند نجاح الاتصال، سيُطلَق الحدث
_IRQ_L2CAP_CONNECT، مما يتيح للعميل الحصول على معرّف القناة (CID) وقيمتي MTU المحلية والبعيدة (peer).الاتصال غير الناجح سيُطلق الحدث
_IRQ_L2CAP_DISCONNECTمع حالة غير صفرية.
- l2cap_disconnect(conn_handle: int, cid: int, /) None¶
يقطع اتصال قناة L2CAP نشطة بمعرّف الاتصال conn_handle ومعرّف القناة cid المحددين.
- l2cap_send(conn_handle: int, cid: int, buf: bytes, /) bool¶
يرسل المخزن المؤقت buf المحدد (والذي يجب أن يدعم بروتوكول المخزن المؤقت) على قناة L2CAP المعرّفة بـ conn_handle وcid.
يجب أن يحقق المخزن المؤقت كلا الحدّين: يجب ألا يتجاوز قيمة MTU البعيدة (peer)، ويجب ألا يتجاوز ضعف قيمة MTU المحلية.
سيُرجع هذا
Falseإذا كانت القناة الآن "متوقفة" (stalled)، مما يعني أنه يجب عدم استدعاءl2cap_sendمرة أخرى حتى يُستقبل الحدث_IRQ_L2CAP_SEND_READY(والذي سيحدث عندما يمنح الجهاز البعيد مزيداً من الأرصدة، عادةً بعد أن يكون قد استقبل البيانات وعالجها).
- l2cap_recvinto(conn_handle: int, cid: int, buf: Any | None, /) int¶
يستقبل بيانات من conn_handle وcid المحددين إلى المخزن المؤقت buf المقدَّم (والذي يجب أن يدعم بروتوكول المخزن المؤقت، مثل bytearray أو memoryview).
يُرجع عدد البايتات المقروءة من القناة.
إذا كانت قيمة buf هي
None، فإنه يُرجع عدد البايتات المتاحة.ملاحظة: بعد استقبال الحدث
_IRQ_L2CAP_RECV، ينبغي للتطبيق أن يستمر في استدعاءl2cap_recvintoحتى لا تبقى بايتات متاحة في مخزن الاستقبال المؤقت (عادةً حتى حجم قيمة MTU البعيدة (peer)).إلى أن يصبح مخزن الاستقبال المؤقت فارغاً، لن يُمنح الجهاز البعيد مزيداً من أرصدة القناة ولن يتمكن من إرسال أي بيانات إضافية.
الإقران والربط (Pairing and Bonding)
يتيح الإقران تشفير الاتصال وتوثيقه عبر تبادل الأسرار (مع حماية اختيارية من هجمات MITM عبر توثيق مفتاح المرور passkey).
الربط (Bonding) هو عملية تخزين تلك الأسرار في وحدة تخزين غير متطايرة. عندما يكون الجهاز مرتبطاً، يصبح قادراً على حلّ عنوان خاص قابل للحل (RPA) من جهاز آخر بناءً على مفتاح حلّ الهوية (IRK) المخزّن. ولدعم الربط، يجب على التطبيق تنفيذ الحدثين
_IRQ_GET_SECRETو_IRQ_SET_SECRET.- gap_pair(conn_handle: int, /) None¶
يبدأ الإقران مع الجهاز البعيد.
قبل استدعاء هذا، تأكد من ضبط خيارات التهيئة
ioوmitmوle_secureوbond(عبرconfig).عند نجاح الإقران، سيُطلَق الحدث
_IRQ_ENCRYPTION_UPDATE.
- gap_passkey(conn_handle: int, action: int, passkey: int, /) None¶
يستجيب لحدث
_IRQ_PASSKEY_ACTIONلمعرّف الاتصال conn_handle والإجراء action المحددين. يعتمد معنى passkey على action (والذي يعتمد بدوره على قدرة الإدخال/الإخراج (I/O) المُهيّأة):الإجراء
استجابة passkey المطلوبة
_PASSKEY_ACTION_INPUTمفتاح المرور الذي يقرأه المستخدم من الجهاز البعيد.
_PASSKEY_ACTION_DISPLAYمفتاح مرور عشوائي مكوّن من 6 أرقام مُولَّد محلياً ومعروض للمستخدم.
_PASSKEY_ACTION_NUMERIC_COMPARISON1لقبول مفتاح المرور المعروض في الحدث_IRQ_PASSKEY_ACTION، أو0لإلغاء الإقران.
class UUID¶
- class bluetooth.UUID(value: int | bytes | str, /)¶
ينشئ نسخة UUID بالقيمة
valueالمحددة. يستخدم Bluetooth ثلاثة أعراض لـ UUID؛ ويقبلUUIDأياً منها:عرض UUID
أنواع
valueالمقبولةمثال
16-bit
intأو مخزن مؤقت بحجم 2 بايت (little-endian)UUID(0x2908)أوUUID(b'\x08\x29')32-bit
مخزن مؤقت بحجم 4 بايت (little-endian)
UUID(b'\x08\x29\x00\x00')128-bit
مخزن مؤقت بحجم 16 بايت أو سلسلة نصية مفصولة بشرطات
UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')عادةً ما تكون معرّفات UUID بعرض 16-bit و32-bit معرّفات مخصّصة من SIG (راجع أرقام Bluetooth المخصّصة)؛ أما معرّفات UUID بعرض 128-bit فتكون عادةً معرّفة من قِبل المورّد.