Bluetooth

Este documento descreve como usar as APIs Bluetooth, Bluetooth Socket e Bluetooth Low Energy para comunicação com dispositivos Bluetooth e Bluetooth de baixa energia.

Para ver informações contextuais sobre o Bluetooth, consulte as especificações oficiais do Bluetooth.

Requisitos do manifesto

Para apps do Chrome que usam Bluetooth, adicione a entrada Bluetooth ao manifesto e especifique, se adequado, os UUIDs de perfis, protocolos ou serviços que você quer implementar e se quer implementá-los com o soquete e/ou as APIs Low Energy.

Por exemplo, para uma implementação de soquete:

"bluetooth": {
  "uuids": [ "1105", "1106" ],
  "socket": true
}

Para uma implementação de baixa energia:

"bluetooth": {
  "uuids": [ "180D", "1809", "180F" ],
  "low_energy": true
}

Para acessar apenas o estado do adaptador, descobrir dispositivos por perto e receber informações básicas sobre eles, somente a entrada em si é necessária:

"bluetooth": {}

Informações do adaptador

Como acessar o estado do adaptador

Para ver o estado do adaptador Bluetooth, use o método bluetooth.getAdapterState:

chrome.bluetooth.getAdapterState(function(adapter) {
  console.log("Adapter " + adapter.address + ": " + adapter.name);
});

Notificações do adaptador

O evento bluetooth.onAdapterStateChanged é enviado sempre que o estado do adaptador muda. Isso pode ser usado, por exemplo, para determinar quando o rádio do adaptador está ligado ou desligado.

var powered = false;
chrome.bluetooth.getAdapterState(function(adapter) {
  powered = adapter.powered;
});

chrome.bluetooth.onAdapterStateChanged.addListener(
  function(adapter) {
    if (adapter.powered != powered) {
      powered = adapter.powered;
      if (powered) {
        console.log("Adapter radio is on");
      } else {
        console.log("Adapter radio is off");
      }
    }
  });

Informações do dispositivo

Listar dispositivos conhecidos

Para ver uma lista dos dispositivos conhecidos pelo adaptador Bluetooth, use o método bluetooth.getDevices:

chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    console.log(devices[i].address);
  }
});

Todos os dispositivos são retornados, incluindo os pareados e aqueles descobertos recentemente. Ele não iniciará a descoberta de novos dispositivos. Consulte Descobrir dispositivos por perto.

Recebendo notificações do dispositivo

Em vez de chamar bluetooth.getDevices repetidamente, você pode usar os eventos bluetooth.onDeviceAdded, bluetooth.onDeviceChanged e bluetooth.onDeviceRemoved para receber notificações.

O evento bluetooth.onDeviceAdded é enviado sempre que um dispositivo é descoberto pelo adaptador ou um dispositivo é conectado a ele:

chrome.bluetooth.onDeviceAdded.addListener(function(device) {
  console.log(device.address);
});

Adicionar um listener a esse evento não inicia a descoberta de dispositivos. Consulte Como descobrir dispositivos próximos.

Mudanças nos dispositivos, incluindo dispositivos descobertos anteriormente que estão sendo pareados, são notificados pelo evento bluetooth.onDeviceChanged:

chrome.bluetooth.onDeviceChanged.addListener(function(device) {
  console.log(device.address);
});

Por fim, o evento bluetooth.onDeviceRemoved é enviado sempre que um dispositivo pareado é removido do sistema ou um dispositivo descoberto não foi visto recentemente:

chrome.bluetooth.onDeviceRemoved.addListener(function(device) {
  console.log(device.address);
});

Descobrindo dispositivos por perto

Para iniciar a descoberta de dispositivos por perto, use o método bluetooth.startDiscovery. A descoberta pode consumir muitos recursos, portanto, chame bluetooth.stopDiscovery quando terminar.

Chame bluetooth.startDiscovery sempre que seu app precisar descobrir dispositivos próximos. Não faça a chamada condicional na propriedade discovering de bluetooth.AdapterState. A chamada será bem-sucedida mesmo que outro app esteja descobrindo dispositivos próximos e vai garantir que o adaptador continue fazendo a descoberta depois que o outro app for interrompido.

