API Web Bluetooth позволяет веб-сайтам взаимодействовать с устройствами Bluetooth.
Что, если бы я сказал вам, что веб-сайты могут безопасно и с сохранением конфиденциальности взаимодействовать с находящимися поблизости устройствами Bluetooth? Таким образом, пульсометры, поющие лампочки и даже черепахи смогут напрямую взаимодействовать с веб-сайтом.
До сих пор возможность взаимодействия с устройствами Bluetooth была возможна только для приложений, специфичных для конкретной платформы. API Web Bluetooth призван изменить эту ситуацию и перенести его и в веб-браузеры.
Прежде чем мы начнем
В этом документе предполагается, что у вас есть базовые знания о том, как работают Bluetooth Low Energy (BLE) и общий профиль атрибутов .
Несмотря на то, что спецификация API Web Bluetooth еще не доработана, авторы спецификации активно ищут разработчиков-энтузиастов, которые могли бы опробовать этот API и оставить отзыв о спецификации и отзывах о реализации .
Подмножество API Web Bluetooth доступно в ChromeOS, Chrome для Android 6.0, Mac (Chrome 56) и Windows 10 (Chrome 70). Это означает, что вы должны иметь возможность запрашивать и подключаться к ближайшим устройствам Bluetooth Low Energy, считывать / записывать характеристики Bluetooth, получать уведомления GATT , знать, когда устройство Bluetooth отключается , и даже читать и записывать в дескрипторы Bluetooth . Дополнительную информацию см. в таблице совместимости браузеров MDN.
Для Linux и более ранних версий Windows включите флаг #experimental-web-platform-features
в about://flags
.
Доступно для исходных пробных версий
Чтобы получить как можно больше отзывов от разработчиков, использующих Web Bluetooth API на местах, Chrome ранее добавил эту функцию в Chrome 53 в качестве исходной пробной версии для ChromeOS, Android и Mac.
Судебный процесс успешно завершился в январе 2017 года.
Требования безопасности
Чтобы понять компромиссы в области безопасности, я рекомендую статью о модели безопасности Web Bluetooth от Джеффри Ясскина, инженера-программиста из команды Chrome, работающего над спецификацией API Web Bluetooth.
только HTTPS
Поскольку этот экспериментальный API представляет собой новую мощную функцию, добавленную в Интернет, он доступен только для защищенных контекстов . Это означает, что вам нужно будет строить с учетом TLS .
Требуется жест пользователя
В целях безопасности обнаружение устройств Bluetooth с помощью navigator.bluetooth.requestDevice
должно запускаться жестом пользователя, например прикосновением или щелчком мыши. Мы говорим о прослушивании событий pointerup
, click
и touchend
.
button.addEventListener('pointerup', function(event) {
// Call navigator.bluetooth.requestDevice
});
Вникнуть в код
API Web Bluetooth в значительной степени опирается на обещания JavaScript. Если вы с ними не знакомы, ознакомьтесь с этим замечательным руководством по Promises . Еще одна вещь: () => {}
— это стрелочные функции ECMAScript 2015.
Запросить устройства Bluetooth
Эта версия спецификации Web Bluetooth API позволяет веб-сайтам, работающим в центральной роли, подключаться к удаленным серверам GATT через соединение BLE. Он поддерживает связь между устройствами, поддерживающими Bluetooth 4.0 или более поздней версии.
Когда веб-сайт запрашивает доступ к близлежащим устройствам с помощью navigator.bluetooth.requestDevice
, браузер предлагает пользователю выбрать устройство, где он может выбрать одно устройство или отменить запрос.
Функция navigator.bluetooth.requestDevice()
принимает обязательный объект, определяющий фильтры. Эти фильтры используются для возврата только тех устройств, которые соответствуют некоторым рекламируемым службам Bluetooth GATT и/или имени устройства.
Фильтр услуг
Например, чтобы запросить устройства Bluetooth, рекламирующие службу аккумуляторов Bluetooth GATT :
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Если вашей службы Bluetooth GATT нет в списке стандартизированных служб Bluetooth GATT , вы можете предоставить либо полный UUID Bluetooth, либо короткую 16- или 32-битную форму.
navigator.bluetooth.requestDevice({
filters: [{
services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
}]
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Фильтр имени
Вы также можете запросить устройства Bluetooth на основе имени устройства, рекламируемого с помощью ключа фильтров name
, или даже префикса этого имени с помощью ключа фильтров namePrefix
. Обратите внимание, что в этом случае вам также потребуется определить ключ optionalServices
, чтобы иметь возможность доступа к любым службам, не включенным в фильтр служб. Если вы этого не сделаете, позже при попытке доступа к ним вы получите сообщение об ошибке.
navigator.bluetooth.requestDevice({
filters: [{
name: 'Francois robot'
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Фильтр данных производителя
Также можно запросить устройства Bluetooth на основе конкретных данных производителя, которые объявляются с помощью ключа фильтров manufacturerData
. Этот ключ представляет собой массив объектов с обязательным ключом идентификатора компании Bluetooth с именем companyIdentifier
. Вы также можете указать префикс данных, который фильтрует данные производителя с устройств Bluetooth, которые начинаются с него. Обратите внимание, что вам также потребуется определить ключ optionalServices
, чтобы иметь возможность доступа к любым службам, не включенным в фильтр служб. Если вы этого не сделаете, позже при попытке доступа к ним вы получите сообщение об ошибке.
// 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); });
Маску также можно использовать с префиксом данных для соответствия некоторым шаблонам в данных производителя. Чтобы узнать больше, ознакомьтесь с объяснением фильтров данных Bluetooth .
Фильтры исключения
Параметр exclusionFilters
в navigator.bluetooth.requestDevice()
позволяет исключить некоторые устройства из средства выбора браузера. Его можно использовать для исключения устройств, соответствующих более широкому фильтру, но не поддерживаемых.
// 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); });
Без фильтров
Наконец, вместо filters
вы можете использовать клавишу acceptAllDevices
, чтобы отобразить все ближайшие устройства Bluetooth. Вам также потребуется определить ключ optionalServices
, чтобы иметь доступ к некоторым сервисам. Если вы этого не сделаете, позже при попытке доступа к ним вы получите сообщение об ошибке.
navigator.bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Подключитесь к устройству Bluetooth
Итак, что же делать теперь, когда у вас есть BluetoothDevice
? Давайте подключимся к удаленному серверу GATT Bluetooth, который содержит определения служб и характеристик.
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); });
Чтение характеристики Bluetooth
Здесь мы подключаемся к GATT-серверу удаленного устройства Bluetooth. Теперь мы хотим получить первичную услугу GATT и прочитать характеристику, принадлежащую этой службе. Попробуем, например, прочитать текущий уровень заряда аккумулятора устройства.
В приведенном ниже примере battery_level
— это стандартизированная характеристика уровня заряда батареи .
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); });
Если вы используете пользовательскую характеристику Bluetooth GATT, вы можете предоставить для service.getCharacteristic
либо полный UUID Bluetooth, либо короткую 16- или 32-битную форму.
Обратите внимание, что вы также можете добавить прослушиватель событий characteristicvaluechanged
для характеристики, чтобы обрабатывать чтение ее значения. Ознакомьтесь с примером чтения измененного значения характеристики , чтобы узнать, как дополнительно обрабатывать предстоящие уведомления GATT.
…
.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);
}
Запись в характеристику Bluetooth
Записать характеристику Bluetooth GATT так же просто, как и прочитать ее. На этот раз давайте воспользуемся точкой контроля сердечного ритма, чтобы сбросить значение поля «Затраченная энергия» на 0 на устройстве мониторинга сердечного ритма.
Обещаю, здесь нет никакой магии. Все это объясняется на странице «Характеристика контрольной точки сердечного ритма» .
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); });
Получать уведомления ГАТТ
Теперь давайте посмотрим, как получать уведомления об изменении характеристики измерения сердечного ритма на устройстве:
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
}
В примере уведомлений показано, как остановить уведомления с помощью stopNotifications()
и правильно удалить добавленный прослушиватель событий characteristicvaluechanged
.
Отключиться от устройства Bluetooth
Чтобы обеспечить лучшее взаимодействие с пользователем, вы можете прослушивать события отключения и предлагать пользователю повторно подключиться:
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.`);
}
Вы также можете вызвать device.gatt.disconnect()
, чтобы отключить веб-приложение от устройства Bluetooth. Это запустит существующие прослушиватели событий gattserverdisconnected
. Обратите внимание, что связь с устройством Bluetooth НЕ прекратится, если другое приложение уже обменивается данными с устройством Bluetooth. Чтобы узнать больше, ознакомьтесь с примером отключения устройства и примером автоматического повторного подключения .
Чтение и запись в дескрипторы Bluetooth
Дескрипторы Bluetooth GATT — это атрибуты, описывающие характеристическое значение. Вы можете читать и записывать их аналогично характеристикам Bluetooth GATT.
Давайте посмотрим, например, как прочитать пользовательское описание интервала измерения термометра здоровья устройства.
В приведенном ниже примере health_thermometer
— это сервис Health Thermometer , measurement_interval
характеристика интервала измерения , а gatt.characteristic_user_description
— дескриптор описания характеристики пользователя .
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); });
Теперь, когда мы прочитали пользовательское описание интервала измерения термометра здоровья устройства, давайте посмотрим, как его обновить и записать собственное значение.
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); });
Примеры, демо и кодлабы
Все приведенные ниже образцы Web Bluetooth прошли успешное тестирование. Чтобы в полной мере насладиться этими образцами, я рекомендую вам установить [приложение BLE Peripheral Simulator для Android], которое имитирует периферийное устройство BLE с помощью службы батареи, службы измерения сердечного ритма или службы термометра здоровья.
Новичок
- Информация об устройстве — получение основной информации об устройстве с устройства BLE.
- Уровень заряда батареи — получение информации о батарее с устройства BLE, рекламирующего информацию о батарее.
- Сброс энергии — сброс энергии, затраченной на устройство BLE, сообщающее частоту сердечных сокращений.
- Свойства характеристики — отображение всех свойств определенной характеристики устройства BLE.
- Уведомления — запуск и остановка характерных уведомлений с устройства BLE.
- Отключение устройства — отключитесь и получите уведомление об отключении устройства BLE после подключения к нему.
- Получить характеристики — получить все характеристики рекламируемой услуги с устройства BLE.
- Получить дескрипторы — получить дескрипторы всех характеристик рекламируемой услуги с устройства BLE.
- Фильтр данных производителя — получение базовой информации об устройстве с устройства BLE, которая соответствует данным производителя.
- Фильтры исключений — получение основной информации об устройстве с устройства BLE с помощью базовых фильтров исключения.
Объединение нескольких операций
- Характеристики GAP — получите все характеристики GAP устройства BLE.
- Характеристики информации об устройстве — получите все характеристики информации об устройстве для устройства BLE.
- Потеря соединения — установите характеристику уровня оповещения устройства BLE (readValue и writeValue).
- Откройте для себя службы и характеристики — откройте для себя все доступные основные службы и их характеристики с устройства BLE.
- Автоматическое переподключение — повторное подключение к отключенному устройству BLE с использованием алгоритма экспоненциальной задержки.
- Чтение измененного значения характеристики — читайте уровень заряда батареи и получайте уведомления об изменениях с устройства BLE.
- Чтение дескрипторов — чтение дескрипторов всех характеристик службы с устройства BLE.
- Write Descriptor — запись в дескриптор «Характерное описание пользователя» на устройстве BLE.
Ознакомьтесь также с нашими тщательно подобранными демонстрациями Web Bluetooth и официальными лабораториями Web Bluetooth Codelabs .
Библиотеки
- web-bluetooth-utils — это модуль npm, который добавляет в API некоторые удобные функции.
- Оболочка Web Bluetooth API доступна в Node.js самом популярном центральном модуле BLE Node.js. Это позволяет вам использовать веб-пакеты/браузеры без необходимости использования сервера WebSocket или других плагинов.
- angular-web-bluetooth — это модуль для Angular , который абстрагирует весь шаблон, необходимый для настройки веб-API Bluetooth.
Инструменты
- Начало работы с веб-интерфейсом Bluetooth — это простое веб-приложение, которое сгенерирует весь шаблонный код JavaScript для начала взаимодействия с устройством Bluetooth. Введите имя устройства, услугу, характеристику, определите его свойства, и все готово.
- Если вы уже являетесь разработчиком Bluetooth, плагин Web Bluetooth Developer Studio также сгенерирует JavaScript-код Web Bluetooth для вашего устройства Bluetooth.
Советы
Страница Bluetooth Internals доступна в Chrome по about://bluetooth-internals
так что вы можете проверить все о ближайших устройствах Bluetooth: статус, службы, характеристики и дескрипторы.
![Скриншот внутренней страницы для отладки Bluetooth в Chrome](https://developer.chrome.google.cn/static/docs/capabilities/bluetooth/image/screenshot-the-internal-acdfb455a1a38.jpg?authuser=5&hl=ru)
Я также рекомендую посетить официальную страницу «Как зарегистрировать ошибки Web Bluetooth», так как отладка Bluetooth иногда может быть затруднена.
Что дальше
Сначала проверьте статус реализации браузера и платформы, чтобы узнать, какие части Web Bluetooth API реализуются в данный момент.
Хотя он еще не завершен, вот краткий обзор того, чего ожидать в ближайшем будущем:
- Сканирование близлежащих рекламных объявлений BLE будет выполняться с помощью
navigator.bluetooth.requestLEScan()
. - Новое событие
serviceadded
будет отслеживать вновь обнаруженные службы Bluetooth GATT, а событиеserviceremoved
будет отслеживать удаленные. Новое событиеservicechanged
сработает, когда какая-либо характеристика и/или дескриптор будет добавлена или удалена из службы Bluetooth GATT.
Показать поддержку API
Планируете ли вы использовать Web Bluetooth API? Ваша публичная поддержка помогает команде Chrome расставлять приоритеты в функциях и показывает другим поставщикам браузеров, насколько важно их поддерживать.
Отправьте твит @ChromiumDev, используя хэштег #WebBluetooth
и сообщите нам, где и как вы его используете.
Ресурсы
- Переполнение стека
- Статус функции Chrome
- Ошибки реализации Chrome
- Веб-спецификация Bluetooth
- Проблемы со спецификациями на GitHub
- Приложение BLE Peripheral Simulator
Благодарности
Спасибо Кейси Баскес за рецензию на эту статью. Изображение героя от SparkFun Electronics из Боулдера, США .