Bluetooth

W tym dokumencie opisujemy, jak używać interfejsów API Bluetooth, Bluetooth Socket i Bluetooth Low Energy do komunikacji z urządzeniami Bluetooth Low Energy.

Podstawowe informacje dotyczące Bluetootha znajdziesz w oficjalnych specyfikacjach Bluetootha.

Wymagania dotyczące pliku manifestu

W przypadku aplikacji Chrome korzystających z Bluetootha dodaj do pliku manifestu wpis bluetooth i w razie potrzeby podaj identyfikatory UUID profili, protokołów lub usług, które chcesz wdrożyć, wraz z informacjami, czy chcesz wdrożyć je z interfejsami gniazd i interfejsów Low Energy API.

Na przykład w przypadku implementacji gniazda:

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

A jeśli chcesz wdrożyć tryb energooszczędny:

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

Aby uzyskać dostęp tylko do stanu adaptera, wykrywać urządzenia w pobliżu i uzyskać podstawowe informacje o urządzeniach, wymagany jest tylko sam wpis:

"bluetooth": {}

Informacje o adapterze

Uzyskiwanie stanu adaptera

Aby sprawdzić stan adaptera Bluetooth, użyj metody bluetooth.getAdapterState:

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

Powiadomienia dotyczące adaptera

Zdarzenie bluetooth.onAdapterStateChanged jest wysyłane po każdej zmianie stanu adaptera. Może to np. pomóc określić, kiedy radio adaptera ma być włączone lub wyłączone.

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

Informacje o urządzeniu

Wyświetlanie listy znanych urządzeń

Aby uzyskać listę urządzeń znanych adapterowi Bluetooth, użyj metody bluetooth.getDevices:

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

Zwrócone zostaną wszystkie urządzenia, w tym ostatnio wykryte urządzenia sparowane i urządzenia. Nie rozpocznie wykrywania nowych urządzeń (patrz Wykrywanie urządzeń w pobliżu).

Odbieranie powiadomień na urządzeniu

Zamiast wielokrotnie wywoływać bluetooth.getDevices, możesz otrzymywać powiadomienia przy użyciu zdarzeń bluetooth.onDeviceAdded, bluetooth.onDeviceChanged i bluetooth.onDeviceRemoved.

Zdarzenie bluetooth.onDeviceAdded jest wysyłane za każdym razem, gdy adapter wykryje urządzenie lub nawiąże z nim połączenie:

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

Dodanie odbiornika do tego zdarzenia nie rozpocznie wykrywania urządzeń (patrz Wykrywanie urządzeń w pobliżu).

Zmiany dotyczące urządzeń, w tym wykryte wcześniej urządzenia, które zostały sparowane, są powiadamiane zdarzeniem bluetooth.onDeviceChanged:

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

Na koniec zdarzenie bluetooth.onDeviceRemoved jest wysyłane za każdym razem, gdy sparowane urządzenie zostanie usunięte z systemu lub gdy wykryte urządzenie nie zostało ostatnio wykryte:

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

Wykrywanie urządzeń w pobliżu

Aby rozpocząć wykrywanie urządzeń w pobliżu, użyj metody bluetooth.startDiscovery. Odkrywanie może wymagać znacznych zasobów, dlatego po zakończeniu należy wywołać metodę bluetooth.stopDiscovery.

Aby wykryć urządzenia w pobliżu, wywołaj bluetooth.startDiscovery. Nie wykonuj połączeń warunkowych na podstawie właściwości discovering parametru bluetooth.AdapterState. Wywołanie zakończy się pomyślnie, nawet jeśli inna aplikacja wykryje urządzenia w pobliżu, a adapter będzie nadal wykrywać urządzenia po zatrzymaniu tej aplikacji.

Informacje o każdym nowo wykrytego urządzeniu są odbierane za pomocą zdarzenia bluetooth.onDeviceAdded. Zdarzenie nie będzie wysyłane w przypadku urządzeń, które zostały niedawno wykryte lub zostały wcześniej sparowane lub połączone. Zamiast tego wywołaj bluetooth.getDevices, aby uzyskać aktualne informacje, i użyj zdarzenia bluetooth.onDeviceChanged, aby otrzymywać powiadomienia o zmianach tych informacji w wyniku ich wykrycia.