As informações sobre cada dispositivo recém-descoberto são recebidas usando o evento bluetooth.onDeviceAdded. O evento não é enviado para dispositivos que já foram descobertos recentemente ou que já foram pareados ou conectados anteriormente. Em vez disso, você precisa chamar bluetooth.getDevices para receber as informações atuais e usar o evento bluetooth.onDeviceChanged para ser notificado sobre mudanças nessas informações como resultado da descoberta.

Exemplos

var device_names = {};
var updateDeviceName = function(device) {
  device_names[device.address] = device.name;
};
var removeDeviceName = function(device) {
  delete device_names[device.address];
}

// Add listeners to receive newly found devices and updates
// to the previously known devices.
chrome.bluetooth.onDeviceAdded.addListener(updateDeviceName);
chrome.bluetooth.onDeviceChanged.addListener(updateDeviceName);
chrome.bluetooth.onDeviceRemoved.addListener(removeDeviceName);

// With the listeners in place, get the list of devices found in
// previous discovery sessions, or any currently active ones,
// along with paired devices.
chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    updateDeviceName(devices[i]);
  }
});

// Now begin the discovery process.
chrome.bluetooth.startDiscovery(function() {
  // Stop discovery after 30 seconds.
  setTimeout(function() {
    chrome.bluetooth.stopDiscovery(function() {});
  }, 30000);
});

Se o usuário desativar o rádio Bluetooth, todas as sessões de descoberta serão encerradas e não retomadas automaticamente quando o rádio for ligado. Se isso for importante para o app, assista ao evento bluetooth.onAdapterStateChanged. Se a propriedade discovering mudar para false, seu app precisará chamar bluetooth.startDiscovery novamente para retomar. Tenha cuidado com a natureza intensa de recursos da descoberta.

Como identificar dispositivos

São fornecidas várias opções diferentes para identificar dispositivos retornados por bluetooth.getDevices e os eventos relacionados.

Se o dispositivo oferecer suporte à especificação do ID do dispositivo Bluetooth, várias propriedades vão ser adicionadas ao objeto Device contendo os campos definidos por essa especificação. Exemplos

chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    if (devices[0].vendorIdSource != undefined) {
      console.log(devices[0].address + ' = ' +
                  devices[0].vendorIdSource + ':' +
                  devices[0].vendorId.toString(16) + ':' +
                  devices[0].productId.toString(16) + ':' +
                  devices[0].deviceId.toString(16));
    }
  }
});

A especificação do ID do dispositivo geralmente é suficiente para identificar um modelo específico e até mesmo uma revisão de um dispositivo de um fornecedor. Quando ele não estiver presente, será necessário confiar nas informações sobre a classe ou o tipo do dispositivo, opcionalmente combinadas com o prefixo do fabricante no address.

A maioria dos dispositivos Bluetooth fornece informações de classe de dispositivo como um campo de bit interpretado de acordo com o documento Números atribuídos de banda de base. Esse campo de bits está disponível na propriedade deviceClass.

chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    if (devices[0].vendorIdSource != undefined) {
      console.log(devices[0].address + ' = ' +
                  devices[0].deviceClass.toString(16));
    }
  }
});

A análise do campo pode ser complexa, portanto, para os tipos de dispositivos mais comuns, o Chrome processa isso e define o campo type. Quando isso não estiver disponível ou for insuficiente para suas necessidades, você vai precisar analisar o deviceClass por conta própria.

chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    if (devices[0].vendorIdSource != undefined) {
      console.log(devices[0].address + ' = ' + devices[0].type);
    }
  }
});

Como usar RFCOMM e L2CAP

Os Aplicativos do Google Chrome podem fazer conexões com qualquer dispositivo compatível com os serviços RFCOMM ou L2CAP. Isso inclui a maioria dos dispositivos Bluetooth clássicos no mercado.

Como se conectar a uma tomada

São necessárias três coisas para se conectar a um dispositivo. Um soquete para fazer a conexão, criado com bluetoothSocket.create, o endereço do dispositivo ao qual você quer se conectar e o UUID do próprio serviço.

Antes de fazer a conexão, verifique se o adaptador reconhece o dispositivo usando bluetooth.getDevice ou as APIs de descoberta de dispositivos.

As informações necessárias para estabelecer a conexão, incluindo se o protocolo RFCOMM ou L2CAP precisa ser usado e qual canal ou PSM, é obtido usando a descoberta de SDP no dispositivo.

Exemplos

var uuid = '1105';
var onConnectedCallback = function() {
  if (chrome.runtime.lastError) {
    console.log("Connection failed: " + chrome.runtime.lastError.message);
  } else {
    // Profile implementation here.
  }
};

