Berkomunikasi dengan perangkat Bluetooth melalui JavaScript

Web Bluetooth API memungkinkan situs berkomunikasi dengan perangkat Bluetooth.

François Beaufort
François Beaufort

Bagaimana jika saya memberi tahu Anda bahwa situs dapat berkomunikasi dengan perangkat Bluetooth di sekitar dengan cara yang aman dan menjaga privasi? Dengan cara ini, pemantau detak jantung, lampu bohlam yang bernyanyi, dan bahkan kura-kura dapat berinteraksi langsung dengan situs.

Hingga saat ini, kemampuan untuk berinteraksi dengan perangkat Bluetooth hanya dapat dilakukan untuk aplikasi khusus platform. Web Bluetooth API bertujuan untuk mengubah ini dan juga menghadirkannya ke browser web.

Sebelum kita mulai

Dokumen ini mengasumsikan bahwa Anda memiliki beberapa pengetahuan dasar tentang cara kerja Bluetooth Hemat Energi (BLE) dan Profil Atribut Generik.

Meskipun spesifikasi Web Bluetooth API belum selesai, penulis spec secara aktif mencari developer yang antusias untuk mencoba API ini dan memberikan masukan tentang spesifikasi dan masukan tentang implementasi.

Sebagian Web Bluetooth API tersedia di ChromeOS, Chrome untuk Android 6.0, Mac (Chrome 56), dan Windows 10 (Chrome 70). Artinya, Anda harus dapat meminta dan terhubung ke perangkat Bluetooth Hemat Energi di sekitar, membaca/write karakteristik Bluetooth, menerima Notifikasi GATT, mengetahui saat perangkat Bluetooth terputus, dan bahkan membaca dan menulis ke deskripsi Bluetooth. Lihat tabel Kompatibilitas browser MDN untuk mengetahui informasi selengkapnya.

Untuk Linux dan Windows versi sebelumnya, aktifkan tanda #experimental-web-platform-features di about://flags.

Tersedia untuk uji coba origin

Untuk mendapatkan masukan sebanyak mungkin dari developer yang menggunakan Web Bluetooth API di lapangan, sebelumnya Chrome telah menambahkan fitur ini di Chrome 53 sebagai uji coba origin untuk ChromeOS, Android, dan Mac.

Uji coba telah berhasil berakhir pada Januari 2017.

Persyaratan keamanan

Untuk memahami kompromi keamanan, sebaiknya baca postingan Model Keamanan Web Bluetooth dari Jeffrey Yasskin, seorang engineer software di tim Chrome, yang mengerjakan spesifikasi Web Bluetooth API.

Khusus HTTPS

Karena API eksperimental ini merupakan fitur baru dan canggih yang ditambahkan ke web, API tersebut hanya disediakan untuk mengamankan konteks. Ini berarti Anda harus membuat aplikasi dengan mempertimbangkan TLS.

Diperlukan gestur pengguna

Sebagai fitur keamanan, penemuan perangkat Bluetooth dengan navigator.bluetooth.requestDevice harus dipicu oleh gestur pengguna seperti sentuhan atau klik mouse. Kita akan memproses peristiwa pointerup, click, dan touchend.

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

Mempelajari kode

Web Bluetooth API sangat bergantung pada Promise JavaScript. Jika Anda belum terbiasa dengan promise, lihat Tutorial Promises yang bagus ini. Satu hal lagi, () => {} adalah Fungsi Panah ECMAScript 2015.

Meminta perangkat Bluetooth

Versi spesifikasi Web Bluetooth API ini memungkinkan situs, yang berjalan dalam peran Pusat, untuk terhubung ke Server GATT jarak jauh melalui koneksi BLE. Fitur ini mendukung komunikasi antarperangkat yang menerapkan Bluetooth 4.0 atau yang lebih baru.

Saat situs meminta akses ke perangkat di sekitar menggunakan navigator.bluetooth.requestDevice, browser akan meminta pengguna dengan pemilih perangkat agar mereka dapat memilih satu perangkat atau membatalkan permintaan.

Perintah pengguna perangkat Bluetooth.

Fungsi navigator.bluetooth.requestDevice() menggunakan objek wajib yang menentukan filter. Filter ini digunakan untuk hanya menampilkan perangkat yang cocok dengan beberapa layanan GATT Bluetooth yang diiklankan dan/atau nama perangkat.

Filter layanan

Misalnya, untuk meminta perangkat Bluetooth mengiklankan Layanan Baterai GATT Bluetooth:

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

Namun, jika Layanan GATT Bluetooth Anda tidak tercantum dalam daftar layanan GATT Bluetooth standar, Anda dapat memberikan UUID Bluetooth lengkap atau bentuk 16-bit atau 32-bit singkat.

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

Filter nama

Anda juga dapat meminta perangkat Bluetooth berdasarkan nama perangkat yang diiklankan dengan kunci filter name, atau bahkan awalan nama ini dengan kunci filter namePrefix. Perhatikan bahwa dalam hal ini, Anda juga harus menentukan kunci optionalServices agar dapat mengakses layanan apa pun yang tidak disertakan dalam filter layanan. Jika tidak, Anda akan mendapatkan error nanti saat mencoba mengaksesnya.

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