Przykład:

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

Jeśli użytkownik wyłączy radio Bluetooth, wszystkie sesje wykrywania zostaną zakończone i nie wznowione automatycznie po włączeniu radia. Jeśli jest to istotne w przypadku Twojej aplikacji, obejrzyj zdarzenie bluetooth.onAdapterStateChanged. Jeśli właściwość discovering zmieni się na false, aplikacja będzie musiała ponownie wywołać bluetooth.startDiscovery, aby wznowić. Pamiętaj, by odkrywać zasoby, które wymagają dużo zasobów.

Identyfikowanie urządzeń

Dostępnych jest kilka różnych opcji identyfikowania urządzeń zwróconych przez bluetooth.getDevices i powiązanych zdarzeń.

Jeśli urządzenie obsługuje specyfikację identyfikatora urządzenia Bluetooth, do obiektu Device z polami określonymi w tej specyfikacji dodanych jest kilka właściwości. Przykład:

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

Specyfikacja identyfikatora urządzenia zwykle wystarcza do identyfikacji konkretnego modelu, a nawet wersji urządzenia od dostawcy. Jeśli go nie ma, musisz polegać na informacjach o klasie lub typie urządzenia, opcjonalnie połączone z prefiksem producenta w address.

Większość urządzeń Bluetooth podaje informacje o klasie urządzenia jako pole bitowe interpretowane zgodnie z dokumentem Baseband Assigned Numbers (Numer przypisany pasma podstawowego). To pole bitowe jest dostępne we właściwości 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));
    }
  }
});

Analizowanie pola może być skomplikowane, więc w przypadku najpopularniejszych typów urządzeń Chrome robi to za Ciebie i ustawia pole type. Jeśli ta opcja nie jest dostępna lub jest niewystarczająca do Twoich potrzeb, musisz samodzielnie przeanalizować pole 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].type);
    }
  }
});

Korzystanie z RFCOMM i L2CAP

Aplikacje Chrome mogą nawiązywać połączenia z dowolnym urządzeniem obsługującym usługi RFCOMM lub L2CAP. Obejmuje to większość klasycznych urządzeń Bluetooth dostępnych na rynku.

Łączę z gniazdkiem

Aby nawiązać połączenie z urządzeniem, potrzebujesz 3 rzeczy. Gniazdko, z którym można nawiązać połączenie, utworzone za pomocą metody bluetoothSocket.create; adres urządzenia, z którym chcesz się połączyć, oraz identyfikator UUID usługi.

Przed nawiązaniem połączenia upewnij się, że adapter zna urządzenie, korzystając z interfejsu bluetooth.getDevice lub interfejsów API wykrywania urządzeń.

Informacje niezbędne do nawiązania połączenia bazowego, w tym informacje o tym, czy należy użyć protokołu RFCOMM czy L2CAP oraz który kanał lub PSM uzyskuje się za pomocą wykrywania SDP na urządzeniu.

Przykład:

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

Zachowaj nick dla socketId, aby móc później wysyłać do niego dane (bluetoothSocket.send).

Odbieranie i wysyłanie do gniazda

Odbieranie danych z gniazdka i wysyłanie do niego danych używa obiektów ArrayBuffer. Więcej informacji o obiektach TrackBuffer znajdziesz w omówieniu tablic o typach JavaScript oraz w samouczku Jak przekonwertować obiekt TrackBuffer na String (i z niego).

Aby wysłać dane, które masz w usłudze arrayBuffer, użyj funkcji 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")
  }
})

W przeciwieństwie do metody wysyłania danych dane są odbierane w ramach zdarzenia (bluetoothSocket.onReceive). Gniazdka są tworzone jako niewstrzymane (patrz bluetoothSocket.setPaused), dzięki czemu odbiornik zdarzenia jest zwykle dodawany między tagami bluetoothSocket.create i bluetoothSocket.connect.

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

Błędy odbierania gniazdka i rozłączanie

