Контроль забраслетом у ритмі BlueZ
Експерименти я розпочав з вивчення набору сервісів та характеристик, доступних через Bluetooth 4.0 (або Bluetooth Low Energy, далі – BLE). Щось неважко було знайти в мережі, і ця інформація мені дуже допомогла, але вона стосувалася попередньої версії без потрібного мені датчика. Тому я почав із BLE-сканера.
Натиснувши на “OPEN TAB” і потім “CONNECT”, отримав набір сервісів:
Ідентифікатор вимірювача пульсу виявився стандартним для таких пристроїв – 0x180D. Забігаючи наперед, скажу, що зрадів я рано.
Як ретранслятор я використовував Raspberry Pi (модель B) та BLE-usb-адаптер BT400 від ASUS. Також були потрібні BlueZ – справжній швейцарський ніж для роботи з Bluetooth під Linux та пара додаткових модулів для Python.
Для Raspberry Pi використовувався образ Raspbian. Після apt-get update та apt-get upgrade перевірив адаптер:
Відмінно, мій адаптер у першому рядку. Встановив BlueZ. Рекомендується завантажити останній архів коду, на момент підготовки статті це був BlueZ 5.37, розпакувати та скомпілювати. Я задовольнився версією 5.23, яка встановлюється через apt-get. Коригування установки можна перевірити, виконавши команду gatttool –help. Gatttool — інструмент BlueZ для роботи з GATT, загальним профілем атрибутів BLE пристроїв. У старих версіях gatttool за умовчанням не встановлювався, потрібно було «прикручувати» руками, але тут help був доступний і отже, маю майже все необхідне для роботи з браслетом. Через pip встановив Pexpect для роботи з BlueZ з Python. Перезавантажив Raspberry та ввімкнув адаптер. Статус адаптера перевірив командою hciconfig:
Прапор DOWN показав, що адаптер вимкнено, ввімкнув його командою: sudo hciconfig hci0 up
Перш ніж писати код для Raspberry, мені потрібно було переконатися, щовсі необхідні мені послуги (частота пульсу, рівень заряду акумулятора і вібродзвінок) доступні в термінальному режимі з BlueZ. Просканував BLE оточення і без проблем знайшов браслет:
Підключився до браслету командою connect, запустивши gatttool в інтерактивному режимі (ключ I):
З'єднання в інтерактивному режимі без спарювання зазвичай триває 20 секунд. Це так званий низький рівень секретності, він використовується за умовчанням. Список доступних сервісів виводиться командою primary:
Визначити, що за сервіс можна за чотирма цифрами після uuid. Вийшло два загальні сервіси (generic), два сервіси, задані виробником (fee0 і fee1), HRM сервіс (180d) та алертинг (1802). Перелік характеристик браслета виводиться командою char-desc у порядку зростання покажчиків (handles). Знайшов у списку характеристику з ідентифікатором ff0c: handle: 0x002c, uuid: 0000ff0c-0000-1000-8000-00805f9b34fb, Покажчик 0x002c для рівня заряду акуму. Спробував вважати дані командою char-read-hnd (прочитати дані за вказівником):
Другим «підкорився» вібродзвінок. За даними MCP я припустив, що це Immediate Alert, а Alert Level це команда, яку потрібно надіслати на ідентифікатор 0x2A06:
У списку характеристик цьому ідентифікатору відповідає рядок: handle: 0x0051, uuid: 00002a06-0000-1000-8000-00805f9b34fb Направив команду на покажчик 0x0051 зі значенням 0
Браслет відгукнувся двома слабкими дзижчаннями, значення 02 це двічі по 01, тобто. чотири сигнали, а 03 - два, але сильніших. З частотою пульсу виявилося значно складніше. MCP показав наступне:
Пов'язані з цим сервісом характеристики:
Нічого не вийшло, значення успішно записувалося, аленіяких повідомлень не надходило, браслет просто вимикався за кілька секунд. Запуск gatttool у консольному режимі з ключем – listen також не дав результатів, gatttool просто «зависав» в очікуванні. Загадка, одним словом.
Для прояснення ситуації довелося використовувати BLE-сніфер (на ноутбуці з Windows 8). В основі був перепрошитий BLE-usb-донгл на чіпі СС2540 від Texas Instruments та програма Smart Packet Sniffer того ж виробника. Все необхідне, включаючи програматор, можна легко знайти у вигляді набору для розробника, а програму і прошивку я вільно скачав з сайту TI.
Так виглядають пакети у сніффері в режимі презентації:
Тут видно, як значення 0100 записується в CCC з покажчиком 0x004C, дозволяючи повідомлення про частоту пульсу.
Під час аналізу пакетів вдалося з'ясувати таке:
- Щоразу при з'єднанні в браслет надсилаються всі дозволи повідомлень (CCC з ідентифікатором 2902)
- Далі відбувається передача інформації про користувача
- Потім, за вказівником 0x0028 записуються дата та час
- Після цього зчитуються дані про рівень заряду батареї та кількість пройдених за день кроків
- Перед тим як отримати повідомлення про частоту пульсу за вказівником 0x004E, відповідним характеристикою «точка контролю пульсу» записується послідовність 0x15 0x00 0x00 (припустимо, що це скидання)
- Потім туди записується 0x15 0x02 0x01, що в моєму випадку відповідає лівій руці
- Після цього, через 15-20 секунд, надходить повідомлення з частотою пульсу у двох байтах, наприклад 06 40. Другий байт і є частота пульсу в hex
Скрипт виводить рівень заряду батареї, відправляє повідомлення, чекає та друкує частоту пульсу. Загадка вирішена, залишилося навчитися відправляти дані в хмарний сервіс, як я вирішив використовувати Thingspeak. Це безкоштовний сервіс із простим API та готовою візуалізацією.
Налаштування Thingspeak зайняло не більше п'яти хвилин. Необхідно зареєструватися та увійти до персонального простору. Далі, створити новий канал, в налаштуваннях каналу вказати назву, кількість та мітки полів. Зберегти установки та перейти на вкладку API Keys. Там скопіювати API-ключ для запису (Write API Key):
Після цього – перейти на вкладку Private View (якщо при налаштуванні каналу не було вказано “Make Public”).
За відправку даних у Thingspeak відповідає ось така конструкція на Python:
У штатному режимі роботи в консоль виводиться номер надсилання даних, починаючи з одиниці. Радіус дії ретранслятора 3-4 метри у прямій видимості, що нормально для медичної палати. Однак, браслет на такій відстані легко екранується долонею.
Тестував систему, що вийшла, в процесі тренування на велотренажері, 20 хвилин. Інтервал між вимірюваннями – 3 хвилини, кількість вимірювань – 8. Браслет схильний завищувати частоту пульсу при нещільному контакті зі шкірою, для більшої точності помістив датчик із тильного боку зап'ястя. Результат на Thingspeak:
Як видно з графіка, 8 вимірів ніяк не вплинули на заряд акумулятора. Думаю, експеримент можна вважати цілком успішним і отриманий досвід використовуватиме проектування власного пристрою або, наприклад, пошукати ОЕМ.