التواصل مع الأجهزة التي تتضمّن بلوتوث عبر JavaScript

تسمح واجهة برمجة تطبيقات بلوتوث الويب للمواقع الإلكترونية بالاتصال بأجهزة البلوتوث.

François Beaufort
François Beaufort

ماذا لو أخبرتك بأنّ المواقع الإلكترونية يمكن أن تتصل بالأجهزة القريبة التي تتضمّن بلوتوث؟ بطريقة آمنة تحافظ على الخصوصية؟ بهذه الطريقة، يتم رصد معدل ضربات القلب والغناء والمصابيح الكهربائية، وحتى السلاحف يمكنها التفاعل مباشرةً مع موقع إلكتروني.

حتى الآن، يمكن التفاعل مع الأجهزة التي تتضمّن بلوتوث. للتطبيقات الخاصة بنظام التشغيل فقط. تهدف واجهة برمجة تطبيقات Web Bluetooth API إلى تغيير ينقله إلى متصفحات الويب أيضًا.

قبل أن نبدأ

يفترض هذا المستند أن لديك بعض المعرفة الأساسية حول كيفية انخفاض مستوى البلوتوث يعمل كل من الطاقة (BLE) والملف الشخصي للسمة العامة.

على الرغم من أنه لم يتم الانتهاء بعد من مواصفات Web Bluetooth API، لا يبحث المؤلفون بشكل نشط عن مطورين متحمسين لتجربة واجهة برمجة التطبيقات هذه قدِّم ملاحظاتك حول المواصفات وملاحظات حول عملية التنفيذ.

تتوفّر مجموعة فرعية من Web Bluetooth API في نظام التشغيل ChromeOS وChrome لنظام Android 6.0 وMac (Chrome 56) وWindows 10 (Chrome 70). هذا يعني أنك يجب أن تكون قادرًا طلب والاتصال بالأجهزة القريبة التي تعمل بالبلوتوث منخفض الطاقة قراءة/كتابة خصائص بلوتوث، تلقي إشعارات GATT، معرفة عند انقطاع اتصال جهاز بلوتوث، وحتى القراءة والكتابة إلى أدوات وصف البلوتوث راجع جدول توافق المتصفح الخاص بشبكة MDN لمعرفة المزيد. المعلومات.

بالنسبة إلى نظام التشغيل Linux والإصدارات السابقة من Windows، فعّل تم الإبلاغ عن #experimental-web-platform-features في about://flags.

متاحة لمرحلة التجربة والتقييم

للحصول على أكبر قدر ممكن من الملاحظات من المطورين الذين يستخدمون الويب واجهة برمجة تطبيقات البلوتوث في الحقل، أضاف Chrome هذه الميزة من قبل في Chrome 53 كإصدار تجريبي المصدر لنظام التشغيل ChromeOS وAndroid وMac.

انتهت الفترة التجريبية بنجاح في كانون الثاني (يناير) 2017.

متطلبات الأمان

ننصحك باستخدام Web Bluetooth Security (بروتوكول أمان البلوتوث في الويب) لمعرفة الإيجابيات والسلبيات المتعلّقة بالأمان. مشاركة حول النموذج نشرها "جيفري ياسكين"، مهندس برمجيات في فريق Chrome نعمل على مواصفات واجهة برمجة تطبيقات بلوتوث الويب.

HTTPS فقط

ولأن واجهة برمجة التطبيقات التجريبية هذه هي ميزة جديدة قوية تمت إضافتها إلى الويب، فهي إتاحتها فقط للسياقات الآمنة. هذا يعني أنك ستحتاج إلى البناء باستخدام وضع TLS في الاعتبار.

إيماءة المستخدم مطلوبة

كميزة أمان، يمكن اعتبار اكتشاف أجهزة بلوتوث المزودة بـ يجب تشغيل navigator.bluetooth.requestDevice من خلال إيماءة مستخدم مثل كلمسة أو نقرة بالماوس. نحن نتحدث عن الاستماع إلى حدث pointerup وclick وtouchend.

