Comunicação com dispositivos Bluetooth por JavaScript
A API Web Bluetooth permite que sites se comuniquem com dispositivos Bluetooth.
E se eu dissesse que os sites podem se comunicar com dispositivos Bluetooth próximos de maneira segura e com privacidade? Dessa forma, monitores de frequência cardíaca, lâmpadas de som e até tartarugas podem interagir diretamente com um site.
Até agora, a capacidade de interagir com dispositivos Bluetooth era possível apenas para aplicativos específicos da plataforma. A API Web Bluetooth tem como objetivo mudar essa situação e possibilitar que navegadores da web também façam isso.
Antes de começarmos #
Este artigo pressupõe que você tenha algum conhecimento básico de como o Bluetooth Low Energy (BLE) e o Generic Attribute Profile (GATT) funcionam.
Mesmo que a especificação da API Web Bluetooth ainda não esteja finalizada, os autores das especificações estão procurando ativamente por desenvolvedores entusiasmados para experimentar essa API e fornecer feedback sobre as especificações e comentários sobre a implementação.
Um subconjunto da API Web Bluetooth está disponível no ChromeOS, Chrome para Android 6.0, Mac (Chrome 56) e Windows 10 (Chrome 70). Isso significa que você deve ser capaz de solicitar e se conectar a dispositivos Bluetooth Low Energy próximos, ler/gravar características do Bluetooth, receber notificações GATT, saber quando um dispositivo Bluetooth é desconectado e até ler e gravar descritores Bluetooth. Consulte a tabela de compatibilidade com navegador do MDN para obter mais informações.
Para Linux e versões anteriores do Windows, habilite o sinalizador #experimental-web-platform-features
about://flags
.
Disponível para testes de origem #
Para obter o máximo de feedback possível dos desenvolvedores que usam a API Web Bluetooth no campo, o Chrome já adicionou esse recurso no Chrome 53 como uma versão de teste original para o ChromeOS, Android e Mac.
O teste foi finalizado com êxito em janeiro de 2017.
Requisitos de segurança #
Para entender as vantagens e desvantagens da segurança, recomendo a publicação do modelo de segurança do Web Bluetooth de Jeffrey Yasskin, engenheiro de software da equipe do Chrome, que trabalha na especificação da API Web Bluetooth.
Apenas HTTPS #
Como essa API experimental é um recurso novo e poderoso adicionado à web, está disponível apenas para contextos seguros. Isso significa que você precisará construir com o TLS em mente.
Gesto do usuário necessário #
Como recurso de segurança, a descoberta de dispositivos Bluetooth com navigator.bluetooth.requestDevice
deve ser acionada por um gesto do usuário, como toque ou clique do mouse. Estamos falando sobre ouvir eventos de pointerup
, click
e touchend
.
button.addEventListener('pointerup', function(event) {
// Call navigator.bluetooth.requestDevice
});
Entre no código #
A API Web Bluetooth depende muito das Promessas do JavaScript. Se você não estiver familiarizado com elas, confira este incrível tutorial sobre Promessas. Além disso, () => {}
são simplesmente funções de seta do ECMAScript 2015.
Solicite dispositivos Bluetooth #
Esta versão da especificação da API Web Bluetooth permite que sites, executando na função Central, se conectem a servidores GATT remotos por meio de uma conexão BLE. É compatível com comunicação entre dispositivos que implementam Bluetooth 4.0 ou mais recente.
Quando um site solicita acesso a dispositivos próximos usando navigator.bluetooth.requestDevice
, o navegador exibe ao usuário um seletor de dispositivos no qual é possível escolher um dispositivo ou simplesmente cancelar a solicitação.
O navigator.bluetooth.requestDevice()
obtém um objeto obrigatório que define os filtros. Esses filtros são usados para retornar apenas dispositivos que correspondam a alguns serviços GATT Bluetooth anunciados e/ou o nome do dispositivo.
Filtro de serviços #
Por exemplo, para solicitar dispositivos Bluetooth que anunciam o serviço de bateria Bluetooth GATT:
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Se o seu serviço Bluetooth GATT não estiver na lista de serviços Bluetooth GATT padronizados, você poderá inserir o UUID Bluetooth completo ou um formato curto de 16 ou 32 bits.
navigator.bluetooth.requestDevice({
filters: [{
services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
}]
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Filtro de nome #
Você também pode solicitar dispositivos Bluetooth com base no nome do dispositivo anunciado com a chave de filtros name
ou até um prefixo desse nome com a chave de filtros namePrefix
. Observe que, nesse caso, você também precisará definir a chave optionalServices
para poder acessar serviços não incluídos em um filtro de serviço. Do contrário, você obterá um erro mais tarde ao tentar acessá-los.
navigator.bluetooth.requestDevice({
filters: [{
name: 'Francois robot'
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Filtro de dados do fabricante #
Também é possível solicitar dispositivos Bluetooth com base nos dados específicos do fabricante anunciados com a chave de filtros manufacturerData
. Essa chave é uma matriz de objetos com uma chave obrigatória de identificação de empresa Bluetooth, com o nome companyIdentifier
. Você também pode fornecer um prefixo de dados que filtra os dados do fabricante de dispositivos Bluetooth que iniciam com ele. Observe que você também precisará definir a chave optionalServices
para poder acessar serviços não incluídos em um filtro de serviço. Do contrário, você obterá um erro mais tarde ao tentar acessá-los.
// 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); });
Uma máscara também pode ser usada com um prefixo de dados para corresponder a alguns padrões nos dados do fabricante. Confira o explicador de filtros de dados Bluetooth para saber mais.
Sem filtros #
Por fim, em vez de filters
, você pode usar a chave acceptAllDevices
para mostrar todos os dispositivos Bluetooth próximos. Também será necessário definir a chave optionalServices
para poder acessar alguns serviços. Do contrário, um erro ocorrerá mais tarde ao tentar acessá-los.
navigator.bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Conecte-se a um dispositivo Bluetooth #
Então, o que fazer agora que você tem um BluetoothDevice
? Vamos nos conectar ao servidor GATT remoto Bluetooth que contém as definições de serviço e características.
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); });
Leia uma característica do Bluetooth #
Estamos conectados ao servidor GATT do dispositivo Bluetooth remoto. Agora queremos obter um Serviço GATT Primário e ler uma característica que pertence a esse serviço. Vamos tentar, por exemplo, ler o nível de carga atual da bateria do dispositivo.
No exemplo abaixo, battery_level
é a Característica Nível de Bateria padronizada.
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 você usar uma característica GATT Bluetooth personalizada, é possível inserir o UUID Bluetooth completo ou um formulário curto de 16 ou 32 bits para service.getCharacteristic
.
Note que você também pode adicionar um ouvinte de evento characteristicvaluechanged
em uma característica para ler seu valor. Verifique a Amostra alterada de leitura de valor de característica para ver como tratar as próximas notificações do GATT opcionalmente.
…
.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);
}
Grave em uma característica Bluetooth #
Gravar em uma característica GATT Bluetooth é tão fácil quanto ler. Desta vez, vamos usar o Ponto de Controle da Freqüência Cardíaca para redefinir o valor do campo Energia Despendida para 0 em um dispositivo de monitoramento de freqüência cardíaca.
Eu prometo que não há mágica aqui. Tudo está explicado na página Característica Ponto de Controle da Freqüência Cardíaca.
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); });
Receba notificações GATT #
Agora veremos como receber notificações quando a característica Medição de Frequência Cardíaca for alterada no 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
}
A Amostra de Notificações mostra como parar notificações com stopNotifications()
e remover corretamente o ouvinte de evento characteristicvaluechanged
adicionado.
Desconecte-se de um dispositivo Bluetooth #
Para proporcionar uma experiência melhor ao usuário, você pode ouvir eventos de desconexão e convidar o usuário a se reconectar:
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.`);
}
Você também pode chamar device.gatt.disconnect()
para desconectar seu aplicativo da web do dispositivo Bluetooth. Isso acionará os ouvintes de eventos exisentes do gattserverdisconnected
. Observe que a comunicação do dispositivo Bluetooth NÃO será interrompida se outro aplicativo já estiver se comunicando com o dispositivo Bluetooth. Verifique a Amostra de Desconexão de Dispositivo e a Amostra de Reconexão Automática para saber mais.
Leia e grave em descritores Bluetooth #
Os descritores GATT do Bluetooth são atributos que descrevem um valor característico. Você pode lê-los e gravá-los de maneira semelhante às características do Bluetooth GATT.
Vamos ver, por exemplo, como ler a descrição do usuário do intervalo de medição do termômetro de integridade do dispositivo.
No exemplo abaixo, health_thermometer
é o Serviço de Termômetro de Integridade, measurement_interval
é a característica Intervalo de Medição e gatt.characteristic_user_description
é o descritor Descrição de Usuário Característico.
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); });
Agora que lemos a descrição do usuário do intervalo de medição do termômetro de integridade do dispositivo, vamos ver como atualizá-lo e gravar um valor personalizado.
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); });
Amostras, demonstrações e codelabs #
Todos os exemplos da Web Bluetooth abaixo foram testados com êxito. Para aproveitar essas amostras ao máximo, recomendo que você instale o aplicativo BLE Peripheral Simulator Android, que simula um periférico BLE com um serviço de bateria, um serviço de frequência cardíaca ou um serviço de termômetro de integridade.
Principiante #
- Informações do dispositivo - recupera informações básicas do dispositivo em um dispositivo BLE.
- Nível da bateria - recupera as informações da bateria em um dispositivo BLE que anuncia as informações da bateria.
- Redefinir energia - redefine a energia despendida em um dispositivo BLE que anuncia a frequência cardíaca.
- Propriedades da característica - exibe todas as propriedades de uma característica específica de um dispositivo BLE.
- Notificações - inicie e pare notificações de características em um dispositivo BLE.
- Desconexão do dispositivo - desconecte e seja notificado de uma desconexão de um dispositivo BLE após conectar-se.
- Obtenha características - obtenha todas as características de um serviço anunciado em um dispositivo BLE.
- Obtenha descritores - obtenha todos os descritores das características de um serviço anunciado em um dispositivo BLE.
- Filtro de dados do fabricante - recupera informações básicas do dispositivo em um dispositivo BLE que correspondem aos dados do fabricante.
Combinando múltiplas operações #
- Características GAP - obtenha todas as características GAP de um dispositivo BLE.
- Características de informações do dispositivo - obtenha todas as características de informações do dispositivo de um dispositivo BLE.
- Perda de link - defina a característica do nível de alerta de um dispositivo BLE (readValue e writeValue).
- Descubra serviços e características - descubra todos os serviços primários acessíveis e suas características em um dispositivo BLE.
- Reconexão automática - reconecte-se a um dispositivo BLE desconectado usando um algoritmo de backoff exponencial.
- Read Characteristic Value Changed - leia o nível da bateria e seja notificado sobre as alterações em um dispositivo BLE.
- Ler descritores - leia todos os descritores de características de um serviço em um dispositivo BLE.
- Write Descriptor - grave no descritor "Descrição de Usuário Característico" em um dispositivo BLE.
Confira também nossas Demos da Web Bluetooth coletadas e Codelabs oficiais da Web Bluetooth.
Bibliotecas #
- web-bluetooth-utils é um módulo npm que adiciona algumas funções convenientes à API.
- Um shim de API Web Bluetooth está disponível no noble, o módulo central Node.js BLE mais popular. Isso permite que você empacote/navegue na web noble sem a necessidade de um servidor WebSocket ou outros plug-ins.
- angular-web-bluetooth é um módulo para Angular que abstrai todo o clichê necessário para configurar a API Web Bluetooth.
Ferramentas #
- Introdução à Web Bluetooth é um aplicativo da web simples que irá gerar todo o código padrão do JavaScript para começar a interagir com um dispositivo Bluetooth. Insira um nome de dispositivo, um serviço, uma característica, defina suas propriedades e pronto.
- Se você já for um desenvolvedor Bluetooth, o Web Bluetooth Developer Studio Plugin também gerará o código do Web Bluetooth JavaScript para o seu dispositivo Bluetooth.
Dicas #
Uma página Bluetooth Internals está disponível no Chrome em about://bluetooth-internals
para que você possa inspecionar tudo sobre dispositivos Bluetooth próximos: status, serviços, características e descritores.

Também recomendo verificar a página oficial Como arquivar bugs do Web Bluetooth, pois às vezes pode ser difícil depurar o Bluetooth.
Próximos passos #
Verifique o status de implementação do navegador e da plataforma primeiro para saber quais partes da API Web Bluetooth estão sendo implementadas no momento.
Embora ainda esteja incompleta, aqui está uma prévia do que esperar no futuro próximo:
- A varredura de anúncios BLE próximos acontecerá com
navigator.bluetooth.requestLEScan()
. - Um novo
serviceadded
rastreará os serviços Bluetooth GATT recém-descobertos, enquanto oserviceremoved
rastreará os removidos. Um novoservicechanged
será disparado quando qualquer característica e/ou descritor for adicionado ou removido de um serviço GATT Bluetooth.
Mostre seu apoio à API #
Você está planejando usar a API Web Bluetooth? Seu apoio público ajuda a equipe do Chrome a priorizar os recursos e mostra a outros fornecedores de navegadores como o apoio é fundamental.
Envie um tweet para @ChromiumDev usando a hashtag #WebBluetooth
e diga-nos onde e como você está usando a API.
Recursos #
- Stack Overflow: https://stackoverflow.com/questions/tagged/web-bluetooth
- Status do recurso do Chrome: https://www.chromestatus.com/feature/5264933985976320
- Erros de implementação do Chrome: https://crbug.com/?q=component:Blink>Bluetooth
- Especificação de Bluetooth da web: https://webbluetoothcg.github.io/web-bluetooth
- Problemas de especificações: https://github.com/WebBluetoothCG/web-bluetooth/issues
- Aplicativo BLE Peripheral Simulator: https://github.com/WebBluetoothCG/ble-test-peripheral-android
Reconhecimentos #
Agradecimentos a Kayce Basques por revisar este artigo. Imagem do herói elaborada por SparkFun Electronics de Boulder, EUA.