chrome.bluetoothSocket.create(function(createInfo) {
  chrome.bluetoothSocket.connect(createInfo.socketId,
    device.address, uuid, onConnectedCallback);
});

Mantenha um identificador para o socketId para que você possa enviar dados (bluetoothSocket.send) a esse soquete mais tarde.

Receber e enviar para um soquete

O recebimento de dados e o envio para um soquete usam objetos ArrayBuffer. Para saber mais sobre ArrayBuffers, confira a visão geral, Matrizes tipadas em JavaScript e o tutorial, Como converter um ArrayBuffer de e para uma string.

Para enviar dados que você tem em arrayBuffer, use bluetoothSocket.send:

chrome.bluetoothSocket.send(socketId, arrayBuffer, function(bytes_sent) {
  if (chrome.runtime.lastError) {
    console.log("Send failed: " + chrome.runtime.lastError.message);
  } else {
    console.log("Sent " + bytes_sent + " bytes")
  }
})

Diferente do método de envio de dados, os dados são recebidos em um evento (bluetoothSocket.onReceive. Os soquetes são criados e não pausados (consulte bluetoothSocket.setPaused) para que o listener desse evento seja adicionado entre bluetoothSocket.create e bluetoothSocket.connect.

chrome.bluetoothSocket.onRecieve.addListener(function(receiveInfo) {
  if (receiveInfo.socketId != socketId)
    return;
  // receiveInfo.data is an ArrayBuffer.
});

Erros e desconexão do soquete

Para receber notificações de erros de soquete, incluindo desconexão, adicione um listener ao evento bluetoothSocket.onReceiveError.

chrome.bluetoothSocket.onReceiveError.addListener(function(errorInfo) {
  // Cause is in errorInfo.error.
  console.log(errorInfo.errorMessage);
});

Como se desconectar de uma tomada

Para encerrar a conexão e desconectar o soquete, use bluetoothSocket.disconnect.

chrome.bluetoothSocket.disconnect(socketId);

Serviços de publicação

Além de fazer conexões de saída com dispositivos, os apps do Chrome podem publicar serviços que podem ser usados por qualquer dispositivo compatível com RFCOMM ou L2CAP.

Ouvindo em uma tomada

Há suporte para dois tipos de serviços publicados. A RFCOMM é a mais usada e abrange a maioria dos dispositivos e perfis:

var uuid = '1105';
chrome.bluetoothSocket.create(function(createInfo) {
  chrome.bluetoothSocket.listenUsingRfcomm(createInfo.socketId,
    uuid, onListenCallback);
});

A L2CAP é a outra e abrange outros tipos de dispositivos e usos específicos do fornecedor, como upload de firmware.

var uuid = '0b87367c-f188-47cd-bc20-a5f4f70973c6';
chrome.bluetoothSocket.create(function(createInfo) {
  chrome.bluetoothSocket.listenUsingL2cap(createInfo.socketId,
    uuid, onListenCallback);
});

Em ambos os casos, um bluetoothSocket.ListenOptions opcional pode ser transmitido para alocar um canal ou PSM específico. O callback indica um erro pelo chrome.runtime.lastError. Caso contrário, o sucesso. Mantenha um identificador para o socketId para que você possa aceitar conexões (bluetoothSocket.onAccept) desse soquete.

Como aceitar conexões de clientes

As conexões de cliente são aceitas e transmitidas para o aplicativo pelo evento bluetoothSocket.onAccept.

chrome.bluetoothSocket.onAccept.addListener(function(acceptInfo) {
  if (info.socketId != serverSocketId)
    return;

  // Say hello...
  chrome.bluetoothSocket.send(acceptInfo.clientSocketId,
    data, onSendCallback);

  // Accepted sockets are initially paused,
  // set the onReceive listener first.
  chrome.bluetoothSocket.onReceive.addListener(onReceive);
  chrome.bluetoothSocket.setPaused(false);
});

Parar de aceitar conexões de cliente

Para deixar de aceitar conexões de clientes e cancelar a publicação do serviço, use bluetoothSocket.disconnect.

chrome.bluetoothSocket.disconnect(serverSocketId);

Interagir com dispositivos de baixa energia

O Bluetooth de baixa energia, ou Bluetooth Smart, é uma tecnologia sem fio destinada ao consumo reduzido de energia. A API Bluetooth Low Energy permite que os aplicativos implementem o papel central em uma conexão LE com um periférico. As seções a seguir descrevem como descobrir, conectar-se e interagir com periféricos Bluetooth de baixa energia.

Como descobrir e se conectar a periféricos

Assim como os dispositivos Bluetooth tradicionais, os periféricos de LE podem ser descobertos usando os métodos descritos em Descobrir dispositivos por perto . Um dispositivo de LE se torna detectável enviando pacotes de dados chamados "Dados de publicidade", e diz-se que ele está no modo de publicidade. Os dados de publicidade podem conter UUIDs de serviços disponíveis no dispositivo. Se estiverem presentes, esses UUIDs poderão ser acessados usando a propriedade uuids do objeto bluetooth.Device correspondente.

Depois de descoberto, um dispositivo LE pode ser conectado chamando bluetoothLowEnergy.connect para que o aplicativo possa interagir com os serviços dele:

chrome.bluetooth.onDeviceAdded.addListener(function(device) {
  var uuid = '0000180d-0000-1000-8000-00805f9b34fb';
  if (!device.uuids || device.uuids.indexOf(uuid) < 0)
    return;

  // The device has a service with the desired UUID.
  chrome.bluetoothLowEnergy.connect(device.address, function () {
    if (chrome.runtime.lastError) {
      console.log('Failed to connect: ' + chrome.runtime.lastError.message);
      return;
    }

    // Connected! Do stuff...
    ...
  });
});

Depois de conectado, a propriedade connected do objeto bluetooth.Device correspondente terá o valor true. A chamada de bluetoothLowEnergy.connect estabelece uma reivindicação pelo aplicativo na conexão física com o dispositivo. Uma conexão física com o dispositivo pode existir sem nunca chamar bluetoothLowEnergy.connect (por exemplo, devido a outro aplicativo). Nesse caso, embora seu aplicativo ainda possa interagir com os serviços do dispositivo, ele precisa sempre chamar bluetoothLowEnergy.connect para evitar que outro aplicativo desconecte o link físico.

Quando seu aplicativo não precisar mais estar conectado, ele poderá remover a reivindicação sobre a conexão chamando bluetoothLowEnergy.disconnect:

chrome.bluetoothLowEnergy.disconnect(deviceAddress);

Isso não necessariamente destruirá o link físico para o dispositivo, porque pode haver outros aplicativos que tenham conexões ativas com o dispositivo. Às vezes, o dispositivo pode ser desconectado por motivos que estão além do controle do aplicativo (por exemplo, se o dispositivo desaparecer ou for explicitamente desconectado pelo usuário por utilitários do sistema operacional). Seu aplicativo precisa observar o evento bluetooth.onDeviceChanged para receber notificações sobre mudanças na conexão e se reconectar, se necessário.

Depois de conectado, o dispositivo que está executando o Chrome recebe o chamado papel central, enquanto o dispositivo remoto está no papel periférico. Nesse ponto, seu aplicativo pode interagir com os serviços no dispositivo usando os métodos descritos na seção a seguir. Observação:no momento, as APIs não oferecem suporte para a atuação como um periférico LE. Os apps só podem implementar o papel central.

Serviços, características e descritores

O Bluetooth Low Energy é baseado em um protocolo simples de solicitação/resposta chamado Attribute Protocol (ATT). Usando a ATT, um dispositivo central interage com os chamados atributos em um dispositivo periférico em conformidade com um perfil Bluetooth especial chamado Perfil de atributo genérico (GATT, na sigla em inglês). O GATT define os seguintes conceitos gerais:

  • Serviço: um serviço GATT representa uma coleção de dados e comportamentos associados para realizar uma função específica de um dispositivo. Por exemplo, um monitor de frequência cardíaca normalmente tem pelo menos um "Serviço de frequência cardíaca". As informações sobre um serviço GATT estão contidas em um objeto bluetoothLowEnergy.Service.
  • Característica: uma característica GATT é um elemento de dados básico usado para criar um serviço GATT, contendo um valor, além de propriedades que definem como esse valor pode ser acessado. Por exemplo, o "Serviço de frequência cardíaca" tem a característica "Medição de frequência cardíaca", que é usada para descobrir o valor da frequência cardíaca do usuário. As informações sobre uma característica GATT estão contidas em um objeto bluetoothLowEnergy.Characteristic.
  • Descritor: um descritor de característica GATT contém mais informações sobre uma característica. As informações sobre um descritor de característica do GATT estão contidas em um objeto bluetoothLowEnergy.Descriptor.

A API Bluetooth Low Energy permite que os aplicativos encontrem informações sobre os serviços, as características e os descritores de um dispositivo chamando bluetoothLowEnergy.getServices, bluetoothLowEnergy.getCharacteristics e bluetoothLowEnergy.getDescriptors. Os apps podem filtrar serviços, características e descritores comparando o campo uuid com o UUID GATT desejado:

chrome.bluetoothLowEnergy.getServices(deviceAddress, function(services) {
  ...
  for (var i = 0; i < services.length; i++) {
    if (services[i].uuid == HEART_RATE_SERVICE_UUID) {
      heartRateService = services[i];
      break;
    }
  }
  ...
});

Cada serviço, característica e descritor acessível pela API recebe um identificador exclusivo de instância, que pode ser obtido usando o campo instanceId. Esse ID de instância pode ser usado para identificar um objeto GATT e realizar operações específicas nele:

chrome.bluetoothLowEnergy.getCharacteristics(heartRateService.instanceId,
                                             function(chracteristics) {
  ...
  for (var i = 0; i < characteristics.length; i++) {
    if (characteristics[i].uuid == HEART_RATE_MEASUREMENT_UUID) {
      measurementChar = characteristics[i];
      break;
    }
  }
  ...
  chrome.bluetoothLowEnergy.getDescriptors(measurementChar.instanceId,
                                           function(descriptors) {
    ...
  });
});

Eventos de serviço

Quando um dispositivo está conectado, o Chrome descobre os serviços dele. À medida que cada serviço é descoberto e removido, o app recebe os eventos bluetoothLowEnergy.onServiceAdded e bluetoothLowEnergy.onServiceRemoved:

  var initializeService = function(service) {
    if (!service) {
      console.log('No service selected!');
      // Reset UI, etc.
      ...
      return;
    }

    myService = service;

    // Get all the characteristics and descriptors and bootstrap the app.
    ...
  };

  chrome.bluetoothLowEnergy.onServiceAdded.addListener(function(service) {
    if (service.uuid == MY_SERVICE_UUID)
      initializeService(service);
  });

  chrome.bluetoothLowEnergy.onServiceRemoved.addListener(function(service) {
    if (service.instanceId == myService.instanceId)
      initializeService(null);
  });

O Chrome descobre todas as características e descritores de um serviço de forma assíncrona e envia o evento bluetoothLowEnergy.onServiceAdded depois que a descoberta é concluída. Se a conexão com um periférico for encerrada, o Chrome removerá todos os serviços relacionados e enviará o evento bluetoothLowEnergy.onServiceRemoved.

Alguns periféricos podem modificar os serviços. Por exemplo, as características de um serviço podem mudar ou os serviços podem ser adicionados e removidos completamente. O Chrome notifica os apps sobre essas mudanças usando os eventos bluetoothLowEnergy.onServiceChanged, bluetoothLowEnergy.onServiceAdded e bluetoothLowEnergy.onServiceRemoved.

  chrome.bluetoothLowEnergy.onServiceChanged.addListener(function(service) {
    if (service.instanceId != myService.instanceId)
      return;

    updateMyService(service);
  });

Ler e gravar o valor de uma característica

A característica GATT codifica um aspecto do serviço. Um app central lê, age e modifica o estado do serviço de um periférico operando no valor de uma característica. O valor da característica é uma sequência de bytes, e o significado deles é definido pela especificação de alto nível que define uma determinada característica. Por exemplo, o valor da característica Medição de frequência cardíaca codifica a frequência cardíaca do usuário e a quantidade total de calorias que ele queimou, enquanto a característica Localização do sensor corporal codifica em que parte do corpo o sensor de frequência cardíaca deve ser usado.

O Chrome oferece o método bluetoothLowEnergy.readCharacteristicValue para ler o valor de uma característica:

chrome.bluetoothLowEnergy.readCharacteristicValue(chrc.instanceId,
                                                  function(result) {
  if (chrome.runtime.lastError) {
    console.log('Failed to read value: ' + chrome.runtime.lastError.message);
    return;
  }

  var bytes = new Uint8Array(result.value);

  // Do stuff with the bytes.
  ...
});

Algumas características são graváveis, especialmente aquelas que se comportam como "Pontos de Controle", em que a gravação do valor tem efeitos colaterais. Por exemplo, a característica do Ponto de controle de frequência cardíaca é usada para informar ao sensor de frequência cardíaca para redefinir a contagem do total de calorias queimadas e oferecer suporte apenas a gravações. Para isso, o Chrome fornece o método bluetoothLowEnergy.writeCharacteristicValue:

var myBytes = new Uint8Array([ ... ]);
chrome.bluetoothLowEnergy.writeCharacteristicValue(chrc.instanceId,
                                                   myBytes.buffer,
                                                   function() {
  if (chrome.runtime.lastError) {
    console.log('Failed to write value: ' +
                chrome.runtime.lastError.message);
    return;
  }

  // Value is written now.
});

Os descritores de característica se comportam da mesma forma e podem ser lidos e/ou graváveis. O Chrome oferece os métodos bluetoothLowEnergy.readDescriptorValue e bluetoothLowEnergy.writeDescriptorValue para ler e gravar o valor de um descritor.

Para verificar se uma característica é compatível com leituras ou gravações, o aplicativo pode verificar o campo properties de um objeto bluetoothLowEnergy.Characteristic. Embora esse campo não contenha informações sobre os requisitos de segurança para acessar um valor, ele descreve qual operação de valor a característica aceita em geral.

Como processar notificações de valor

Algumas características tornam seu valor conhecido por meio de notificações ou indicações. Por exemplo, a característica de medição de frequência cardíaca não é legível nem gravável, mas envia atualizações sobre o valor atual em intervalos regulares. Os aplicativos podem detectar essas notificações usando o evento bluetoothLowEnergy.onCharacteristicValueChanged.

  chrome.bluetoothLowEnergy.onCharacteristicValueChanged.addListener(
      function(chrc) {
    if (chrc.instanceId != myCharId)
      return;

    var bytes = new Uint8Array(chrc.value);

    // Do stuff with the bytes.
    ...
  });

Mesmo que uma característica seja compatível com notificações/indicações, ela não será ativada por padrão. Um app precisa chamar os métodos bluetoothLowEnergy.startCharacteristicNotifications e bluetoothLowEnergy.stopCharacteristicNotifications para iniciar ou parar de receber o evento bluetoothLowEnergy.onCharacteristicValueChanged.

  // Start receiving characteristic value notifications.
  var notifying = false;
  chrome.bluetoothLowEnergy.startCharacteristicNotifications(chrc.instanceId,
                                                             function() {
    if (chrome.runtime.lastError) {
      console.log('Failed to enable notifications: ' +
                  chrome.runtime.lastError.message);
      return;
    }

    notifying = true;
  });

  ...

  // No longer interested in notifications from this characteristic.
  if (notifying) {
    chrome.bluetoothLowEnergy.stopCharacteristicNotifications(
        chrc.instanceId);
  }

Depois que as notificações forem iniciadas, o app vai receber o bluetoothLowEnergy.onCharacteristicValueChanged sempre que uma notificação ou indicação é recebida da característica. Se a característica for compatível com leituras, esse evento também será enviado após uma chamada bem-sucedida para bluetoothLowEnergy.readCharacteristicValue. Isso permite que os apps unifiquem o fluxo de controle de uma atualização de valor acionada por uma solicitação de leitura e notificações:

  chrome.bluetoothLowEnergy.onCharacteristicValueChanged.addListener(
      function(chrc) {
    // Process the value.
    ...
  });

  chrome.bluetoothLowEnergy.startCharacteristicNotifications(chrc.instanceId,
                                                             function() {
    // Notifications started. Read the initial value.
    chrome.bluetoothLowEnergy.readCharacteristicValue(chrc.instanceId,
                                                      function(result) {
      ...
      // No need to do anything here since onCharacteristicValueChanged
      // will handle it.
    });
  });

Se uma característica for compatível com notificações, o campo properties dela conterá a propriedade "notify" ou "indicate".

OBSERVAÇÃO: se uma característica for compatível com notificações/indicações, ela terá o descritor de "Configuração de característica do cliente" para ativar/desativar notificações. O Chrome não permite que os apps gravem nesse descritor. Em vez disso, os apps precisam usar os métodos bluetoothLowEnergy.startCharacteristicNotifications e bluetoothLowEnergy.stopCharacteristicNotifications para controlar o comportamento das notificações.