Comunicazione con dispositivi Bluetooth tramite JavaScript

L'API Web Bluetooth consente ai siti web di comunicare con i dispositivi Bluetooth.

François Beaufort
François Beaufort

E se ti dicessi che i siti web possono comunicare con i dispositivi Bluetooth nelle vicinanze in modo sicuro e incentrato sulla tutela della privacy? In questo modo, il battito cardiaco monitora, canta lampadine e persino le tartarughe potrebbero interagire direttamente con un sito web.

Finora, era possibile interagire con i dispositivi Bluetooth solo per app specifiche per le piattaforme. L'API Web Bluetooth ha lo scopo di cambiare questo lo rende disponibile anche sui browser web.

Prima di cominciare

In questo documento si presuppone che tu abbia una conoscenza di base di Bluetooth Low L'energia (BLE) e il profilo attributo generico funzionano.

Anche se la specifica API Web Bluetooth non è ancora stata finalizzata, le specifiche autori sono attivamente alla ricerca di sviluppatori entusiasti che provino questa API e Invia feedback sulle specifiche e sull'implementazione.

Un sottoinsieme dell'API Web Bluetooth è disponibile in ChromeOS e Chrome per Android 6.0, Mac (Chrome 56) e Windows 10 (Chrome 70). Ciò significa che dovresti essere in grado per richiedere e connettersi a dispositivi Bluetooth Low Energy nelle vicinanze, leggere/scrivere caratteristiche Bluetooth, ricevere notifiche GATT, sapere quando un dispositivo Bluetooth viene disconnesso e anche lettura e scrittura su Descrittori Bluetooth. Per ulteriori informazioni, consulta la tabella Compatibilità del browser di MDN. informazioni.

Per Linux e le versioni precedenti di Windows, abilita il #experimental-web-platform-features flag in about://flags.

Disponibile per le prove dell'origine

Per ottenere il maggior numero possibile di feedback dagli sviluppatori che utilizzano il Web l'API Bluetooth sul campo, in precedenza Chrome ha aggiunto questa funzionalità 53 come prova dell'origine per ChromeOS, Android e Mac.

Il periodo di prova è terminato a gennaio 2017.

Requisiti di sicurezza

Per comprendere i compromessi in termini di sicurezza, ti consiglio di utilizzare Web Bluetooth Security Post del modello di Jeffrey Yasskin, software engineer del team di Chrome, lavorando alle specifiche dell'API Web Bluetooth.

Solo HTTPS

Poiché questa API sperimentale è una nuova potente funzione aggiunta al web, è reso disponibile solo per contesti sicuri. Ciò significa che dovrai creare TLS.

Gesto dell'utente richiesto

Come funzionalità di sicurezza, il rilevamento di dispositivi Bluetooth con L'app navigator.bluetooth.requestDevice deve essere attivata tramite un gesto dell'utente, ad esempio come un tocco o un clic del mouse. Stiamo parlando dell'ascolto Eventi pointerup, click e touchend.

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

Impara a conoscere il codice

L'API Web Bluetooth fa molto affidamento sulle promesse JavaScript. In caso contrario dai un'occhiata a questo fantastico tutorial sulle promesse. Un'ultima cosa: () => {} sono funzioni freccia in ECMAScript 2015.

Richiedi dispositivi Bluetooth

Questa versione della specifica dell'API Web Bluetooth consente i siti web in esecuzione in con il ruolo Centrale, per connettersi ai server GATT remoti tramite una connessione BLE. it supporta la comunicazione tra dispositivi che implementano Bluetooth 4.0 o versioni successive.

Quando un sito web richiede l'accesso a dispositivi nelle vicinanze utilizzando navigator.bluetooth.requestDevice, il browser chiede all'utente con un dispositivo selettore dove possono scegliere un dispositivo o annullare la richiesta.

Richiesta all'utente del dispositivo Bluetooth.

La funzione navigator.bluetooth.requestDevice() accetta un oggetto obbligatorio che definisce i filtri. Questi filtri vengono utilizzati per restituire solo i dispositivi che corrispondono ad alcuni pubblicizzati i servizi GATT Bluetooth e/o il nome del dispositivo.

Filtro servizi

Ad esempio, per richiedere dispositivi Bluetooth che pubblicizzano il GATT Bluetooth Servizio batteria:

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

Se il servizio GATT Bluetooth non è nell'elenco dei dispositivi Bluetooth standardizzati ai servizi GATT, tuttavia, potresti fornire l'UUID Bluetooth completo o un breve Formato a 16 o 32 bit.

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

Filtro nome