Filter data produsen

Anda juga dapat meminta perangkat Bluetooth berdasarkan data khusus produsen yang diiklankan dengan kunci filter manufacturerData. Kunci ini adalah array objek dengan kunci ID perusahaan Bluetooth wajib bernama companyIdentifier. Anda juga dapat menyediakan awalan data yang memfilter data produsen dari perangkat Bluetooth yang diawali dengannya. Perhatikan bahwa Anda juga perlu menentukan kunci optionalServices agar dapat mengakses layanan apa pun yang tidak disertakan dalam filter layanan. Jika tidak, Anda akan mendapatkan error nanti saat mencoba mengaksesnya.

// 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); });

Masker juga dapat digunakan dengan awalan data untuk mencocokkan beberapa pola dalam data produsen. Lihat penjelasan filter data Bluetooth untuk mempelajari lebih lanjut.

Filter pengecualian

Opsi exclusionFilters di navigator.bluetooth.requestDevice() memungkinkan Anda mengecualikan beberapa perangkat dari pemilih browser. Filter ini dapat digunakan untuk mengecualikan perangkat yang cocok dengan filter yang lebih luas, tetapi tidak didukung.

// 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); });

Tanpa filter

Terakhir, Anda dapat menggunakan kunci acceptAllDevices, bukan filters, untuk menampilkan semua perangkat Bluetooth di sekitar. Anda juga harus menentukan kunci optionalServices agar dapat mengakses beberapa layanan. Jika tidak, Anda akan mendapatkan pesan {i>error<i} saat mencoba mengaksesnya.

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

Menyambungkan ke perangkat Bluetooth

Jadi, apa yang harus Anda lakukan sekarang setelah memiliki BluetoothDevice? Mari hubungkan ke Server GATT jarak jauh Bluetooth yang menyimpan definisi layanan dan karakteristik.

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); });

Membaca Karakteristik Bluetooth

Di sini kita terhubung ke Server GATT dari perangkat Bluetooth jarak jauh. Sekarang kita ingin mendapatkan Layanan GATT Utama dan membaca karakteristik yang dimiliki layanan ini. Mari kita coba, misalnya, membaca level pengisian daya saat ini dari baterai perangkat.

Pada contoh di depan, battery_level adalah Karakteristik Tingkat Baterai standar.

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); });

Jika menggunakan karakteristik GATT Bluetooth kustom, Anda dapat memberikan UUID Bluetooth lengkap atau format 16-bit atau 32-bit singkat ke service.getCharacteristic.

Perhatikan bahwa Anda juga dapat menambahkan pemroses peristiwa characteristicvaluechanged pada karakteristik untuk menangani pembacaan nilainya. Lihat Contoh Perubahan Nilai Karakteristik Baca untuk melihat cara menangani notifikasi GATT mendatang secara opsional.


.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);
}

Menulis ke Karakteristik Bluetooth

Menulis ke Karakteristik GATT Bluetooth semudah membacanya. Kali ini, mari kita gunakan Titik Kontrol Detak Jantung untuk mereset nilai kolom Energi yang Dikeluarkan ke 0 di perangkat pemantau detak jantung.

Saya janji tidak ada sihir di sini. Semuanya dijelaskan di halaman Karakteristik Titik Kontrol Detak Jantung.

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); });

Menerima notifikasi GATT

Sekarang, mari kita lihat cara mendapatkan notifikasi saat karakteristik Pengukuran Detak Jantung berubah di perangkat:

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
}

Contoh Notifikasi menunjukkan cara menghentikan notifikasi dengan stopNotifications() dan menghapus pemroses peristiwa characteristicvaluechanged yang ditambahkan dengan benar.

Memutuskan Sambungan dari Perangkat Bluetooth

