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


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

Комментарии (24)


  1. bormental
    18.03.2016 22:44

    Осталось решить проблему с дистанционным наполением водой :)


    1. gshamshurin
      19.03.2016 07:45

      Подставку прикрутить к столешнице, сделать примитивный датчик наличия чайника на подставке + отдельный шланг от водяного фильтра + микроконтроллер + исполнительное устройство типа крана + весы в подставке (контролировать что вода наливается куда надо).


    1. bogdanov-s
      19.03.2016 17:29

      Mi Water Purifier умеет конектиться к смартфону — есть простор для эксперементов.


    1. invite_ciel
      19.03.2016 17:29

      Ещё неплохо бы решить проблему с автоматическим употреблением воды, тогда подобные устройства вообще можно было бы не трогать. :)


  1. DrPass
    19.03.2016 00:27
    -2

    По крайней мере, теперь понятно, для чего вообще эти чайники существуют, и кто их может купить ради этой функции. Скучающие от безделья программисты.


    1. Sablast
      19.03.2016 10:06
      +1

      Мой вариант использования такого чайника — двое малышей на искусственном вскармливании, когда они начинают нервничать ночью по телефону включается чайник на подогрев воды до 70 градусов (необходимо для наведения молочной смеси), пока доберешься до кухни вода уже готова =)


  1. mityada
    19.03.2016 10:06
    +1

    Чтобы не гадать по чаинкам, можно взять APK приложения (com.readyforsky) и декомпилировать его. Протоколы всех устройств Ready For Sky сразу будут как на ладони. Вот, например, ответ этого чайника на запрос состояния (команда 6): pastebin.com/rpJpqTzH. Также видны всякие интересные штуки вроде обновления прошивки.


    1. Calvrack
      19.03.2016 10:11

      Ух ты! Как здорово! Теперь все гораздо проще. Спасибо. Хотя, признаться честно, большая часть времени у меня ушла не на то чтобы понять что слать, а чтобы с помощью урезанного gatttool как-то это проделать.


  1. shachneff
    19.03.2016 10:06

    Спасибо за информацию про перехват BlueTooth, как раз прошлой ночью неуспешно реверсил apk мобильного приложения, которое управляет этой техникой. Я прикупил «умную розетку» и «умный трекер». Появилась идея сделать из «умной розетки» watchdog для домашнего сервера, чтобы перезагружать, если он завис, с домашнего роутера.


    1. loly_girl
      19.03.2016 10:44

      Круто, мне такое же нужно, чтобы перезагружать иногда зависающий роутер с домашнего сервера.


  1. hobbyte
    19.03.2016 10:47

    Благодарю за информацию, надо опробовать ваши наработки с их розеткой.
    3ю неделю неспешно ковыряюсь. Декомпелировал разные версии их приложения, но ничего не понял. Не програмист.
    Просмотр обмена bluetooth на мысли, так же, не навёл.
    В связи с моей неспособностью вникнуть в BLE протокол управления, возникла мысль сделать прокладку из RemixOS c Ready4Sky.GW в виртуалке и попробовать дёргать по http.


    1. hobbyte
      21.03.2016 18:47

      Благодарю, Calvrack, с розеткой работает: авторизация, вкл, выкл, определение состояния. Комада для включения отличается: 55: counter :03:aa.


      1. Calvrack
        21.03.2016 20:19

        Здорово что работает. Работает оно на мой взгляд чудом. потому что все задержки на глазок. Все-таки надо переписать это все на C/C++… но боюсь руки долго не дойдут.


    1. webself
      21.03.2016 19:34

      Подскажите, ваш экземпляр розетки тоже заметно шумит при работе? Или мне одному повезло..


      1. hobbyte
        22.03.2016 08:26

        Вблизи, до метра, слышно жужжание. Далее не слышу.


  1. hobbyte
    19.03.2016 10:59

    Если правильно помню, 0x000c — notification, 0100 — вкл.


    1. mityada
      19.03.2016 14:59

      Это Client Characteristic Configuration (https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml), младший бит включает оповещения (там little-endian, поэтому значение будет 0x0001).


  1. Raegdan
    19.03.2016 13:27
    +3

    Интересно, умеет ли данный чайник отвечать "418 я чайник" при попытке попросить у него кофе по протоколу HTCPCP? Если нет — производителю должно быть стыдно за несоблюдение стандарта аж от 1998 года!


    1. kovyl
      19.03.2016 22:02
      +1

      Зашел, чтобы спросить про 418.


      1. alexws54tk
        21.03.2016 10:00

        Вы тут не одиноки. (=


    1. alexws54tk
      21.03.2016 10:26

      Перечитал сведения о HTCPCP. Узнал, что HTCPCP/1.0 (RFC 2324) получил обновление в виде HTCPCP-TEA (RFC 7168) для полной поддержки чайников.


  1. heibert
    19.03.2016 21:31
    +2

    Так вот о чём была книжка «Linux для чайников»…


    1. bormental
      19.03.2016 22:56

      Тут, скорее, чайник для "линукса".


  1. vechnoe
    20.03.2016 12:21

    Отлично, теперь можно подключать к Emacs чтобы заваривать кофе не отрываясь от кода.