Puoi anche richiedere dispositivi Bluetooth in base al nome del dispositivo pubblicizzato con la chiave dei filtri name o anche un prefisso di questo nome con la namePrefix chiave filtri. Tieni presente che in questo caso dovrai anche definire chiave optionalServices per poter accedere a servizi non inclusi in un filtro del servizio di servizio. In caso contrario, riceverai un messaggio di errore in seguito quando cercherai di accedere che li rappresentano.

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

Filtro dati del produttore

È anche possibile richiedere dispositivi Bluetooth in base al produttore specifici dati pubblicizzati con la chiave dei filtri manufacturerData. Questa chiave è un array di oggetti con una chiave ID azienda Bluetooth obbligatoria denominata companyIdentifier. Puoi anche fornire un prefisso dati che filtri dati sul produttore da dispositivi Bluetooth che lo avviano. Tieni presente che Devi anche definire la chiave optionalServices per poter accedere ai servizi non incluso in un filtro di servizio. In caso contrario, riceverai un messaggio di errore in seguito quando durante i tentativi di accesso.

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

Una maschera può essere utilizzata anche con un prefisso di dati per trovare corrispondenze di alcuni pattern in dati del produttore. Per scoprire di più, consulta l'spiegazione dei filtri dati Bluetooth altro ancora.

Filtri di esclusione

L'opzione exclusionFilters in navigator.bluetooth.requestDevice() consente escludi alcuni dispositivi dal selettore del browser. Può essere utilizzato per escludere dispositivi che corrispondono a un filtro più ampio ma non sono supportati.

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

Nessun filtro

Infine, invece di filters puoi usare il tasto acceptAllDevices per mostrare tutto dispositivi Bluetooth nelle vicinanze. Dovrai anche definire il optionalServices per poter accedere ad alcuni servizi. In caso contrario, riceverai un errore in seguito quando provi ad accedervi.

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

Connessione a un dispositivo Bluetooth

Cosa fai ora che hai un BluetoothDevice? Colleghiamoci Server GATT remoto Bluetooth che contiene il servizio e la caratteristica definizioni.

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

Lettura di una caratteristica Bluetooth

Qui ci connettiamo al server GATT del dispositivo Bluetooth remoto. Ora vuoi ottenere un servizio GATT principale e leggere una caratteristica che appartiene questo servizio. Proviamo, ad esempio, a leggere il livello di carica attuale batteria del dispositivo.

Nell'esempio che segue, battery_level è il livello della batteria standardizzato Caratteristica.

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

Se utilizzi una caratteristica GATT Bluetooth personalizzata, puoi fornire Bluetooth UUID completo o un formato breve a 16 o 32 bit per service.getCharacteristic.

Tieni presente che puoi anche aggiungere un listener di eventi characteristicvaluechanged su una per gestire la lettura del suo valore. Scopri la Caratteristica di lettura Esempio di valore modificato per scoprire come gestire facoltativamente il GATT imminente notifiche.

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

Scrittura a una caratteristica Bluetooth

Scrivere in una caratteristica GATT Bluetooth è facile come leggerla. Questa volta usiamo il punto di controllo del battito cardiaco per reimpostare il valore dell'energia spesa su 0 su un dispositivo di monitoraggio del battito cardiaco.

Prometto che non c'è magia qui. È spiegato tutto nella sezione Controllo della frequenza cardiaca pagina Caratteristica di punto.

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

Ricevere notifiche GATT

Ora vediamo come ricevere una notifica quando viene eseguita la misurazione del battito cardiaco modifiche alle caratteristiche del dispositivo:

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
}

L'esempio di notifiche mostra come interrompere le notifiche con stopNotifications() e rimuovi correttamente characteristicvaluechanged listener di eventi.

Disconnettersi da un dispositivo Bluetooth

Per offrire una migliore esperienza utente, potresti voler ascoltare gli eventi di disconnessione e invita l'utente a riconnettersi:

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

Puoi anche chiamare device.gatt.disconnect() per scollegare la tua app web dal Dispositivo Bluetooth. Questa operazione attiverà l'evento gattserverdisconnected esistente e ascoltatori. Tieni presente che NON interromperà la comunicazione del dispositivo Bluetooth se un altro L'app sta già comunicando con il dispositivo Bluetooth. Controlla il dispositivo Scollega il campione e Campione di riconnessione automatico per approfondire.

Lettura e scrittura sui descrittori Bluetooth

I descrittori GATT Bluetooth sono attributi che descrivono un valore caratteristico. Puoi leggerle e scriverle in modo simile a Bluetooth GATT caratteristiche.

Vediamo, ad esempio, come leggere la descrizione utente della misurazione intervallo del termometro per la salute del dispositivo.

Nell'esempio seguente, health_thermometer è il servizio Termometro sanitario, measurement_interval la caratteristica dell'intervallo di misurazione e gatt.characteristic_user_description la Descrizione della caratteristica dell'utente descrittore.

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

