Управляем чайником SkyKettle из GNU/Linux
Довольно много даже и на Гиктаймс рекламируют технику компании Redmond которая поддерживает технологию R4S — Ready For Sky.
Все бы ничего, но техника эта управляется по Bluetooth со смартфона. И больше никак. Есть, говорят, вариант с каким-то шлюзом и управлением из облака… но выставлять мой любимый чайник наружу — никакой радости.
Ситуация складывается странная. С одной стороны Ready For Sky состоит в консорциуме — allseenalliance, который, вроде бы, какой-то опенсорсный. С другой — ни фрагмента кода, ни строчки документации на протокол своего чайника я не видел. Я подозреваю что внутри что-то вроде чипа NORDIC SEMICONDUCTOR — и возможно надо читать доку на него.
Любой кто покупает технику с закрытыми протоколами совершает насилие над будущим.
Эта статья описывает первый шаг в управлении чайником в GNU/Linux — возможности включать и выключать его из консоли (с оговорками). Это важно потому, что если вам хочется чаю — вы не отрывая рук от клавиатуры ставите его кипятиться. Потом идете его пить. До этого — надо было искать смартфон и клацать в него пальцами — тут уж проще до чайника дойти. Еще один плюс — мультиплексирование доступа — пока можно держать только один смартфон подключенным к чайнику, а результаты консольного запроса можно транслировать в много мест.
Расширить этот подход до небольшого веб-приложения я думаю сможет каждый.
Как получить данные обменаНачиная с андроида 4.4 кажется, в девелоперском меню появилась опция — Settings->Developer Options->Enable Bluetooth HCI snoop log (По умолчанию девелоперское меню скрыто). При включенной опции — всё общение телефона по Bluetooth логгируется в файл btsnoop_hci.log (имя файла в памяти телефона может отличаться в зависимости от настроек). Далее этот лог можно скопировать на PC и там проанализировать с помощью wireshark. Тот удобно и аккуратно показывает весь обмен, раскрывая и распаковывая пакеты. Сценарий, таким образом, тривиален — работаем с чайником из штатного приложения, сохраняем лог, анализируем. Далее стоит задача — повторить обмен своими средствами, выдавая себя за телефон.
Что представляет из себя протокол обменаЯ не большой спец по Bluetooth, но устройства Bluetooth Low Energy имеют несколько протоколов поверх собственно соединения — одним из них является протокол GATT/BT ATT — en.wikipedia.org/wiki/List_of_Bluetooth_protocols#Low_Energy_Attribute_Protocol_.28ATT.29, он в свою очередь надстроен поверх протокола L2CAP. Именно по BT ATT и общается чайник и смартфон.
Если просканировать и опросить чайник на предмет первичных сервисов, мы получим что-то вроде
- attr handle = 0x0001, end grp handle = 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb Generic Access
- attr handle = 0x0008, end grp handle = 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb Generic Attribute
- attr handle = 0x0009, end grp handle = 0xffff uuid: 6e400001-b5a3-f393-e0a9-e50e24dcca9e UART Service
Именно через последний сервис и будет вестись общение. Теперь можно посмотреть все детальные возможности —
- handle = 0x0002, char properties = 0x0a, char value handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb read write
- handle = 0x0004, char properties = 0x02, char value handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb read
- handle = 0x0006, char properties = 0x02, char value handle = 0x0007, uuid = 00002a04-0000-1000-8000-00805f9b34fb read
- handle = 0x000a, char properties = 0x10, char value handle = 0x000b, uuid = 6e400003-b5a3-f393-e0a9-e50e24dcca9e notify read
- handle = 0x000d, char properties = 0x0c, char value handle = 0x000e, uuid = 6e400002-b5a3-f393-e0a9-e50e24dcca9e write
Итак, как же идет общение: — смартфон устанавливает соединение с чайником — прочитывает, как и я только что, возможности чайника. — потом инициирует общение, записывая по handle 0x000c (которого как будто при опросе и нет) значение 0x0100 — далее шлет чайнику команды по собственному протоколу (а может это протокол от NORDIC), и периодически опрашивает его состояние — все это поверх UART Service>ATT>BLE
Как этим управлять?Вопрос естественным образом разделяется на аппаратную и программную составляющую. C первой все не сложно — я купил первый попавшийся донгл на ALI и он заработал — ru.aliexpress.com/item/Bluetooth-4-0-Dongles-Mini-USB-2-0-3-0-Bluetooth-Dongle-Adapters-Dual-Mode-adapter/32292553074.html
С программной частью гораздо сложнее. Собственно под GNU/Linux у нас нет выбора — BlueZ. И с этим есть проблемы. Если я верно понимаю — типичный способ работы с BlueZ это обращение через DBUS. С/С++/Phyton биндинги, вроде и есть, но не для BT ATT протокола. Зато для него есть инструмент командной строки gatttool.
Казалось бы- это хорошо — инструмент опенсорсный, и можно посмотреть как он работает — code.metager.de/source/xref/linux/bluetooth/bluez/attrib. Но толку с исходников мало — он легко не отделяется от bluez и glib. Добивать и собрать его отдельно мне стало лень. А некие коррективы внести хотелось бы. Gatttool имеет инверсию абстракции — он прячет от пользователя установление соединения в «не интерактивном» режиме, и не поддается разумной автоматизации в «интерактивном». Более того с документацией в blueZ все очень плохо.
Чайник очень быстро разрывает соединение — в пределах секунды. А протокол требует сразу после переконнекта послать 0x0100 на хендл 0x000e — таким образом у нас остается два выбора — 1. Пытаться обернуть интерактивный режим gatttool и обращаться к нему — работающему в фоне через bash или python. 2. Посылать 0x0100 на хендл 0x000e всегда. В надежде что оно что-то там внутри включает, и это что-то не включится повторно лишний раз.
Первый подход я не осилил, хотя очень пытался, дело в том что gatttool использует для вывода не чистый stdout, а GNU Readline Library, и задача обертки по сложности сравнялась с задачей пересборки. Потому пошел вторым путем.
Итак возвращаясь к протоколу общения.Настало время нырнуть в дебри. Первым делом для управления чайника надо авторизоваться. Смартфон для этого выбирает ключ и шлет последовательно посылки на хендл 0x000e и получает ответы с хендла 0x000b
SEND 55:00:ff: [8 байт ключа] :aa RECV: 55:00:ff:00:aa SEND 55:01:ff: [8 байт ключа] :aa RECV: 55:01:ff:00:aa SEND 55:02:ff: [8 байт ключа] :aa RECV: 55:02:ff:00:aa
Из этого нехитрого обмена видно, что сообщения на хендл нумеруются и ответы приходят с тем же номером — для удобства идентификации. Каждый обмен начинается с 0x55 и кончается на 0xAA (полосатые числа). Обычно 3ий байт ответа повторяет номер команды.
Теперь надо дойти до чайника и нажать на нем кнопку "+" на 10 секунд. Так же как делали это со смартфоном. При этом вывод поменяется на SEND: 55:1e:ff: [8 байт ключа] :aa RECV: 55:1e:ff: 01 :aa Теперь так будет всегда при этом запросе. Ключ запомнен. Что за команды использует смартфон после авторизации?
Посылка сразу после включения — смысл не ясен до конца Вскипятить и/или поддерживать Выключение Запросить состояниеSEND: 55: counter :06:aa RECV: 55: counter :06:00:00:00:00:00:0c:00:00:00:00:51:00:00:00:00:00:aa - kettle is on in boiling RECV: 55: counter :06:00:00:28:00:00:0c:00:01:02:00:33:00:00:00:00:00:aa - kettle is on RECV: 55: counter :06:00:00:00:00:00:0c:00:00:00:00:3e:00:00:00:00:00:aa - kettle is off RECV: 55: counter :06 00 00 28 00 00 0c 00 01 00 00 64 00 00 00 00 00 aa RECV: 55: counter :06 01 00 28 00 00 0c 00 01 02 00 64 00 00 00 00 00 aa - kettle finished boiling RECV: 55: counter :06 01 00 28 00 00 0c 00 01 02 00 63 00 00 00 00 00 aa - a while after finished boiling
общий вид: 55: counter :06: keep warm? :00: keepwarm temp? :00:00:0c:00:01: heater? :00: temp :00:00:00:00:00:aa
heater - нет полной уверенности, но состояние где-то в районе 10-12ого байтов. - 0x00 - off - 0x02 - on temp - градусы Цельсия текущей температуры (в чайнике) keepwarm temp - градусы Цельсия температуры, которую надо поддерживать Большинство байт кроме температуры мне пока не понятно. Должен быть, наверное, датчик пустоты чайника.
Как этим пользоваться— поставить себе на GNU/Linux bluez и проверить что у вас есть gatttool — он должен идти в комплекте. — узнать MAC своего чайника вызвав bt-device -l — скачать скрипт из репозитория ниже — выполнить одну из следующих команд (возможно вам надо иметь права писать в bluetooth) (если еще не сделано — авторизовать приложение нажав "+" на чайнике.)
./connect.sh [KETTLE MAC] auth — просто ждет авторизации ./connect.sh [KETTLE MAC] query — запросить статус в цикле ./connect.sh [KETTLE MAC] queryone — запросить статус один раз ./connect.sh [KETTLE MAC] keeptemp — включить в режиме- вскипятить и поддерживать ./connect.sh [KETTLE MAC] on — включить ./connect.sh [KETTLE MAC] off — выключить
— помните что только одно устройство может контролировать чайник в каждый момент времени — если у вас запущено и активно приложение на смартфоне — ничего работать не будет.
Остаются проблемы1. Не понятно когда происходит деавторизация. Очевидно не по реконнекту. Возможно по исчерпанию 255 запросов счетчика. 2. Код на bash завязан на задержи и возможны всякие гонки. Это ужасно. Надо все-таки выпотрошить gatttool и сделать аккуратную реализацию. 3. Возможно надо раскурочить чайник понять какого цвета у него потроха и что можно еще делать с ним по BT? может перешить и добавить туда что-то полезное? 4. Я вас всех авторизую жестко прописанным ключом… и потом смогу всеми вашими чайниками управлять, если вы мой сосед. Это все тоже надо поправить. 5. Расковырять все детали протокола. Нет ли уязвимостей?