Aby otrzymywać powiadomienia o błędach gniazd, w tym o rozłączeniu, dodaj detektor do zdarzenia bluetoothSocket.onReceiveError.

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

Odłączanie od gniazdka

Aby rozłączyć połączenie i odłączyć gniazdko, użyj polecenia bluetoothSocket.disconnect.

chrome.bluetoothSocket.disconnect(socketId);

Usługi wydawnicze

Oprócz nawiązywania połączeń wychodzących z urządzeniami Aplikacje Chrome mogą publikować usługi, z których może korzystać dowolne urządzenie obsługujące RFCOMM lub L2CAP.

Słuchanie z gniazdka

Obsługiwane są 2 typy opublikowanych usług. RFCOMM jest najczęściej używany i obejmuje większość urządzeń i profili:

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

Drugi to L2CAP obejmuje inne typy urządzeń oraz zastosowania specyficzne dla dostawców, takie jak przesyłanie oprogramowania układowego.

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

W obu przypadkach można przekazać opcjonalny bluetoothSocket.ListenOptions, aby przydzielić określony kanał lub PSM. Wywołanie zwrotne wskazuje błąd występujący w polu chrome.runtime.lastError, a w przeciwnym razie powodzenie. Zachowaj nick dla socketId, aby móc później akceptować połączenia (bluetoothSocket.onAccept) z tego gniazda.

Akceptowanie połączeń z klientami

Połączenia z klientem są akceptowane i przekazywane do aplikacji za pomocą zdarzenia 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);
});

Przestań akceptować połączenia z klientami

Aby przestać akceptować połączenia z klientami i cofnąć publikację usługi, użyj polecenia bluetoothSocket.disconnect.

chrome.bluetoothSocket.disconnect(serverSocketId);

Interakcja z urządzeniami o niskim zużyciu energii

Bluetooth Low Energy (Bluetooth Smart) to technologia bezprzewodowa mająca na celu zmniejszenie zużycia energii. Interfejs Bluetooth Low Energy API umożliwia aplikacjom wdrożenie głównej roli w połączeniu LE z urządzeniem peryferyjnym. W kolejnych sekcjach opisano, jak wykrywać urządzenia peryferyjne Bluetooth Low Energy, łączyć się z nimi i wchodzić z nimi w interakcje.

Wykrywanie urządzeń peryferyjnych i łączenie się z nimi

Podobnie jak w przypadku tradycyjnych urządzeń Bluetooth urządzenia peryferyjne LE można wykrywać, korzystając z metod opisanych w artykule Wykrywanie urządzeń w pobliżu . Urządzenie LE sprawia, że jest wykrywalne, wysyłając pakiety danych nazywane „danymi reklamowymi”, a urządzenie działa w trybie reklamowym. Dane reklamowe mogą zawierać identyfikatory UUID usług, które są dostępne na urządzeniu. Jeśli identyfikatory te są obecne, będą dostępne za pomocą właściwości uuids odpowiedniego obiektu bluetooth.Device.

Po wykryciu urządzenia LE można połączyć się z urządzeniem bluetoothLowEnergy.connect, aby aplikacja mogła korzystać z jego usług:

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

Po nawiązaniu połączenia właściwość connected odpowiedniego obiektu bluetooth.Device będzie miała wartość true. Wywołanie bluetoothLowEnergy.connect powoduje zgłoszenie roszczenia przez aplikację dotyczącą fizycznego połączenia z urządzeniem. Może istnieć fizyczne połączenie z urządzeniem bez wywoływania metody bluetoothLowEnergy.connect (na przykład z powodu innej aplikacji). W takim przypadku, chociaż aplikacja nadal może wchodzić w interakcje z usługami na urządzeniu, powinna zawsze wywoływać metodę bluetoothLowEnergy.connect, aby uniemożliwić innej aplikacji rozłączenie fizycznego połączenia.

Gdy aplikacja nie będzie już musiała być połączona, może usunąć swoje roszczenie dotyczące połączenia, wywołując bluetoothLowEnergy.disconnect:

chrome.bluetoothLowEnergy.disconnect(deviceAddress);