Dopo aver letto la descrizione dell'intervallo di misurazione del termometro per la salute di un dispositivo, vediamo come aggiornarlo e scrivere un valore.

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

Esempi, demo e codelab

Tutti gli esempi di Bluetooth web riportati di seguito sono stati testati correttamente. Per goderti questi contenuti di esempio, ti consiglio di installare [BLE Peipheral Simulator app Android] che simula una periferica BLE con un servizio batteria, un monitoraggio del battito cardiaco o un servizio di Termometro sanitario.

Principiante

  • Info dispositivo: consente di recuperare le informazioni di base del dispositivo da un dispositivo BLE.
  • Livello batteria: consente di recuperare le informazioni sulla batteria da un dispositivo BLE che pubblicizza le informazioni sulla batteria.
  • Ripristina energia: reimposta l'energia spesa da un dispositivo BLE che pubblicizza la frequenza cardiaca.
  • Proprietà caratteristiche: mostra tutte le proprietà di una caratteristica specifica di un dispositivo BLE.
  • Notifiche: avvia e interrompi le notifiche caratteristiche da un dispositivo BLE.
  • Disconnessione del dispositivo: consente di disconnettersi e ricevere una notifica in caso di disconnessione di un dispositivo BLE dopo aver eseguito la connessione.
  • Ottieni le caratteristiche: ottieni tutte le caratteristiche di un servizio pubblicizzato da un dispositivo BLE.
  • Ottieni descrittori - Ottieni tutte le caratteristiche descrittori di un servizio pubblicizzato da un Dispositivo BLE.
  • Filtro dati del produttore: consente di recuperare le informazioni di base del dispositivo da un dispositivo BLE corrispondente ai dati del produttore.
  • Filtri di esclusione. Consente di recuperare le informazioni di base del dispositivo da un dispositivo BLE dotato di filtri di esclusione di base.

Combinare più operazioni

Dai un'occhiata anche alle nostre demo web Bluetooth selezionate e ai codelab Web Bluetooth ufficiali.

Biblioteche

  • web-bluetooth-utils è un modulo npm che aggiunge alcune funzioni utili a l'API.
  • Uno shim API Web Bluetooth è disponibile in noble, la BLE di Node.js più diffusa modulo centrale. Ciò ti consente di webpack/browserify noble senza bisogno per un server WebSocket o altri plug-in.
  • angular-web-bluetooth è un modulo per Angular che astrae tutta la è necessario il boilerplate per configurare l'API Web Bluetooth.

Strumenti

  • Iniziare a utilizzare Web Bluetooth è una semplice app web che genera tutti il codice boilerplate JavaScript per iniziare a interagire con un dispositivo Bluetooth. Inserisci il nome di un dispositivo, un servizio, una caratteristica, definisci le sue proprietà e è tutto pronto.
  • Se sei già uno sviluppatore Bluetooth, Web Bluetooth Developer Studio il plug-in genererà inoltre il codice JavaScript Bluetooth per il web Dispositivo Bluetooth.

Suggerimenti

In Chrome è disponibile una pagina Interni Bluetooth all'indirizzo about://bluetooth-internals in modo da poter controllare tutto ciò che riguarda le vicinanze Dispositivi Bluetooth: stato, servizi, caratteristiche e descrittori.

Screenshot della pagina interna per eseguire il debug del Bluetooth in Chrome
Pagina interna in Chrome per il debug dei dispositivi Bluetooth.

Ti consiglio anche di consultare il documento ufficiale su come segnalare bug relativi al Bluetooth sul web. perché a volte il debug del Bluetooth può essere difficile.

Passaggi successivi

Controlla prima lo stato di implementazione del browser e della piattaforma per sapere quali parti dell'API Web Bluetooth sono attualmente in fase di implementazione.

Anche se è ancora incompleta, ecco un'anticipazione di cosa aspettarti futuro:

  • Ricerca di annunci BLE nelle vicinanze avverrà con navigator.bluetooth.requestLEScan().
  • Un nuovo evento serviceadded monitorerà i servizi GATT Bluetooth appena rilevati mentre serviceremoved evento monitorerà quelli rimossi. Un nuovo servicechanged si attiverà quando viene aggiunta una caratteristica e/o un descrittore rimosso da un servizio GATT Bluetooth.

Mostra il supporto per l'API

Intendi utilizzare l'API Web Bluetooth? Il tuo supporto pubblico aiuta il team di Chrome dare la priorità alle funzionalità e mostra agli altri fornitori di browser quanto sia fondamentale supportarli.

Invia un tweet a @ChromiumDev utilizzando l'hashtag #WebBluetooth e facci sapere dove e come lo utilizzi.

Risorse

Ringraziamenti

Grazie a Kayce Basques per aver letto questo articolo. Immagine hero di SparkFun Electronics from Boulder, USA.