Приложение Bluetooth с открытым исходным кодом для Chrome, iOS и Android

Wireless Cables Inc. компания по производству оборудования. Разработка мобильного и веб-программного обеспечения всегда была сложной задачей. Мы знаем прошивку и C-код, а также все мелочи низкого уровня, такие как проектирование печатных плат, но программное обеспечение пользовательского уровня на самом деле не является нашим делом.

Я хотел бы описать здесь, почему и как мы реализовали многоразовое универсальное приложение BLE и как вы можете использовать этот код для реализации собственного приложения для вашего оборудования BLE. Затем единый исходный код будет работать как прогрессивное веб-приложение (PWA) в Chrome (и других браузерах в будущем), а также изначально скомпилирован на iOS и Android.

Пределы BLE

Bluetooth с низким энергопотреблением, BLE, добавляет это требование к дизайну программного обеспечения за счет отсутствия стандартного стандарта потоковой передачи данных, такого как Профиль последовательного порта (SPP), который существует для стандартного Bluetooth. Хотя существует ряд профилей LE, например для мониторов сердечного ритма и т. д. общее определение потоковой передачи данных отсутствует.

Несколько компаний (Silabs, Nordic, TI, Dialog) начали внедрять свою собственную так называемую модель SPP-over-GATT, но все они зависят от поставщика. Для этого не существует стандартного обозначения службы GATT. Поэтому не существует стандарта, как установить скорость передачи данных и тому подобное. Даже безопасность неполная, кому разрешено подключаться или нет.

Конечно, вы можете использовать направленную рекламу BLE для сопряжения с одним приемником, но устройство «сервис», которое позволяет нескольким приемникам безопасно подключаться, если у них есть учетные данные, сложно и может даже потребовать доступ к устройству заранее.

Стандартный Bluetooth имеет такую ​​приятную функцию, как PIN-код. Если у вас есть PIN-код, вы можете подключиться. Так называемый Security-Mode2-Service - это режим, который аутентифицируется для каждого устройства. PIN-коды запрашиваются каждый раз, когда кто-то хочет подключиться.

Миссия

Наша цель состояла в том, чтобы реализовать приложение с одним исходным кодом для общей потоковой передачи данных через BLE, которое может работать как прогрессивное веб-приложение (PGA) в Chrome, а также изначально на iOS и Android.

Нам нужен был эффективный и современный способ кодирования, создания многоразовых, поддерживаемых и легко изменяемых приложений уровня пользователя. И нам нужна была среда для использования различных API-интерфейсов Bluetooth в веб-интерфейсе Bluetooth и встроенном.

И мы хотели сделать его с открытым исходным кодом:

  • Приложения пользовательского уровня, даже для наших продуктов, никуда не годятся
  • Приведите пример реализации кроссплатформенных приложений BLE.
  • Найдите участников, чтобы сделать его лучше (Web BT API против собственного API Cordova)
  • Продвигайте продукты с низким энергопотреблением Bluetooth

Ionic 3 Framework был ответом. Ionic создает мобильные приложения в виде веб-приложений с HTML / Javascript для пользовательского интерфейса, но в основном интегрирует Typescript в качестве языка, взаимодействие типа Angular / Bootstrap и Cordova для доступа к собственному устройству. Это великолепная платформа, которая позволяет использовать навыки веб-разработчика для разработки нативных мобильных приложений на любой платформе.

Обзор исходного кода

Давайте углубимся в исходный код, который доступен на Github. В приложении реализован общий терминал для связи с асинхронным последовательным портом, также известным как RS232.



Вы также можете получить всю среду сборки на Ionic Marketplace в качестве начального приложения: https://market.ionic.io/starters/bluetooth

Служба GATT

Мы решили перегрузить относительно общий стандарт LE для Automation IO Service для нашей последовательной связи. Идея этой службы состоит в том, чтобы иметь доступные для чтения и записи характеристики, представляющие параллельные линии ввода-вывода. Это достаточно близко для представления пакета последовательных данных RS232, если вы думаете о регистрах сдвига. В основном мы используем цифровую характеристику для записи (отправки последовательного пакета) и для уведомления нас о прибытии байта.

Интернет-соединение Bluetooth и встроенный Bluetooth: сканирование