Pamiętaj, że nie musi to spowodować zniszczenia fizycznego połączenia z urządzeniem, ponieważ istnieją inne aplikacje, które mają aktywne połączenie z tym urządzeniem. Czasami urządzenie może zostać rozłączone z powodów, które są poza kontrolą aplikacji (np. zniknie lub zostanie wyraźnie rozłączone przez użytkownika za pomocą narzędzi systemu operacyjnego). Aplikacja powinna rejestrować zdarzenie bluetooth.onDeviceChanged, aby otrzymywać powiadomienia o zmianach w połączeniu i w razie potrzeby ponownie nawiązać połączenie.

Po nawiązaniu połączenia urządzenie, na którym działa Chrome, będzie miało tzw. centralną rolę, a urządzenie zdalne – rolę urządzenia peryferyjnego. Na tym etapie aplikacja może wchodzić w interakcje z usługami na urządzeniu za pomocą metod opisanych w następnej sekcji. Uwaga: interfejsy API nie obsługują obecnie działania jako urządzeń peryferyjnych LE. Aplikacje można wdrożyć tylko rolę centralną.

Usługi, cechy i deskryptory

Bluetooth Low Energy wykorzystuje prosty protokół żądań i odpowiedzi nazywany protokołem atrybutów (ATT). Korzystając z ATT, centralne urządzenie komunikuje się z tak zwanymi atrybutami urządzenia peryferyjnego, tworząc specjalny profil Bluetooth nazywany ogólnym profilem atrybutu (GATT). GATT definiuje następujące ogólne koncepcje:

  • Usługa: usługa GATT reprezentuje zbiór danych i powiązanych z nimi zachowań służących realizacji określonej funkcji urządzenia. Na przykład pulsometr zwykle ma co najmniej jedną „usługę pomiaru tętna”. Informacje o usłudze GATT znajdują się w obiekcie bluetoothLowEnergy.Service.
  • Cecha: cecha GATT to podstawowy element danych używany do tworzenia usługi GATT, zawierający wartość wraz z właściwościami określającymi sposób dostępu do tej wartości. Na przykład „Usługa tętna” ma cechę „Pomiar tętna”, która służy do uzyskiwania wartości tętna użytkownika. Informacje o charakterze GATT są zawarte w obiekcie bluetoothLowEnergy.Characteristic.
  • Deskryptor: deskryptor cechy GATT zawiera dodatkowe informacje o cechy. Informacje o deskryptorze cechy GATT są zawarte w obiekcie bluetoothLowEnergy.Descriptor.

Interfejs Bluetooth Low Energy API umożliwia aplikacjom znajdowanie informacji o usługach, cechach i deskryptorach urządzenia przez wywoływanie metod bluetoothLowEnergy.getServices, bluetoothLowEnergy.getCharacteristics i bluetoothLowEnergy.getDescriptors. Aplikacje mogą filtrować usługi, cechy i deskryptory, porównując pole uuid z oczekiwanym identyfikatorem UUID GATT:

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

Każda usługa, cecha i deskryptor dostępne za pomocą interfejsu API mają przypisany unikalny identyfikator instancji, który można uzyskać za pomocą pola instanceId. Za pomocą tego identyfikatora instancji można zidentyfikować obiekt GATT i wykonać na nim określone operacje:

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

Zdarzenia usługi

Gdy urządzenie się połączy, Chrome wykryje jego usługi. Po wykryciu i usunięciu każdej usługi aplikacja będzie otrzymywać zdarzenia bluetoothLowEnergy.onServiceAdded i 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);
  });

Chrome asynchronicznie wykrywa wszystkie cechy i deskryptory usługi i po zakończeniu wykrywania wysyła zdarzenie bluetoothLowEnergy.onServiceAdded. Jeśli połączenie z urządzeniem peryferyjnym zostanie przerwane, Chrome usunie wszystkie powiązane usługi i wyśle zdarzenie bluetoothLowEnergy.onServiceRemoved.