button.addEventListener('pointerup', function(event) {
  // Call navigator.bluetooth.requestDevice
});

الدخول في الرمز

تعتمد Web Bluetooth API اعتمادًا كبيرًا على وعود JavaScript. إذا لم تكن اطّلِع على هذا الدليل التعليمي حول التعهدات هناك شيء آخر، () => {} هي دوال السهم ECMAScript 2015.

طلب الحصول على أجهزة تتضمّن بلوتوث

يسمح هذا الإصدار من مواصفات واجهة برمجة تطبيقات بلوتوث الويب للمواقع الإلكترونية التي تعمل في الدور المركزي، للاتصال بخوادم GATT عن بُعد عبر اتصال BLE. أُنشأها جون هنتر، الذي كان متخصصًا يتيح الاتصال بين الأجهزة التي تستخدم الإصدار 4.0 من البلوتوث أو الإصدارات الأحدث.

عندما يطلب موقع ويب الوصول إلى الأجهزة المجاورة باستخدام navigator.bluetooth.requestDevice، يطلب المتصفّح من المستخدم الوصول إلى جهاز. محدد حيث يمكنهم اختيار جهاز واحد أو إلغاء الطلب.

طلب من مستخدم جهاز يتضمّن بلوتوث:

تستخدم الدالة navigator.bluetooth.requestDevice() كائنًا إلزاميًا تحدد عوامل التصفية. تُستخدَم هذه الفلاتر لعرض الأجهزة التي تتطابق مع بعض البيانات فقط خدمات Bluetooth GATT المُعلَن عنها و/أو اسم الجهاز.

فلتر الخدمات

على سبيل المثال، لطلب أجهزة بلوتوث التي تعلن عن Bluetooth GATT خدمة البطارية:

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });

إذا لم تكن خدمة Bluetooth GATT مُدرَجة في قائمة إعدادات البلوتوث الموحّدة خدمات GATT، يمكنك توفير إما المعرّف الفريد العالمي (UUID) للبلوتوث الكامل أو معرّف قصير نموذج 16 أو 32 بت

