Introduzione alle Web Bluetooth API

13 febbraio 2018

Nei primi mesi del 2017, nella versione 56 di Chrome, è stata inserita un'interessante funzionalità: la possibilità di connettersi e di colloquiare con dispositivi Bluetooth.

Grazie alle Web Bluetooth API è infatti possibile creare un'applicazione che si connette ad un dispositivo BLE (Bluetooth Low Energy), legge informazioni dal dispositivo e riceve notifiche quando determinati valori cambiano.

Come spesso accade per queste nuove funzionalità, è necessario rispettare due requisiti:

  1. l'applicazione deve essere servita tramite protocollo HTTPS;
  2. la connessione al dispositivo è possibile solo come conseguenza di un'azione volontaria dell'utente (per esempio un click o un “tap”).

L'utilizzo di questa nuova funzionalità richiede un minimo di conoscenza del funzionamento dei BLE e dei GATT (Generic Attribute Profile), che daremo per assodati nel corso di questa lezione.

Implementeremo, nel seguito, il codice necessario per la connessione ad un dispositivo Bluetooth. Analizziamo il seguente codice:

		navigator.bluetooth.requestDevice({...})
		.then(device => { console.log(device) })
		.catch(error => { console.log(error); });
	

L'esecuzione di questo codice fa si che Chrome mostri all'utente una finestra in cui selezionare un dispositivo BLE. L'utente può anche decidere di cancellare la richiesta.

Il metodo requestDevice fornisce una Promise: rimane in attesa di un'azione dell'utente e dell'eventuale tempo di connessione al dispositivo selezionato. Nel caso in cui la connessione vada a buon fine, verrà eseguito il codice presente all'interno del blocco then. In caso contrario, sarà eseguito quello presente nel blocco catch.

La funzione requestDevice supporta un argomento obbligatorio: è necessario fornire un oggetto che descriva i filtri che il browser deve applicare alla ricerca dei dispositivi. L'oggetto può avere diverse proprietà, che permettono di specificare diverse funzionalità:

  • è possibile richiedere al browser di cercare solo i dispositivi che espongono un determinato servizio;
    		/* Per i servizi standard utilizzo il service name
    		{ filters: [{ services: ['battery_service'] }] }
    
    		/* Per i servizi non standard utilizzo il Bluetooth UUID
    		{ filters: [{ 
    			services: [
    				0x1234, 
    				0x12345678, 
    				'99999999-0000-1000-8000-00805f9b34fb'
    				] 
    			}] 
    		}
    	
  • è possibile richiedere al browser di mostrare i dispositivi che espongono un particolare nome:
    		{ filters: [{
    			name: 'Mi Band 2'
    			}]
    		}
    	
  • infine, è possibile decidere di richiedere qualsiasi dispositivo utilizzando la parola chiave acceptAllDevices. In questo caso, è necessario comunque specificare i servizi ai quali dovremo accedere tramite la parola chiave optionalServices:
    		{
    			acceptAllDevices: true,
    			optionalServices: ['battery_service']
    		}
    	

Nel caso in cui la connessione vada a buon fine, la Promise restituisce un oggetto Device. Con questo oggetto, è possibile connettersi al GATT server ed effettuare operazioni di lettura e scrittura delle proprietà del dispositivo (a patto che il dispositivo permetta questo tipo di operazioni).

		navigator.bluetooth.requestDevice(
			{ filters: ... }
		)
		.then(device => {
			// Ottenuto il device mi connetto al GATT Server
			return device.gatt.connect();
		})
		.then(server => { /* ... */ })
	

Solo dopo aver stabilito la connessione al server potremo procedere con la lettura delle proprietà del dispositivo:

		.then(server => {
			// Mi aggancio al servizio per la gestione della batteria
			return server.getPrimaryService('battery_service');
		})
		.then(service => {
			// Recupero la caratterustica relativa alla batteria
			return service.getCharacteristic('battery_level');
		})
		.then(characteristic => {
			// Leggo il valore attuale della batteria
			return characteristic.readValue();
		})
		.then(value => {
			console.log('Carica batteria: ' + value);
		})
	

È altresì possibile decidere di sfruttare un event listener per visualizzare eventuali variazioni di una caratteristica del dispositivo: dopo aver recuperato il servizio, potremmo utilizzare un codice simile al seguente:

		.then(service => ...)
		.then(characteristic => characteristic.startNotifications())
		.then(characteristic => {
			characteristic.addEventListener('characteristicvaluechanged',
			                                handleCharacteristicValueChanged);
			console.log('Notifications have been started.');
		})
		.catch(error => { console.log(error); });

		function handleCharacteristicValueChanged(event) {
			const value = event.target.value;
			console.log('Valore ricevuto ' + value);
		}
	

La funzione handelCharacteristicValueChanged verrà eseguita ogni volta che il valore della caratteristica in ascolto subirà una variazione (nel nostrò caso ad ogni cambio del livello della batteria).

Un'altra informazione che potremmo voler gestire è l'eventuale disconessione del dispositivo precedentemente connesso. Per farlo, è necessario modificare il codice di aggancio al dispositivo:

		navigator.bluetooth.requestDevice(...)
		.then(device => {
			device.addEventListener('gattserverdisconnected', onDisconnected);

			return device.gatt.connect();
		})
	

Al momento della disconnessione del dispositivo, il browser eseguirà il codice contenuto nella funzione onDisconnected permettendo di gestire la disconnessione del dispositivo.

Nel caso in cui non si sia in possesso di un dispositivo BLE con cui testare questa nuova tecnologia, è possibile utilizzare il simulatore BLE messo a disposizione dalla Web Bluetooth Community.

Un ultimo consiglio è quello di guardare gli esempi messi a disposizione dal team di Chrome: sarà così possibile scoprire tutte le funzionalità disponibili e testare le enormi potenzialità dell'API.

Se vuoi aggiornamenti su Introduzione alle Web Bluetooth API inserisci la tua e-mail nel box qui sotto:
 
X
Se vuoi aggiornamenti su Introduzione alle Web Bluetooth API

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy