- Используем Web Bluetooth API для подключения пульсометра и разрабатываем приложение используя Vue.js
- Взлома не будет
- Подключаем устройство
- Дизайн
- Скетч
- Магия рисования совы
- Выводы
- Communicating with Bluetooth devices over JavaScript
- Before we start #
- Available for origin trials #
- Security requirements #
- HTTPS only #
- User gesture required #
- Get into the code #
- Request Bluetooth devices #
- Services filter #
- Name filter #
- Manufacturer data filter #
- No filters #
- Connect to a Bluetooth device #
- Read a Bluetooth Characteristic #
- Write to a Bluetooth Characteristic #
- Receive GATT notifications #
- Disconnect from a Bluetooth Device #
- Read and write to Bluetooth descriptors #
- Samples, demos and codelabs #
- Beginner #
- Combining multiple operations #
- Libraries #
- Tools #
- What’s next #
- Show support for the API #
- Resources #
- Acknowledgements #
Используем Web Bluetooth API для подключения пульсометра и разрабатываем приложение используя Vue.js
Продолжаем обсуждать темы затронутые на You Gonna Love Frontend конференции. Эта статья вдохновлённая докладом Michaela Lehr. Видео с конференции будут доступны уже на этой недели, пока есть слайды. (Видео уже доступно)
Michaela Lehr подключила вибратор к браузеру используя Web APIs, а именно Web Bluetooth API. Проснифериф трафик между приложением и вибратором, она установила, что посылаемые команды очень простые, например: vibrate: 5 . Затем научив его вибрировать под звуки стонов из видео, которые она могла найти в интернете — достигла своих целей 🙂
У меня таких игрушек нет и конструкцией использование не предусмотрено, но есть пульсометр Polar H10, который использует Bluetooth для передачи данных. Собственно его я и решил «взламывать».
Взлома не будет
Первым делом, стоит понять каким образом подключить девайс к браузеру? Гуглим или яндексим в зависимости от ваших наклонностей: Web Bluetooth API , и по первой ссылке видим статью на эту тему.
К сожалению все намного проще и нечего снифирить если вы не хотите, что-либо посылать на дейвайс, который этого не хочет. В той же статье даже есть демонстрация подключенного пульсометра.
Меня это дико обескуражило, даже исходники есть. Что за времена пошли?
Подключаем устройство
Давайте создадим index.html с типичной разметкой:
Поскольку мой пульсометр девайс сертифицированный хоть и ковался в китайских мастерских, но с соблюдением стандартов, его подключение и использование не должно вызвать каких либо сложностей. Существует такая вот вещь — Generic Attributes (GATT). Я сильно не вдавался в подробности, но если просто, то это своего рода спецификация которой следуют Bluetooth девайсы. GATT описывает их свойства и взаимодействия. Для нашего проекта, это все, что нам нужно знать. Полезной для нас ссылкой так же является список сервисов (девайсов по факту). Тут я нашел сервис Heart Rate (org.bluetooth.service.heart_rate) который похоже, то, что нам нужно.
Для того, что бы подключить устройство к браузеру, пользователь должен осмысленно, повзаимодействовать с UI. Так себе конечно безопасность, учитывая, что заходя в зал мой пульсометр молча конектится ко всему чему вздумается (в свое время я этому удивился). Спасибо конечно разработчикам браузеров, но why?! Ну да ладно, не сложно и не так уже противно.
Давайте добавим кнопоку и обработчик на страницу в тело :
Как вы видите пока тут никакого Vue, который я обещал судя по заголовку. Но я сам всего не знаю и пишу статью по ходу дела. Так, что пока делаем таким образом 🙂
Для того, что бы подключить устройство, мы должны использовать navigator.bluetooth.requestDevice . Данный метод умеет принимать массив фильтров. Так как наше приложение будет работать по большей части только с пульсометрами, мы отфильтруем по ним:
Откройте html файл в браузере или используйте browser-sync :
На мне одет пульсометр и спустя несколько секунд Chrome его нашел:
После того как мы нашли необходимый нам девайс, необходимо считывать с него данные. Для этого подключаем его к GATT серверу:
Данные которые мы хотим считывать находятся в характеристиках сервиса (Service Characteristics). У пульсометров всего 3 характеристики, и нас интересует именно org.bluetooth.characteristic.heart_rate_measurement
Для того, что бы считать эту характеристику нам необходимо получить главный сервис. Честно сказать не знаю, WHY. Быть может некоторые девайсы имеют несколько sub сервисов. Затем получить характеристику и подписаться на нотификации.
parseValue функция, которая используется для парсинга данных, спецификацию данных вы можете найти тут — org.bluetooth.characteristic.heart_rate_measurement. Детально на этой функции останавливаться не будем, там все банально.
И так, в консольке мы видим необходимые нам данные. Помимо пульса, мой пульсометр еще показывает RR интервалы. Я так и не придумал как их использовать, это вам домашнее задание 🙂
Дизайн
Следующим этапом необходимо продумать дизайн приложения. Ох, конечно простая на первый вид статья превращается в нетривиальную задачу. Хочется использовать всевозможные пафосные вещи и уже в голове очередь из статей которые не обходимо прочитать по CSS Grids, Flexbox и манипуляции CSS анимацией используя JS (Аниманция пульса дело не статичное).
Скетч
Мне нравится красивый дизайн, но дизайнер с меня так себе.
Фотошопа у меня нет, будем как-то выкручиваться по ходу дела.
Для начала давайте создадим новый Vue.js проект используя Vue-cli
Я выбрал ручную настройку и первая страница настроек у меня выглядит так:
Далее выбирайте под себя, но у меня конфиг Airbnb, Jest и Sass.
Посмотрел половину уроков по CSS Grids от Wes Bos, рекомендую, они бесплатные.
Самое время заняться первоначальной версткой. Мы не будем использовать какие-либо CSS фреймворки, все свое. Разумеется и над поддержкой мы не думаем.
Магия рисования совы
И так, первым делом давайте определим наш layout . По факту приложение будет состоять из двух частей. Мы их так и назовем — first и second . В первой части у нас будет числовое представление (ударов в минуту), во второй график.
Цветовую схему я решил украсть отсюда.
Запускаем наше Vue приложение, если вы еще этого не сделали:
Тулза сама откроет браузер (или нет), там есть хот релоад и линка для внешнего тестирования. Я сразу положил возле себя мобилку, ведь мы думаем о mobile first дизайне. К сожалению, я добавил в шаблон PWA, и на мобилке, кеш чистится при закрытии браузера, но бывает и ок обновляется на сохранение. В общем непонятный момент с которым я не стал разбираться.
Для начала добавим utils.js , с нашей функцией парсинга значений, немного отрефакторив его под eslint в проекте.
Затем убираем все лишнее из HelloWolrd.vue переименовав его в HeartRate.vue , этот компонент будет отвечать за отображения ударов в минуту.
Создаем HeartRateChart.vue для графика:
И собственно говоря mixins.scss , пока тут только один миксин который отвечает за цвет иконки и текста отображающего удары в минуту.
Получилось, вот такое:
Из интересных моментов — используются нативные CSS Variables, но mixins от SCSS.
Вся страница это CSS Grid :
Подобно flexbox , родительский контейнер должен иметь какой-то display . В данном случае это grid .
grid-gap — своего рода пробелы между columns и rows .
height: 100vh — высота на весь viewport , это необходимо, что бы fr занимал пространство во всю высоту (2 части нашего приложения).
grid-template-rows — определяем наш темплейт, fr это сахарная единица, которая учитывает grid-gap и прочее влияющие на размер свойства.
grid-template-areas — в нашем примере просто семантическая.
Хром на данный момент до сих пор не завез нормальных тулзов для инспекции CSS Grids:
В то же время в мазиле:
Теперь нам необходимо добавить обработчик клика на кнопку, аналогично как мы это делали раньше.
Добавляем обработчик:
Не забывайте, что это работает только в хроме и только в хроме на андроиде 🙂
Далее добавим график, мы будем использовать Chart.js и обертку под Vue.js
Polar выделяет 5ть зон тренировки. По этому нам надо как-то различать эти зоны и/или хранить их. У нас уже есть heartRateData . Для эстетики, сделаем дефолтное значение вида:
Будем раскидывать значения согласно 5ти зонам:
Vue.js ChartJS используются следующим образом:
Вы импортируете необходимый стиль графика, расширяете ваш компонент и используя this.renderChart отображаете график.
В нашем случае необходимо обновлять график по мере поступления новых данных, по этому мы спрячем отображение в отдельном методе updateChart и будем вызывать его на mounted и используя вотчеры следить за проперти values :
Наше приложение готово. Но, что бы не скакать перед экраном и доводить себя до 5того уровня, давайте добавим кнопку, которая сгенерирует для нас рандомные данные всех 5ти уровней:
Выводы
Использовать Web Bluetooth API очень просто. Есть моменты с необходимостью считывания данных используя побитовые операторы, но это видать специфика области. Из минусов конечно же является поддержка. На данный момент это только хром, а на мобилках хром и только на андроиде.
Источник
Communicating with Bluetooth devices over JavaScript
The Web Bluetooth API allows websites to communicate with Bluetooth devices.
What if I told you websites could communicate with nearby Bluetooth devices in a secure and privacy-preserving way? This way, heart rate monitors, singing lightbulbs, and even turtles could interact directly with a website.
Until now, the ability to interact with Bluetooth devices has been possible only for platform-specific apps. The Web Bluetooth API aims to change this and brings it to web browsers as well.
Before we start #
This article assumes you have some basic knowledge of how Bluetooth Low Energy (BLE) and the Generic Attribute Profile (GATT) work.
Even though the Web Bluetooth API specification is not finalized yet, the spec authors are actively looking for enthusiastic developers to try out this API and give feedback on the spec and feedback on the implementation.
A subset of the Web Bluetooth API is available in Chrome OS, Chrome for Android 6.0, Mac (Chrome 56) and Windows 10 (Chrome 70). This means you should be able to request and connect to nearby Bluetooth Low Energy devices, read/write Bluetooth characteristics, receive GATT Notifications, know when a Bluetooth device gets disconnected, and even read and write to Bluetooth descriptors. See MDN’s Browser compatibility table for more information.
For Linux and earlier versions of Windows, enable the #experimental-web-platform-features flag in about://flags .
Available for origin trials #
In order to get as much feedback as possible from developers using the Web Bluetooth API in the field, Chrome has previously added this feature in Chrome 53 as an origin trial for Chrome OS, Android, and Mac.
The trial has successfully ended in January 2017.
Security requirements #
To understand the security tradeoffs, I recommend the Web Bluetooth Security Model post from Jeffrey Yasskin, a software engineer on the Chrome team, working on the Web Bluetooth API specification.
HTTPS only #
Because this experimental API is a powerful new feature added to the web, it is made available only to secure contexts. This means you’ll need to build with TLS in mind.
User gesture required #
As a security feature, discovering Bluetooth devices with navigator.bluetooth.requestDevice must be triggered by a user gesture such as a touch or a mouse click. We’re talking about listening to pointerup , click , and touchend events.
Get into the code #
The Web Bluetooth API relies heavily on JavaScript Promises. If you’re not familiar with them, check out this great Promises tutorial. One more thing, () => <> are simply ECMAScript 2015 Arrow functions.
Request Bluetooth devices #
This version of the Web Bluetooth API specification allows websites, running in the Central role, to connect to remote GATT Servers over a BLE connection. It supports communication among devices that implement Bluetooth 4.0 or later.
When a website requests access to nearby devices using navigator.bluetooth.requestDevice , the browser prompts user with a device chooser where they can pick one device or simply cancel the request.
The navigator.bluetooth.requestDevice() function takes a mandatory object that defines filters. These filters are used to return only devices that match some advertised Bluetooth GATT services and/or the device name.
Services filter #
For instance, to request Bluetooth devices advertising the Bluetooth GATT Battery Service:
If your Bluetooth GATT Service is not on the list of the standardized Bluetooth GATT services though, you may provide either the full Bluetooth UUID or a short 16- or 32-bit form.
Name filter #
You can also request Bluetooth devices based on the device name being advertised with the name filters key, or even a prefix of this name with the namePrefix filters key. Note that in this case, you will also need to define the optionalServices key to be able to access any services not included in a service filter. If you don’t, you’ll get an error later when trying to access them.
Manufacturer data filter #
It is also possible to request Bluetooth devices based on the manufacturer specific data being advertised with the manufacturerData filters key. This key is an array of objects with a mandatory Bluetooth company identifier key named companyIdentifier . You can also provide a data prefix that filters manufacturer data from Bluetooth devices that start with it. Note that you will also need to define the optionalServices key to be able to access any services not included in a service filter. If you don’t, you’ll get an error later when trying to access them.
A mask can also be used with a data prefix to match some patterns in manufacturer data. Check out the Bluetooth data filters explainer to learn more.
At the time of writing, the manufacturerData filter key is available in Chrome 92. If backwards compatibility with older browsers is desired, you have to provide a fallback option as the manufacturer data filter is considered empty. See an example.
No filters #
Finally, instead of filters you can use the acceptAllDevices key to show all nearby Bluetooth devices. You will also need to define the optionalServices key to be able to access some services. If you don’t, you’ll get an error later when trying to access them.
Caution: This may result in a bunch of unrelated devices being shown in the chooser and energy being wasted as there are no filters. Use it with caution.
Connect to a Bluetooth device #
So what do you do now that you have a BluetoothDevice ? Let’s connect to the Bluetooth remote GATT Server which holds the service and characteristic definitions.
Read a Bluetooth Characteristic #
Here we are connected to the GATT Server of the remote Bluetooth device. Now we want to get a Primary GATT Service and read a characteristic that belongs to this service. Let’s try, for instance, to read the current charge level of the device’s battery.
In the example below, battery_level is the standardized Battery Level Characteristic.
If you use a custom Bluetooth GATT characteristic, you may provide either the full Bluetooth UUID or a short 16- or 32-bit form to service.getCharacteristic .
Note that you can also add a characteristicvaluechanged event listener on a characteristic to handle reading its value. Check out the Read Characteristic Value Changed Sample to see how to optionally handle upcoming GATT notifications as well.
Write to a Bluetooth Characteristic #
Writing to a Bluetooth GATT Characteristic is as easy as reading it. This time, let’s use the Heart Rate Control Point to reset the value of the Energy Expended field to 0 on a heart rate monitor device.
I promise there is no magic here. It’s all explained in the Heart Rate Control Point Characteristic page.
Receive GATT notifications #
Now, let’s see how to be notified when the Heart Rate Measurement characteristic changes on the device:
The Notifications Sample shows you to how to stop notifications with stopNotifications() and properly remove the added characteristicvaluechanged event listener.
Disconnect from a Bluetooth Device #
To provide a better user experience, you may want to listen for disconnection events and invite the user to reconnect:
You can also call device.gatt.disconnect() to disconnect your web app from the Bluetooth device. This will trigger existing gattserverdisconnected event listeners. Note that it will NOT stop bluetooth device communication if another app is already communicating with the Bluetooth device. Check out the Device Disconnect Sample and the Automatic Reconnect Sample to dive deeper.
Caution: Bluetooth GATT attributes, services, characteristics, etc. are invalidated when a device disconnects. This means your code should always retrieve (through getPrimaryService(s) , getCharacteristic(s) , etc.) these attributes after reconnecting.
Read and write to Bluetooth descriptors #
Bluetooth GATT descriptors are attributes that describe a characteristic value. You can read and write them to in a similar way to Bluetooth GATT characteristics.
Let’s see for instance how to read the user description of the measurement interval of the device’s health thermometer.
In the example below, health_thermometer is the Health Thermometer service, measurement_interval the Measurement Interval characteristic, and gatt.characteristic_user_description the Characteristic User Description descriptor.
Now that we’ve read the user description of the measurement interval of the device’s health thermometer, let’s see how to update it and write a custom value.
Samples, demos and codelabs #
All Web Bluetooth samples below have been successfully tested. To enjoy these samples to their fullest, I recommend you install the BLE Peripheral Simulator Android App which simulates a BLE peripheral with a Battery Service, a Heart Rate Service, or a Health Thermometer Service.
Beginner #
- Device Info — retrieve basic device information from a BLE Device.
- Battery Level — retrieve battery information from a BLE Device advertising Battery information.
- Reset Energy — reset energy expended from a BLE Device advertising Heart Rate.
- Characteristic Properties — display all properties of a specific characteristic from a BLE Device.
- Notifications — start and stop characteristic notifications from a BLE Device.
- Device Disconnect — disconnect and get notified from a disconnection of a BLE Device after connecting to it.
- Get Characteristics — get all characteristics of an advertised service from a BLE Device.
- Get Descriptors — get all characteristics’ descriptors of an advertised service from a BLE Device.
- Manufacturer Data Filter — retrieve basic device information from a BLE Device that matches manufacturer data.
Combining multiple operations #
- GAP Characteristics — get all GAP characteristics of a BLE Device.
- Device Information Characteristics — get all Device Information characteristics of a BLE Device.
- Link Loss — set the Alert Level characteristic of a BLE Device (readValue & writeValue).
- Discover Services & Characteristics — discover all accessible primary services and their characteristics from a BLE Device.
- Automatic Reconnect — reconnect to a disconnected BLE device using an exponential backoff algorithm.
- Read Characteristic Value Changed — read battery level and be notified of changes from a BLE Device.
- Read Descriptors — read all characteristic’s descriptors of a service from a BLE Device.
- Write Descriptor — write to the descriptor «Characteristic User Description» on a BLE Device.
Libraries #
- web-bluetooth-utils is a npm module that adds some convenience functions to the API.
- A Web Bluetooth API shim is available in noble, the most popular Node.js BLE central module. This allows you to webpack/browserify noble without the need for a WebSocket server or other plugins.
- angular-web-bluetooth is a module for Angular that abstracts away all the boilerplate needed to configure the Web Bluetooth API.
Tools #
- Get Started with Web Bluetooth is a simple Web App that will generate all the JavaScript boilerplate code to start interacting with a Bluetooth device. Enter a device name, a service, a characteristic, define its properties and you’re good to go.
- If you’re already a Bluetooth developer, the Web Bluetooth Developer Studio Plugin will also generate the Web Bluetooth JavaScript code for your Bluetooth device.
A Bluetooth Internals page is available in Chrome at about://bluetooth-internals so that you can inspect everything about nearby Bluetooth devices: status, services, characteristics, and descriptors.
Internal page in Chrome for debugging Bluetooth devices.
I also recommend checking out the official How to file Web Bluetooth bugs page as debugging Bluetooth can be hard sometimes.
Caution: Reading and writing to Bluetooth characteristics in parallel may raise errors depending on the platform. I strongly suggest you manually queue GATT operation requests when appropriate. See «GATT operation in progress — how to handle it?».
What’s next #
Check the browser and platform implementation status first to know which parts of the Web Bluetooth API are currently being implemented.
Though it’s still incomplete, here’s a sneak peek of what to expect in the near future:
- Scanning for nearby BLE advertisements will happen with navigator.bluetooth.requestLEScan() .
- A new serviceadded event will track newly discovered Bluetooth GATT Services while serviceremoved event will track removed ones. A new servicechanged event will fire when any characteristic and/or descriptor gets added or removed from a Bluetooth GATT Service.
Show support for the API #
Are you planning to use the Web Bluetooth API? Your public support helps the Chrome team prioritize features and shows other browser vendors how critical it is to support them.
Send a tweet to @ChromiumDev using the hashtag #WebBluetooth and let us know where and how you are using it.
Resources #
- Stack Overflow: https://stackoverflow.com/questions/tagged/web-bluetooth
- Chrome Feature Status: https://www.chromestatus.com/feature/5264933985976320
- Chrome Implementation Bugs: https://crbug.com/?q=component:Blink>Bluetooth
- Web Bluetooth Spec: https://webbluetoothcg.github.io/web-bluetooth
- Spec Issues: https://github.com/WebBluetoothCG/web-bluetooth/issues
- BLE Peripheral Simulator App: https://github.com/WebBluetoothCG/ble-test-peripheral-android
Acknowledgements #
Thanks to Kayce Basques for reviewing this article. Hero image by SparkFun Electronics from Boulder, USA.
Источник