Pull to refresh

Управляем чайником SkyKettle из GNU/Linux

Reading time 6 min
Views 30K

Вступительно


Довольно много даже и на Гиктаймс рекламируют технику компании 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 и общается чайник и смартфон.

Если просканировать и опросить чайник на предмет первичных сервисов, мы получим что-то вроде

     gatttool -b E7:5A:53:79:82:A4 -t random --primary

  • 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


Именно через последний сервис и будет вестись общение.
Теперь можно посмотреть все детальные возможности —

    gatttool -b E7:5A:53:79:82:A4 -t random --characteristics

  • 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, который в общении используется. Ну да ладно.

Итак, как же идет общение:
— смартфон устанавливает соединение с чайником
— прочитывает, как и я только что, возможности чайника.
— потом инициирует общение, записывая по 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 :01:aa
RECV: 55: counter :01:02:06:aa

Тут остается загадкой значение 4 и 5ого байтов.
Вскипятить и/или поддерживать

SEND: 55: counter :05:00:00:28:00:aa
SEND: 55: counter :05:00:00:00:00:aa - просто включить чайник.
SEND: 55: counter :05:01:00:5f:00:aa
RECV: 55: counter :05:01:aa // 01 status meens OK

Формат видимо такой:
55: counter :05:[надо ли поддерживать]:00: [температура поддержания] :00:aa

Не понятны мне пока 5, 7 байты запроса — ненулевыми я их не видел
Выключение

SEND: 55: counter :04:aa
RECV: 55: counter :04:01:aa // 01 status meens OK

Запросить состояние

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. Расковырять все детали протокола. Нет ли уязвимостей?

Где брать?


Ну и репозиторий сыренький — github.com/PimenovAlexander/r4s-bluetooth.
Там же и дампы которые можно посмотреть с помощью wireshark
Если у вас есть другие устройства R4S можно пробовать ломать и их. Если кто-то понимает в Bluetooth расскажите плиз откуда взялся этот 0x000с хендл.
Tags:
Hubs:
+14
Comments 29
Comments Comments 29

Articles