Niektóre urządzenia peryferyjne mogą modyfikować swoje usługi, np. mogą się zmienić parametry usługi lub usługi mogą zostać dodane i usunięte. Chrome powiadamia aplikacje o tych zmianach za pomocą zdarzeń bluetoothLowEnergy.onServiceChanged, bluetoothLowEnergy.onServiceAdded i bluetoothLowEnergy.onServiceRemoved.

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

    updateMyService(service);
  });

Odczyt i zapis wartości cechy

Cecha GATT określa jeden aspekt usługi. Centralna aplikacja odczytuje, działa i modyfikuje stan usługi urządzenia peryferyjnego, działając na wartości cechy. Wartość charakterystyczna to sekwencja bajtów, a jej znaczenie określa ogólna specyfikacja definiująca konkretną cechę. Na przykład wartość cechy Pomiar tętna koduje tętno użytkownika oraz łączną liczbę spalonych przez niego kalorii, a Lokalizacja czujnika na ciele koduje, w którym miejscu w ciele należy nosić czujnik tętna.

Chrome udostępnia metodę bluetoothLowEnergy.readCharacteristicValue, która pozwala odczytać wartość cechy:

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

Niektóre cechy można zapisywać, zwłaszcza te, które zachowują się jak „punkty kontrolne”, gdy zapisywanie wartości ma skutki uboczne. Na przykład: punkt kontrolny tętna jest używany do informowania czujnika tętna, że resetuje on łączną liczbę spalonych kalorii i obsługuje tylko zapisy. Aby to zrobić, Chrome udostępnia metodę 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.
});

Deskryptory cech działają w ten sam sposób – są czytelne oraz możliwe do zapisu. Chrome udostępnia metody bluetoothLowEnergy.readDescriptorValue i bluetoothLowEnergy.writeDescriptorValue do odczytywania i zapisywania wartości deskryptora.

Aby sprawdzić, czy cecha obsługuje odczyty lub zapisy, aplikacja może sprawdzić pole properties obiektu bluetoothLowEnergy.Characteristic. Nie zawiera ono informacji o wymaganiach dotyczących zabezpieczeń dostępu do wartości, ale ogólnie określa, jaką wartość obsługuje cecha.

Obsługa powiadomień o wartości

Niektóre cechy identyfikują swoją wartość za pomocą powiadomień lub wskazówek. Na przykład cecha Pomiar tętna nie jest czytelna ani możliwa do zapisu, ale w regularnych odstępach czasu przesyła aktualne informacje o jej obecnej wartości. Aplikacje mogą odsłuchiwać te powiadomienia za pomocą zdarzenia bluetoothLowEnergy.onCharacteristicValueChanged.

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

    var bytes = new Uint8Array(chrc.value);

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

Nawet jeśli cecha obsługuje powiadomienia/wskaźniki, nie są one domyślnie włączone. Aby uruchomić lub zatrzymać odbiór zdarzenia bluetoothLowEnergy.onCharacteristicValueChanged, aplikacja powinna wywoływać metody bluetoothLowEnergy.startCharacteristicNotifications i bluetoothLowEnergy.stopCharacteristicNotifications.

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

Gdy włączysz powiadomienia, aplikacja będzie otrzymywać wartość bluetoothLowEnergy.onCharacteristicValueChanged za każdym razem, gdy otrzyma ona powiadomienie lub informację z cech. Jeśli cecha obsługuje odczyty, to zdarzenie zostanie też wysłane po pomyślnym wywołaniu funkcji bluetoothLowEnergy.readCharacteristicValue. Dzięki temu aplikacje mogą ujednolicić proces sterowania aktualizacją wartości aktywowaną przez żądanie odczytu i powiadomienia:

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

Jeśli cecha obsługuje powiadomienia, jej pole properties będzie zawierać właściwość "notify" lub "indicate".

UWAGA: jeśli cecha obsługuje powiadomienia/wskaźniki, będzie miała deskryptor „Konfiguracja cechy klienta”, który umożliwi włączenie/wyłączenie powiadomień. Chrome nie zezwala aplikacjom na zapisywanie tego deskryptora. Aby kontrolować zachowanie powiadomień, aplikacje powinny zamiast tego używać metod bluetoothLowEnergy.startCharacteristicNotifications i bluetoothLowEnergy.stopCharacteristicNotifications.