navigator.bluetooth.requestDevice({
  filters: [{
    services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
  }]
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

فلتر الأسماء

يمكنك أيضًا طلب الأجهزة التي تتضمّن بلوتوث استنادًا إلى اسم الجهاز الذي يتم الإعلان عنه. باستخدام مفتاح فلاتر name أو حتى بادئة بهذا الاسم مع namePrefix مفتاح التصفية. لاحظ أنه في هذه الحالة، ستحتاج أيضًا إلى تحديد مفتاح optionalServices للوصول إلى أي خدمات غير مضمّنة في فلتر الخدمة. إذا لم تفعل ذلك، ستظهر لك رسالة خطأ لاحقًا عند محاولة الوصول معهم.

navigator.bluetooth.requestDevice({
  filters: [{
    name: 'Francois robot'
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

فلتر بيانات الشركة المصنّعة

من الممكن أيضًا طلب الأجهزة التي تتضمّن بلوتوث استنادًا إلى الشركة المصنِّعة البيانات المحدّدة التي يتمّ الإعلان عنها باستخدام مفتاح فلاتر manufacturerData. هذا المفتاح عبارة عن مصفوفة من الكائنات التي تتضمن مفتاح معرّف شركة بلوتوث إلزاميًا باسم companyIdentifier ويمكنك أيضًا إدخال بادئة بيانات تتم فلترتها بيانات الشركة المصنّعة من الأجهزة التي تتضمّن بلوتوث التي تبدأ بها. لاحظ أنك سوف عليك أيضًا تحديد مفتاح optionalServices ليتمكن من الوصول إلى أي خدمات لم يتم تضمينها في فلتر الخدمة. إذا لم تفعل ذلك، ستتلقى رسالة خطأ لاحقًا عند محاولة الوصول إليها.

// Filter Bluetooth devices from Google company with manufacturer data bytes
// that start with [0x01, 0x02].
navigator.bluetooth.requestDevice({
  filters: [{
    manufacturerData: [{
      companyIdentifier: 0x00e0,
      dataPrefix: new Uint8Array([0x01, 0x02])
    }]
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

يمكن أيضًا استخدام القناع مع بادئة بيانات لمطابقة بعض الأنماط في بيانات الشركة المصنعة. يمكنك الاطّلاع على شرح حول فلاتر بيانات البلوتوث للتعرّف على كيفية إجراء ذلك. أخرى.

فلاتر الاستبعاد

يتيح الخيار exclusionFilters في navigator.bluetooth.requestDevice() استبعاد بعض الأجهزة من أداة اختيار المتصفّح يمكن استخدامه لاستبعاد الأجهزة التي تطابق فلترًا أوسع نطاقًا، ولكنّها غير متوافقة

// Request access to a bluetooth device whose name starts with "Created by".
// The device named "Created by Francois" has been reported as unsupported.
navigator.bluetooth.requestDevice({
  filters: [{
    namePrefix: "Created by"
  }],
  exclusionFilters: [{
    name: "Created by Francois"
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

عدم استخدام الفلاتر

أخيرًا، بدلاً من filters يمكنك استخدام المفتاح acceptAllDevices لعرض كل الأجهزة القريبة التي تتضمّن بلوتوث. عليك أيضًا تحديد optionalServices. لكي تتمكن من الوصول إلى بعض الخدمات. إذا لم تفعل ذلك، ستظهر لك رسالة خطأ لاحقًا عند محاولة الوصول إليها.

navigator.bluetooth.requestDevice({
  acceptAllDevices: true,
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

الاتصال بجهاز بلوتوث

إذًا، ما هي الخطوات التي يمكنك اتّباعها الآن بعد الحصول على BluetoothDevice؟ دعونا نتواصل مع خادم GATT عن بُعد عبر البلوتوث والذي يضم الخدمة والميزات التعريفات.

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => {
  // Human-readable name of the device.
  console.log(device.name);

  // Attempts to connect to remote GATT Server.
  return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });

قراءة إحدى خصائص البلوتوث

هنا نتصل بخادم GATT الخاص بجهاز البلوتوث البعيد. الآن نحن يريدون الحصول على خدمة GATT أساسية وقراءة إحدى الخصائص التي تنتمي إلى هذه الخدمة. ولنجرب، على سبيل المثال، قراءة مستوى الشحن الحالي بطارية الجهاز.

في المثال القادم، battery_level هو مستوى البطارية الموحّد سمة:

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => device.gatt.connect())
.then(server => {
  // Getting Battery Service…
  return server.getPrimaryService('battery_service');
})
.then(service => {
  // Getting Battery Level Characteristic…
  return service.getCharacteristic('battery_level');
})
.then(characteristic => {
  // Reading Battery Level…
  return characteristic.readValue();
})
.then(value => {
  console.log(`Battery percentage is ${value.getUint8(0)}`);
})
.catch(error => { console.error(error); });

إذا كنت تستخدم ميزة Bluetooth GATT مخصصة، يمكنك تقديم إما معرف فريد كامل للبلوتوث أو نموذج قصير 16 أو 32 بت service.getCharacteristic

يُرجى ملاحظة أنه يمكنك أيضًا إضافة أداة معالجة حدث characteristicvaluechanged على مميزة للتعامل مع قراءة قيمتها. اطلع على خاصية القراءة نموذج القيمة التي تم تغييرها لمعرفة كيفية التعامل بشكل اختياري مع GATT القادم والإشعارات كذلك.

…
.then(characteristic => {
  // Set up event listener for when characteristic value changes.
  characteristic.addEventListener('characteristicvaluechanged',
                                  handleBatteryLevelChanged);
  // Reading Battery Level…
  return characteristic.readValue();
})
.catch(error => { console.error(error); });

function handleBatteryLevelChanged(event) {
  const batteryLevel = event.target.value.getUint8(0);
  console.log('Battery percentage is ' + batteryLevel);
}

الكتابة إلى إحدى خصائص البلوتوث

الكتابة إلى خاصية Bluetooth GATT سهلة مثل قراءتها. هذه المرة، لنستخدم نقطة التحكم في معدل ضربات القلب لإعادة ضبط قيمة الطاقة المستهلَكة إلى 0 على جهاز مراقبة معدل ضربات القلب.

أعدك أنه ليس هناك سحر هنا. وقد تم شرح كل ذلك في مقالة التحكّم في معدّل نبضات القلب. صفحة "خصائص النقاط"

navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_control_point'))
.then(characteristic => {
  // Writing 1 is the signal to reset energy expended.
  const resetEnergyExpended = Uint8Array.of(1);
  return characteristic.writeValue(resetEnergyExpended);
})
.then(_ => {
  console.log('Energy expended has been reset.');
})
.catch(error => { console.error(error); });

تلقّي إشعارات GATT

والآن، لنرى كيف يتم إعلامك عند استخدام قياس معدل ضربات القلب التغييرات في الخصائص على الجهاز:

navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_measurement'))
.then(characteristic => characteristic.startNotifications())
.then(characteristic => {
  characteristic.addEventListener('characteristicvaluechanged',
                                  handleCharacteristicValueChanged);
  console.log('Notifications have been started.');
})
.catch(error => { console.error(error); });

function handleCharacteristicValueChanged(event) {
  const value = event.target.value;
  console.log('Received ' + value);
  // TODO: Parse Heart Rate Measurement value.
  // See https://github.com/WebBluetoothCG/demos/blob/gh-pages/heart-rate-sensor/heartRateSensor.js
}

يعرض لك نموذج الإشعارات كيفية إيقاف الإشعارات باستخدام stopNotifications() وإزالة characteristicvaluechanged المُضافة بشكل صحيح أداة معالجة الأحداث.

إلغاء الربط بجهاز يتضمّن بلوتوث

لتوفير تجربة أفضل للمستخدم، قد تحتاج إلى الاستماع إلى أحداث قطع الاتصال وادعُ المستخدم لإعادة الاتصال:

navigator.bluetooth.requestDevice({ filters: [{ name: 'Francois robot' }] })
.then(device => {
  // Set up event listener for when device gets disconnected.
  device.addEventListener('gattserverdisconnected', onDisconnected);

  // Attempts to connect to remote GATT Server.
  return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });

function onDisconnected(event) {
  const device = event.target;
  console.log(`Device ${device.name} is disconnected.`);
}

يمكنك أيضًا الاتصال بـ device.gatt.disconnect() لإلغاء ربط تطبيق الويب جهاز يتضمّن بلوتوث. سيؤدي ذلك إلى تشغيل حدث gattserverdisconnected الحالي. المستمعين. ملاحظة: لن يتم إيقاف الاتصال بجهاز البلوتوث إذا كانت هناك يجري تطبيق اتصال بالفعل مع الجهاز الذي يتضمن بلوتوث. تحقق من الجهاز إلغاء ربط النموذج ونموذج إعادة الربط التلقائي للاطّلاع على مزيد من التفاصيل

القراءة والكتابة إلى الأدوات الوصفية التي تعمل بالبلوتوث

واصفات GATT للبلوتوث هي سمات تصف قيمة مميزة. يمكنك قراءتها والكتابة إليها بطريقة مشابهة لـ Bluetooth GATT وسماتها الشخصية.

لنرَ مثلاً كيفية قراءة وصف المستخدم للقياس. الفاصل الزمني لميزان الحرارة المتعلّق بالصحة في الجهاز

في المثال أدناه، تشير health_thermometer إلى خدمة ميزان الحرارة الصحي، measurement_interval خاصية فاصل القياس gatt.characteristic_user_description وصف المستخدم المميز .

navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => descriptor.readValue())
.then(value => {
  const decoder = new TextDecoder('utf-8');
  console.log(`User Description: ${decoder.decode(value)}`);
})
.catch(error => { console.error(error); });

والآن بعد أن قرأنا وصف المستخدم للفاصل الزمني للقياس لمقياس درجة الحرارة في جهازك، لنرَ كيفية تعديله ونكتب

navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => {
  const encoder = new TextEncoder('utf-8');
  const userDescription = encoder.encode('Defines the time between measurements.');
  return descriptor.writeValue(userDescription);
})
.catch(error => { console.error(error); });

النماذج والعروض التوضيحية والدروس التطبيقية حول الترميز

تم بنجاح اختبار جميع نماذج البلوتوث على الويب أدناه. للاستمتاع بهذه الألعاب البيانات إلى أقصى حد، فأوصيك بتثبيت [BLE Peripheral Simulator تطبيق Android] الذي يحاكي جهازًا ملحقًا بتقنية البلوتوث المنخفض الطاقة (BLE) من خلال خدمة البطارية، وهي ميزة معدّل نبضات القلب أو خدمة ميزان حرارة صحي.

مبتدئ

الجمع بين عمليات متعددة

يمكنك أيضًا الاطّلاع على عروض Web Bluetooth التجريبية التي تم تنظيمها والدروس التطبيقية الرسمية حول ترميز Web Bluetooth.

المكتبات

  • web-bluetooth-utils عبارة عن وحدة npm تضيف بعض الوظائف الملائمة إلى واجهة برمجة التطبيقات.
  • يتوفّر دعم واجهة برمجة التطبيقات Web Bluetooth API في noble، وهو الأكثر شيوعًا في Node.js BLE الوحدة المركزية. يتيح لك ذلك استخدام حزم الويب أو المتصفّحات الذكية بدون الحاجة إلى لخادم WebSocket أو مكوّنات إضافية أخرى.
  • angular-web-bluetooth هي وحدة لتقنية Angular تمت إزالة جميع يجب أن يتوفّر نصّ نموذجي لإعداد Web Bluetooth API.

الأدوات

نصائح

تتوفر صفحة الإعدادات الداخلية للبلوتوث في Chrome على about://bluetooth-internals كي تتمكّن من فحص كل العناصر المجاورة الأجهزة التي تتضمّن بلوتوث: الحالة والخدمات والخصائص والأدوات الوصفية

لقطة شاشة للصفحة الداخلية لتصحيح أخطاء البلوتوث في Chrome
صفحة داخلية في Chrome لتصحيح أخطاء الأجهزة التي تتضمّن بلوتوث

أنصحك أيضًا بالاطّلاع على صفحة كيفية الإبلاغ عن أخطاء Web Bluetooth الرسمي. لأن تصحيح أخطاء البلوتوث قد يكون صعبًا في بعض الأحيان.

الخطوات التالية

تحقّق أولاً من حالة تنفيذ المتصفّح والنظام الأساسي لمعرفة الأجزاء. يتم حاليًا تنفيذ واجهة برمجة تطبيقات Web Bluetooth.

على الرغم من أنها لا تزال غير مكتملة، إليك نظرة سريعة على ما يمكن توقعه في المستقبل:

  • جارٍ البحث عن إعلانات قريبة من البلوتوث المنخفض الطاقة (BLE) سيحدث مع navigator.bluetooth.requestLEScan().
  • سيتتبّع حدث serviceadded الجديد خدمات Bluetooth GATT التي تم اكتشافها مؤخرًا في حين أنّ حدث واحد (serviceremoved) سيتتبّع الأحداث التي تمّت إزالتها. servicechanged جديد فسيتم تنشيط الحدث عند إضافة أي خاصية و/أو واصف أو من خدمة Bluetooth GATT.

إظهار الدعم لواجهة برمجة التطبيقات

هل تخطط لاستخدام واجهة برمجة تطبيقات Web Bluetooth؟ يساعد دعمك العام فريق Chrome تحديد أولويات الميزات وإظهار لموردي المتصفحات الآخرين مدى أهمية دعمها.

إرسال تغريدة إلى @ChromiumDev باستخدام علامة التصنيف #WebBluetooth عليك إعلامنا بمكان تطبيقك وطريقة استخدامه

الموارد

شكر وتقدير

نشكر كايس باسك على مراجعة هذه المقالة. صورة رئيسية بواسطة SparkFun Electronics من Bolder، الولايات المتحدة الأمريكية.