Untuk memberikan pengalaman pengguna yang lebih baik, sebaiknya Anda memproses peristiwa pemutusan koneksi dan mengundang pengguna untuk terhubung kembali:

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.`);
}

Anda juga dapat memanggil device.gatt.disconnect() untuk memutuskan hubungan aplikasi web dari perangkat Bluetooth. Tindakan ini akan memicu pemroses peristiwa gattserverdisconnected yang ada. Perhatikan bahwa aplikasi TIDAK akan menghentikan komunikasi perangkat Bluetooth jika aplikasi lain sudah berkomunikasi dengan perangkat Bluetooth. Lihat Contoh Putus Koneksi Perangkat dan Contoh Penghubungan Kembali Otomatis untuk mempelajari lebih lanjut.

Membaca dan menulis ke deskripsi Bluetooth

Deskriptor GATT Bluetooth adalah atribut yang mendeskripsikan nilai karakteristik. Anda dapat membaca dan menulisnya dengan cara yang mirip dengan karakteristik GATT Bluetooth.

Mari kita lihat misalnya cara membaca deskripsi pengguna tentang interval pengukuran termometer kesehatan perangkat.

Pada contoh di bawah, health_thermometer adalah layanan Thermometer Kesehatan, measurement_interval karakteristik Interval Pengukuran, dan gatt.characteristic_user_description deskriptor Deskripsi Pengguna Karakteristik.

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); });

Setelah membaca deskripsi pengguna tentang interval pengukuran termometer kesehatan perangkat, mari kita lihat cara memperbaruinya dan menulis nilai kustom.

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); });

Contoh, demo, dan codelab

Semua contoh Bluetooth Web di bawah telah berhasil diuji. Untuk menikmati contoh ini secara maksimal, sebaiknya instal [Aplikasi Android BLE Peripheral Simulator] yang menyimulasikan periferal BLE dengan Layanan Baterai, Layanan Denyut Jantung, atau Layanan Termometer Kesehatan.

Pemula

  • Info Perangkat - mengambil informasi perangkat dasar dari Perangkat BLE.
  • Level Baterai - mengambil informasi baterai dari Perangkat BLE yang mengiklankan informasi Baterai.
  • Reset Energi - mereset energi yang dikeluarkan dari Detak Jantung iklan Perangkat BLE.
  • Properti Karakteristik - menampilkan semua properti karakteristik tertentu dari Perangkat BLE.
  • Notifikasi - memulai dan menghentikan notifikasi karakteristik dari Perangkat BLE.
  • Putus Sambungan Perangkat - memutuskan sambungan dan mendapatkan notifikasi dari pemutusan sambungan Perangkat BLE setelah terhubung ke perangkat tersebut.
  • Get Characteristics - mendapatkan semua karakteristik layanan yang diiklankan dari Perangkat BLE.
  • Get Descriptors - mendapatkan semua deskripsi karakteristik layanan yang diiklankan dari Perangkat BLE.
  • Filter Data Produsen - mengambil informasi perangkat dasar dari Perangkat BLE yang cocok dengan data produsen.
  • Filter Pengecualian - mengambil informasi perangkat dasar dari Perangkat BLE yang menampilkan filter pengecualian dasar.

Menggabungkan beberapa operasi

Lihat Demo Bluetooth Web yang diseleksi dan juga Codelab Bluetooth Web resmi.

Perpustakaan

  • web-bluetooth-utils adalah modul npm yang menambahkan beberapa fungsi praktis ke API.
  • Shim Web Bluetooth API tersedia di noble, modul pusat BLE Node.js yang paling populer. Hal ini memungkinkan Anda melakukan webpack/browserify noble tanpa memerlukan server WebSocket atau plugin lainnya.
  • angular-web-bluetooth adalah modul untuk Angular yang memisahkan semua boilerplate yang diperlukan untuk mengonfigurasi Web Bluetooth API.

Alat

  • Memulai dengan Web Bluetooth adalah Aplikasi Web sederhana yang akan membuat semua kode boilerplate JavaScript untuk mulai berinteraksi dengan perangkat Bluetooth. Masukkan nama perangkat, layanan, karakteristik, tentukan propertinya, dan Anda siap memulai.
  • Jika Anda sudah menjadi developer Bluetooth, Plugin Web Bluetooth Developer Studio juga akan membuat kode JavaScript Web Bluetooth untuk perangkat Bluetooth Anda.

Tips

Halaman Internal Bluetooth tersedia di Chrome di about://bluetooth-internals sehingga Anda dapat memeriksa semua tentang perangkat Bluetooth terdekat: status, layanan, karakteristik, dan deskripsi.

Screenshot halaman internal untuk men-debug Bluetooth di Chrome
Halaman internal di Chrome untuk men-debug perangkat Bluetooth.

Sebaiknya lihat juga halaman resmi Cara melaporkan bug Bluetooth Web karena proses debug Bluetooth terkadang sulit.

Langkah berikutnya

Periksa status implementasi browser dan platform terlebih dahulu untuk mengetahui bagian Web Bluetooth API yang saat ini sedang diimplementasikan.

Meskipun masih belum selesai, berikut adalah cuplikan hal-hal yang akan hadir dalam waktu dekat:

  • Pemindaian iklan BLE di sekitar akan dilakukan dengan navigator.bluetooth.requestLEScan().
  • Peristiwa serviceadded baru akan melacak Layanan GATT Bluetooth yang baru ditemukan, sedangkan peristiwa serviceremoved akan melacak layanan yang dihapus. Peristiwa servicechanged baru akan diaktifkan saat karakteristik dan/atau deskripsi ditambahkan atau dihapus dari Layanan GATT Bluetooth.

Menampilkan dukungan untuk API

Apakah Anda berencana menggunakan Web Bluetooth API? Dukungan publik Anda membantu tim Chrome memprioritaskan fitur dan menunjukkan kepada vendor browser lain betapa pentingnya mendukung fitur tersebut.

Kirim tweet ke @ChromiumDev menggunakan hashtag #WebBluetooth dan beri tahu kami tempat dan cara Anda menggunakannya.

Resource

Ucapan terima kasih

Terima kasih kepada Kayce Basques yang telah meninjau artikel ini. Gambar hero oleh SparkFun Electronics dari Boulder, Amerika Serikat.