По сути, разница между реализацией Bluetooth в Интернете для браузера Chrome и встроенным Bluetooth от Cordova заключается в том, как вы сканируете устройства. Chrome имеет встроенную систему с надежно защищенной системой выбора. Приложению не нужно управлять обнаруженными устройствами, Web Bluetooth сделает это за вас.

Решаем, где мы находимся в управлении вкладками. По сути, это начальная страница нашего приложения.

<ion-tabs selectedIndex="0" #myTabs>
    <ion-tab [root]="terminalRoot" tabTitle="Terminal" 
        tabIcon="app-bluetooth"></ion-tab>
    <ion-tab [root]="settingsRoot" tabTitle="Settings"
        tabIcon="settings"></ion-tab>
    <ion-tab [root]="aboutRoot" tabTitle="About" 
        tabIcon="information-circle"></ion-tab>
</ion-tabs>

Для встроенного Bluetooth приложение должно управлять списком обнаруженных устройств. Вы найдете это в папке устройств. Выбор платформы - это отправная точка нашего приложения, это страница входа. Код tabs.ts определяет, какая страница будет отображаться первой. На нативном мы отображаем страницу устройств, на Chrome сразу отображаем окно терминала.

this.isCordova = this.platform.is("cordova");
console.log("TABS: Platform: " + this.platform.platforms());
if (this.isCordova) {
    // display the device page instead of the terminal page
    this.terminalRoot = 'DevicePage';

Не углубляясь в механизм выбора устройства, следует помнить о важном различии - это гораздо более строгая безопасность в Web Bluetooth. Например, без указания возможной доступной службы батареи вы не сможете подключиться к этой характеристике. Вы должны указать все характеристики, которые хотите использовать во время обнаружения, прежде чем сможете подключиться.

API-интерфейсы веб-Bluetooth и встроенного Bluetooth (Cordova) сильно различаются. Мы постарались только разделить различия между кодом поставщика веб-услуг Bluetooth (ble.ts) и нативной частью, в основном охватывая сканирование (device.ts). Общие части указаны в коде поставщика услуг.

Безопасность

Мы уже упоминали о безопасности и нашли простой способ ее реализовать. Устройства BLE позволяют подключаться, если рекламный пакет является неориентированным и указывает на возможность подключения. Большинство устройств BLE используют это. Или, если подключающееся устройство находится в белом списке и используется направленная реклама, только заранее определенный набор устройств может подключаться. Нам нужно было решение для громкой связи, что-то, что позволяло бы новым устройствам подключаться, если они знают некоторые учетные данные, но не касаясь оборудования.

Как указано, мы добавили ПИН-коды. Для записи учетных данных необходимо использовать новую зашифрованную характеристику только для записи сразу после успешного подключения. Если подтвердится, то теперь доступны все остальные характеристики. В противном случае и в течение короткого времени отключается.

await this.ble.password( pwd );

Вы найдете этот код пароля и характеристику записи в главном файле terminal.ts. Это должно быть сделано до того, как какая-либо характеристика будет прочитана / записана или даже настроена на уведомление. Чтобы обмануть это с помощью наблюдаемого Typecript, который мы создаем для характеристики, подлежащей уведомлению, мы расширяем объект Observable в Reactive Rxjs следующим образом. Теперь мы можем управлять всеми характеристиками соединений, включая уведомления и записывать пароль, прежде чем мы подпишемся на нашу строку данных.

// module augmentation, adding an interface we can implement
declare module 'rxjs/Observable' {
    interface Observable<T> {
        doOnSubscribe(onSubscribe: () => void): this;
    }
}

Представление

Управление передачей данных BLE - это очень асинхронный процесс. Данные могут поступить в любой момент, и передача данных должна осуществляться синхронно с успешной передачей предыдущего пакета. Кроме того, размер пакета ограничен для каждой записи в характеристический вызов. К счастью, обо всем этом позаботится свойство Observable для записи в строку данных. С помощью этого кода мы достигаем скорости передачи данных до 10 кБайт / с без ошибок или повторных отправок. Также обратите внимание, что в родном Bluetooth мы пишем без ответа, что позволяет нам использовать несколько слотов для передачи пакетов подряд, не дожидаясь следующего интервала. Он работает лучше.

// write to char in chunks as well as step by step
// using native Bluetooth when peripheral as parameter isn't there
public sendText( text: string, peripheral?: any ){

    //console.log("sending "+text);
    this.writableSubject.next(true);

    const bytes = text.split('').map(c => c.charCodeAt(0));
    const chunks = [];

    while( bytes.length > 0 ) {
        chunks.push(new Uint8Array(bytes.splice(0, 20)));
    }

    const result = Observable.zip(
            Observable.from( chunks ),
            this.writableSubject.filter(value => value)
        )
        .mergeMap(([ chunk, writeable ]) => {
            //console.log("writing: "+ chunk);
            this.writableSubject.next(false);

            if( peripheral !== undefined ) {
                // Native BLE is a promise
                return Observable.fromPromise(
                    this.ble.writeWithoutResponse( peripheral.id, 
                     UART_SERVICE_STR, UART_TXRX_STR, chunk.buffer )
                )
            } else {
                // Web Bluetooth
                return 
                  Observable.from(this.uartChar.writeValue(chunk));
            }
        })

        // timeout absolutely necessary because otherwise 
        // writeValue will fail when called too quickly
        .map(() => 
            setTimeout(() => this.writableSubject.next( true ), 10))
        // make this into a connectable Observable
        .publish();

    // connect to the Observable and get the result
    result.connect();
    return result;
}

Сделай сам

На странице терминала используется очень популярная библиотека Javascript, xterm.js. Тот, который мы использовали, версия 2.9.2, по-прежнему является чистым Javascript. В настоящее время предпринимаются попытки переписать этот код на Typescript версии 3.

Чистые библиотеки Javascript можно использовать в Typescript, импортировав все, что есть.

// Terminal
import * as Terminal from "xterm";
import style from "xterm/dist/xterm";
import "xterm/dist/addons/fit/fit";

Вы не получите никакого набора текста и можете использовать его по своему усмотрению, но он работает нормально, с некоторыми оговорками. Например. мы использовали тег без привязки ‹ion-textbox› в html-файле и должны были указать Ionic игнорировать его с помощью CUSTOM_ELEMENTS_SCHEMA. С этим трюком страница выглядит хорошо.

Заменить окно терминала графическим виджетом, представляющим ваши данные значимым образом, достаточно просто. Google Charts - отличный способ сделать это.

Пожалуйста, вилка

Продолжайте, разветвите это репо, измените и настройте его и будьте в обществе о своей реализации. Или в качестве пожертвования получите наше приложение Ionic Starter за небольшое пожертвование. Это дает вам полную среду Ionic для работы и разработки, и проверяется, что она компилируется.

Что дальше

Эта реализация использует только связь, ориентированную на соединение (GATT). Это один из способов связи нашего нового поколения продуктов Serial-to-Bluetooth с использованием BLE. Наша цель - предоставить продукты Bluetooth Mesh. Bluetooth Mesh - это широковещательный протокол, который не требует подключения GATT для получения данных. Фактически, когда нет соединения, эти устройства транслируют данные, полученные через последовательный порт, в сеть Bluetooth.

Консорциум Bluetooth Web работает над API сканирования, который расширяет сканирование для подключения до механизма типа сканирование данных. Это важно для Bluetooth Mesh. Все данные передаются с использованием стандартных рекламных пакетов BLE. Реализация пока недоступна в Chrome, но скоро появится. Так же и API рекламы, который позволяет Chrome передавать пакеты рекламы (протестируйте на Chrome OS как флаг разработчика).

В Native Bluetooth сканирование очень возможно для любого пакета, включая пакеты Bluetooth Mesh. Мы начнем реализовывать простое универсальное приложение, на данный момент родное, которое может сканировать пакеты Bluetooth Mesh, например последовательные данные с ваших весов, и отображать данные прямо на экране. Подключение не требуется. У нас есть пример, который уже доступен здесь.

Ресурсы

Ionic 3 Framework
Начало работы с Ionic: презентация

Открытый исходный код: SPP-over-GATT

Ionic Starter App: Bluetooth
AIRcable MiniMesh, оборудование последовательного интерфейса BLE
Протокол последовательной связи Bluetooth Mesh
Генерация последовательного оборудования AIRcable