تسمح Web Bluetooth API للمواقع الإلكترونية بالتواصل مع الأجهزة التي تتضمّن بلوتوث.
ماذا لو أخبرتك أن مواقع الويب يمكن أن تتصل بأجهزة بلوتوث القريبة بطريقة آمنة تحافظ على الخصوصية؟ بهذه الطريقة، يمكن لأجهزة مراقبة معدل ضربات القلب، وغناء مصابيح المصابيح الكهربائية، وحتى السلاحف التفاعل مباشرةً مع الموقع الإلكتروني.
حتى الآن، كانت إمكانية التفاعل مع الأجهزة التي تتضمّن بلوتوث متاحة فقط للتطبيقات المخصّصة للمنصة. تهدف Web Bluetooth API إلى تغيير ذلك و توفيرها لمتصفّحات الويب أيضًا.
قبل البدء
يفترض هذا المستند أنّ لديك بعض المعرفة الأساسية بكيفية عمل تقنية Bluetooth Low Energy (BLE) وGeneric Attribute Profile.
على الرغم من أنّ مواصفات Web Bluetooth API لم تكتمل بعد، يبحث مؤلفو المواصفات عن مطوّرين متحمّسين لتجربة هذه الواجهة وتقديم ملاحظاتهم حول المواصفات وتقديم ملاحظاتهم حول التنفيذ.
تتوفّر مجموعة فرعية من Web Bluetooth API في ChromeOS وChrome لنظام التشغيل Android 6.0 وMac (Chrome 56) وWindows 10 (Chrome 70). وهذا يعني أنّه يجب أن يكون بإمكانك طلب والاتصال بأجهزة Bluetooth Low Energy المجاورة وقراءة/write خصائص البلوتوث وتلقي إشعارات GATT، ومعرفة عند انقطاع اتصال جهاز بلوتوث، وحتى القراءة والكتابة إلى أدوات وصف البلوتوث. اطّلِع على جدول توافق المتصفّحات في MDN للحصول على مزيد من المعلومات.
بالنسبة إلى نظام التشغيل Linux والإصدارات الأقدم من نظام التشغيل Windows، فعِّل علامة
#experimental-web-platform-features
في about://flags
.
متوفّر لعمليات التجربة والتقييم
للحصول على أكبر قدر ممكن من الملاحظات من المطوّرين الذين يستخدمون واجهة برمجة التطبيقات Web Bluetooth API في المجال، أضاف Chrome هذه الميزة سابقًا في Chrome 53 كإصدار تجريبي أولي لنظام التشغيل ChromeOS وAndroid وMac.
وانتهت الفترة التجريبية بنجاح في كانون الثاني (يناير) 2017.
متطلبات الأمان
لفهم المفاضلات الأمنية، أنصحك بمقالة Web Bluetooth Security Model التي كتبها جيفري ياسكين، وهو مهندس برامج في فريق Chrome، ويشرف على مواصفات Web Bluetooth API.
HTTPS فقط
وبما أنّ واجهة برمجة التطبيقات التجريبية هذه هي ميزة جديدة وفعّالة تمت إضافتها إلى الويب، فإنّه لا تتوفّر إلا للسياقات الآمنة. ويعني هذا أنّك ستحتاج إلى الإنشاء مع وضع TLS في الاعتبار.
يجب أن يُجري المستخدم إيماءة
كميزة أمان، يجب أن يتم بدء اكتشاف أجهزة البلوتوث باستخدام
navigator.bluetooth.requestDevice
من خلال إيماءة المستخدم، مثل
اللمس أو النقر بالماوس. نقصد الاستماع إلى أحداث
pointerup
وclick
وtouchend
.
button.addEventListener('pointerup', function(event) {
// Call navigator.bluetooth.requestDevice
});
الاطّلاع على الرمز
تعتمد Web Bluetooth API اعتمادًا كبيرًا على وعود JavaScript. إذا لم تكن
على دراية بها، يمكنك الاطّلاع على هذا الدليل التعليمي الرائع حول الوعود. هناك شيء آخر، وهو أنّ () => {}
هي دوالّ الأسهم في ECMAScript 2015.
طلب أجهزة تتضمّن بلوتوث
يسمح هذا الإصدار من مواصفات Web Bluetooth API للمواقع الإلكترونية التي تعمل في الدور المركزي بالاتصال بخوادم GATT عن بُعد عبر اتصال BLE. ويسمح بالاتصال بين الأجهزة التي تستخدم البلوتوث 4.0 أو الإصدارات الأحدث.
عندما يطلب موقع إلكتروني الوصول إلى الأجهزة المجاورة باستخدام navigator.bluetooth.requestDevice
، يعرض المتصفّح على المستخدم أداة اختيار devices
يمكنه من خلالها اختيار جهاز واحد أو إلغاء الطلب.
تأخذ الدالة navigator.bluetooth.requestDevice()
عنصرًا إلزاميًا يحدد الفلاتر. تُستخدَم هذه الفلاتر لعرض الأجهزة التي تتطابق فقط مع بعض خدمات GATT للبلوتوث المُعلَن عنها و/أو اسم الجهاز.
فلتر الخدمات
على سبيل المثال، لطلب أجهزة بلوتوث تعرض إعلانات عن Bluetooth GATT Battery Service:
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });
إذا لم تكن خدمة Bluetooth GATT مدرَجة في قائمة خدمات GATT Bluetooth العادية، يمكنك تقديم معرّف UUID الكامل لبروتوكول Bluetooth أو نموذج قصير بحجم 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
. هذا المفتاح
هو مصفوفة من العناصر التي تحتوي على مفتاح معرّف شركة Bluetooth إلزامي باسم
companyIdentifier
. يمكنك أيضًا توفير بادئة بيانات تعمل على تصفية
بيانات الشركة المصنعة من أجهزة Bluetooth التي تبدأ بها. يُرجى العلم أنّه عليك
تحديد مفتاح 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); });
عدم استخدام الفلاتر
أخيرًا، يمكنك استخدام المفتاح acceptAllDevices
لعرض جميع الأجهزة القريبة التي تتضمّن بلوتوث بدلاً من filters
. ستحتاج أيضًا إلى تحديد مفتاح 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 الجهاز.
في المثال القادم، 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); });
إذا كنت تستخدم سمة GATT مخصّصة في البلوتوث، يمكنك تقديم إما
معرّف UUID الكامل للبلوتوث أو نموذجًا قصيرًا مكوّنًا من 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);
}
الكتابة إلى إحدى خصائص البلوتوث
إنّ الكتابة في سمة GATT في البلوتوث سهلة مثل قراءتها. هذه المرة، دعنا نستخدم نقطة التحكم في معدل ضربات القلب لإعادة تعيين قيمة حقل "Energy Expended" (الطاقة المستفادة) إلى 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 في البلوتوث هي سمات تصف قيمة سمة. ويمكنك قراءتها وكتابتها بطريقة مشابهة لخصائص 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); });
النماذج والعروض التوضيحية والدروس التطبيقية حول الترميز
تم اختبار جميع عيّنات Web Bluetooth أدناه بنجاح. للاستفادة من هذه عيّنات على أكمل وجه، أنصحك بتثبيت [BLE Peripheral Simulator Android App] الذي يحاكي جهازًا طرفيًا للبلوتوث منخفض الطاقة باستخدام خدمة البطارية أو خدمة معدل ضربات القلب أو خدمة الترمومتر الصحي.
مبتدئ
- معلومات الجهاز: استرداد معلومات الجهاز الأساسية من جهاز BLE
- مستوى البطارية: استرداد معلومات البطارية من جهاز BLE يعرض معلومات البطارية
- إعادة ضبط الطاقة: لإعادة ضبط الطاقة المستنفَدة من جهاز BLE يُعلن عن معدل ضربات القلب
- خصائص السمة: لعرض جميع خصائص سمة معيّنة من جهاز BLE
- الإشعارات: بدء إشعارات السمات وإيقافها من جهاز BLE
- إلغاء ربط الجهاز: يمكنك إلغاء ربط جهاز BLE والحصول على إشعار عند إلغاء الربط به بعد الاتصال به.
- الحصول على الخصائص: يمكنك الحصول على جميع خصائص الخدمة المعلَن عنها من جهاز BLE.
- الحصول على أدوات الوصف - احصل على أوصاف جميع خصائص الخدمة المُعلَن عنها من جهاز BLE.
- فلتر بيانات الشركة المصنّعة: استرداد معلومات الجهاز الأساسية من جهاز BLE يتطابق مع بيانات الشركة المصنّعة
- فلاتر الاستبعاد: استرداد معلومات الجهاز الأساسية من جهاز BLE يعرض فلاتر استبعاد أساسية
دمج عمليات متعددة
- سمات GAP: يمكنك الحصول على جميع سمات GAP لجهاز BLE.
- سمات معلومات الجهاز: يمكنك الحصول على جميع سمات معلومات الجهاز لجهاز BLE.
- فقدان الربط: يمكنك ضبط سمة "مستوى التنبيه" لجهاز BLE (readValue وwriteValue).
- اكتشاف الخدمات والسمات: يمكنك اكتشاف جميع الخدمات الأساسية التي يمكن الوصول إليها والسمات المرتبطة بها من جهاز BLE.
- إعادة الاتصال التلقائي: إعادة الاتصال بجهاز BLE غير متصل باستخدام خوارزمية التوقف التدرّجي
- قراءة تغيير قيمة الخصائص: يمكنك قراءة مستوى البطارية وتلقّي إشعارات بالتغييرات التي تطرأ على جهاز البلوتوث المنخفض الطاقة.
- قراءة الأوصاف: قراءة جميع أوصاف السمات لخدمة من جهاز BLE
- كتابة الوصف: كتابة الوصف "وصف المستخدم للخاصية" على جهاز BLE
يمكنك أيضًا الاطّلاع على العروض التوضيحية المنظَّمة لواجهة Web Bluetooth والإصدارات الرسمية من Web Bluetooth Codelabs.
المكتبات
- web-bluetooth-utils هي وحدة npm تضيف بعض وظائف تسهيل الاستخدام إلى واجهة برمجة التطبيقات.
- تتوفّر حزمة Web Bluetooth API shim في noble، وهي وحدة Node.js BLE central الأكثر رواجًا. ويتيح لك ذلك استخدام حزم الويب أو استخدام المتصفِّحات النبيلة بدون الحاجة إلى خادم WebSocket أو مكوّنات إضافية أخرى.
- angular-web-bluetooth هي وحدة Angular تُنشئ نموذجًا موحّدًا لجميع الإجراءات الأساسية اللازمة لضبط Web Bluetooth API.
الأدوات
- البدء باستخدام Web Bluetooth هو تطبيق ويب بسيط سينشئ كل الرمز البرمجي الجاهز لـ JavaScript لبدء التفاعل مع جهاز يتضمّن بلوتوث. أدخِل اسم جهاز أو خدمة أو سمة وحدِّد خصائصها ويمكنك المتابعة.
- إذا كنت مطوِّر تطبيقات بلوتوث، سينشئ مكوّن Web Bluetooth Developer Studio الإضافي أيضًا رمز JavaScript لتطبيق Web Bluetooth لجهازك الذي يتضمّن بلوتوث.
نصائح
تتوفّر صفحة الإعدادات الداخلية للبلوتوث في Chrome على
about://bluetooth-internals
كي تتمكّن من فحص كل البيانات المتعلّقة بالأجهزة القريبة
التي تتضمّن بلوتوث، مثل الحالة والخدمات والخصائص والأدوات الوصفية.
ننصحك أيضًا بالاطّلاع على صفحة كيفية الإبلاغ عن أخطاء Web Bluetooth الرسمية، لأنّ تصحيح أخطاء البلوتوث قد يكون صعبًا في بعض الأحيان.
الخطوات التالية
تحقَّق أولاً من حالة تنفيذ المتصفّح والنظام الأساسي لمعرفة الأجزاء من Web Bluetooth API التي يتم تنفيذها حاليًا.
على الرغم من أنّ هذه الميزة لا تزال غير مكتملة، إليك نظرة سريعة على ما يمكن توقّعه في القريب المستقبل:
- سيتم إجراء البحث عن "إعلانات BLE" قريبة
في
navigator.bluetooth.requestLEScan()
. - سيتتبّع الحدث الجديد
serviceadded
خدمات GATT في البلوتوث التي تم اكتشافها حديثًا، بينما سيتتبّع الحدثserviceremoved
الخدمات التي تمّت إزالتها. سيتم بدء حدثservicechanged
جديد عند إضافة أيّ سمة و/أو وصف أو إزالتهما من خدمة GATT في البلوتوث.
إظهار الدعم لواجهة برمجة التطبيقات
هل تخطّط لاستخدام Web Bluetooth API؟ يساعد دعمك العلني فريق Chrome في تحديد الميزات ذات الأولوية وإظهار مدى أهمية توفيرها في المتصفّحات الأخرى.
أرسِل تغريدة إلى @ChromiumDev باستخدام الهاشتاغ
#WebBluetooth
وأطلِعنا على مكان استخدامك للميزة وطريقة استخدامك لها.
الموارد
- Stack Overflow
- حالة ميزات Chrome
- أخطاء تنفيذ Chrome
- مواصفات تقنية البلوتوث على الويب
- مشاكل المواصفات على GitHub
- تطبيق محاكي الأجهزة الطرفية للبلوتوث منخفض الطاقة
الشكر والتقدير
نشكر Kayce Basques على مراجعة هذه المقالة. صورة رئيسية بواسطة SparkFun Electronics من Bolder، الولايات المتحدة الأمريكية.