- PVSM.RU - https://www.pvsm.ru -
В предыдущих сериях я:
Со временем накопилось понимание как устроены разные инкарнации умных домов, с точки зрения реализации сценариев и протоколов взаимодействия. С этим знанием я наделал устройств и реализовал для них "правильную" распределенную среду программирования для IoT с lisp-ом, криптографией и сборкой мусора. Под катом поведаю о ходе и результате процесса.
Xiaomi:
Home Assistant:
Главная проблема в централизованном подходе home assistant — имущественный ценз. При покупке умной розетки ~1000руб, для её работы с Home Assistant придётся докупить Raspberry PI ~4000руб, ведь Home Assistant надо на чем-то запускать. Такие натяжки бюджета резко охлаждают пыл желающих отведать умных домов и тормозит всю индустрию.
Через несколько абзацев выяснится, что устройства умного дома почти всегда оснащены совсем не детским CPU, силы которых хочется использовать, а не загонять в рамки "Я — начальник, ты — дурак" им. Home Assistant.
В то же время xiaomi реализовали правильный децентрализованный протокол, но зачем-то сузили возможности устройств ограничив их стрёмным, но развесистым json-based dsl (личное впечатление составлять тут [4]).
В голове созревало видение "правильной" среды для управления умным домом, но без реального приложения реализовывать протокол задумка пустая. Я изучал соседние протоколы zigbee/ble и контроллеры esp32/nrf51 и собирался с мыслями, разбирался и собирался снова…
Внезапно во мне самозародилась потребность измерять качество воздуха в окружающей среде.
У Xiaomi не нашлось измерителя CO2, ломать еще одного китайца, чтобы он заработал с home assistant не хотелось, а с прошлой серии во мне дребезжал гештальт, что неплохо бы научиться паять….
Следуя зову паяльника, я решил вручную, то есть самостоятельно, породить устройств для умного дома, а заодно ознакомиться с микроконтроллерами, arduino-ide (мимо меня прошло как-то), понять достаточно ли моих знаний физики, чтобы использовать мультиметр во благо, но без инструкции, а также потешить самолюбие реализацией "правильного" умного дома.
Под этим предлогом была зачата секретная лаборатория
Что хотелось создать в качестве Proof of concept:
Логи home-assistant при подключении к устройствам Xiaomi сдали их компонентную базу строчкой лога "chuangmi.plug.v3 1.3.0_92 ESP8266 detected". Разведка сообщила, что ESP8266 [5] — это дешевый (~100руб/шт) китайский микроконтроллер, нежно любимый и горячо поддерживаемый всеми и каждым. Этот чип умеет общаться без проводов по Wi-Fi, а с проводами по I2C/SPI/UART/GPIO. Также ESP8266 оснащен довольно мощным вычислительным ядром Xtensa 80/160Mhz 32-битный 112Кбайт памяти разработки калифорнийской компании Tensilica (там какая-то мутная история, tensilica была распущена в 2013, а esp8266 был замечен общественностью в августе 2014), а еще там есть 1Мб флеш памяти, которого по легенде должно хватать на всё.
Вот и прекрасно фокусируюсь на них. ESP8266 продается в модулях с разными формфакторами [6]. Для простоты ручной сборки взял модули esp201 [7] — они удобнее других тем, что уже распаяны на гребенку 2.54mm. В ожидании доставки вникаю в примеры кода arduino и даташиты…
В процессе прокачиваются навыки работы с паяльником и мультиметром…
Всплывает минус ESP8266. Xtensa и Wi-Fi очень прожорливы — настолько, что устройства делающие что-либо отличное от сна будут выжирать батарейку за недели в лучшем случае. Для батареечных устройств надо брать например nrf51 (~150руб/шт). Обидно досадно, но ладно. Будем втыкать устройства в розетку.
На просторах aliexpress нашлось несколько типов сенсоров CO2 (подробнее тут [8]). Мой выбор псевдослучайным образом пал на CCS811 (дрова тут [9]). Они оказались довольно дорогими (~500руб/шт) и прожорливыми, так как для замеров CO2 и TVOC сенсор содержит нагревательный элемент, подогревающий воздух перед анализом, греется он не мгновенно и ощутимо жрет энергию до 60мА, что практически исключает применение CCS811 в батареечных устройствах.
Для экрана подойдут LED модули 8x8 пикселей на max7219 [10] (~100руб/шт). Тоже нуждаются в обильном питании...
Чтобы эти модули были показательно независимы от всего кроме розетки купил блоков питания hlk-pm03 [11] (~200руб/шт). Это 4х-ногое устройство; две передние ноги которого суются в розетку 220v AC, а две задние подают 3.3v DC в цепь питания esp8266.
Сверху присыпать двумя щепотками резисторов, конденсаторов и кнопок. Канифоль и припой добавляем по вкусу. Припугивать паяльником до готовности (если интересна схемо-распаячная часть с мультиметром и бредбордами реквестуйте в каментах — опишу).
В результате вышеупомянутых изысканий народилось два устройства:
Так выглядит SensorPack в интерьере
А так Pixel на фоне бинокля:
В процессе сборки устройств были накостылены прошивки которые:
Это простые прошивки в 20-50 строк каждая. Их успешное выполнение доказывает работоспособность сборки и вменяемость драйверов.
Осталось создать прошивку, которая предоставит пользователю:
Основанный на udp протокол, используемый Xiaomi в их wi-fi устройствах, мне понравился своей простотой. Там сообщение — это один udp пакет, в ответ на такой пакет принимающая сторона должна кинуть на ip/порт источника пакета ответ — тоже udp пакет. Если ответа нет — перепосылка. Очень просто, понятно — берем как есть Исходников от xiaomi нет, но есть клиенты опенсорс реализаций (например такая [12]), воспроизводим по наитию, выкидывая непонятное и/или ненужное под лозунгом "Faster! Harder! Scooter!" "Меньше — лучше!".
В процессе для отладки зародились клиент и сервер для реализуемого протокола на python.
Сначала клиенты на python начинают общаться по реализуемому протоколу между собой, затем с устройством.
У Xiaomi-miio из открытых алгоритмов строится очень причудливая симметричная схема шифрования сообщений (детали тут [13]).
Выкидываем её за борт, берем aes128-cbc и реализуем следующий формат сообщений:
Аналогичная логика работы с ключом, IV и пакетами реализуется в python и на устройстве через arduino api.
Вот тут [14] для наглядности можно глянуть python реализацию
Текущая реализация использует IV, генерируемый случайным образом, поэтому подвержена replay attack. Чуть утешает, что xiaomi тоже подвержена replay attack, чем я активно пользовался :) Зачинится, если часть IV сделать монотонно возрастающим и хранить на устройствах последний IV для каждого устройства, с которым велось взаимодействие. Надеюсь такие финты ушами не нарушат криптографических заповедей...
К этому моменту у меня есть устройства, умеющие общаться со мной, посредством python-скриптов, и между собой, используя реализацию протокола в прошивке. Но сообщения эти никак не влияют на поведение устройств, бесцельно летают по воздуху туда-сюда. Что я хочу гонять в этих сообщениях? В устройствах довольно много FLOPSов и есть памяти чуть, а значит их можно использоваться как программируемые устройства, чтобы такие вещи как перевод из Цельсия в Фаренгейты выполнялись прямо на сенсоре, дальше больше. Так может они и скрип выполнить могут, чтобы на каждый чих прошивку не обновлять?! Форматировать строки, анимировать картинку на led матрице, вычислять медиану для n последних замеров — это всё можно и должно делаться на устройстве.
Первой мысль было взять JS его все знают. Но ESP8266 отказался выполнять JS, ибо вменяемых реализаций в дикой природе обнаружено не было. Зато нашелся Lua, да еще с готовой прошивкой NodeMCU для ESP8266. Подходит, заодно и lua попрактикую.
Реализовал протокол и шифрование уже на lua и всё было хорошо пока…
Пока не оказалось, что:
"Что проще всего реализовать?” — подумал я, и в голову пришел lisp. Уже засучив рукава и нависнув над клавиатурой, решил поискать, а нет ли уже ма-а-а-а-аленького lisp для esp8266, и он дан был мне в виде uLisp [15]. Взял его и c помощью его автора — многоуважаемого @technoblogy запилил прошивку которая:
В отличии от Lua прошивки, с ulisp я брал уже драйвера от arduino и заворачивал их в ulisp функции. Сам ulisp используется исключительно как клей, объединяющий высокоуровневые функции, реализованные на C++. Такой подход позволяет экономить память, сделать lisp программы более читабельными и использовать огромную базу драйверов от arduino.
В моей сети устройства адресуются так:
192.168.2.99 — IP адрес SensorBoard
192.168.2.174 — IP адрес Pixel
Как это работает в лабораторных условиях:
python tools/client.py --ip 192.168.2.99 --message '(+ 1 2)' --key YOUR_AES128_HEX_KEY
>> (+ 1 2)
<< 3
Для получения доступных возможностей устройства можно вызвать метод discovery. Он возвращает список специфичных для устройства функций, доступных на устройстве в дополнение к стандартным функциям ulisp.
python tools/client.py --ip 192.168.2.99 --message '(discovery)' --key YOUR_AES128_HEX_KEY
>> (discovery)
<< ("light-read" "co2-read" "tvoc-read" "humidity-read" "temperature-read")
Через эти функции читаем показания CCS811
python tools/client.py --ip 192.168.2.99 --message '(list (co2-read) (tvoc-read))' --key YOUR_AES128_HEX_KEY
>> (list (co2-read) (tvoc-read))
<< (840 67)
Вот такой сетевой REPL, но это слишком просто Еще у нас есть методы для прямого взаимодействия
python tools/client.py --ip 192.168.2.174 --message '(discovery)' --key YOUR_AES128_HEX_KEY
>> (discovery)
<< ("show" "request")
show — выводит на экран led матрицы бегущую строку
request — это метод, отправляющий сообщение другому устройству, используя его можно сделать инициатором сообщений, например вот так
# форматируем сообщение и отправляем его бегущей строкой на led матрицу на 30 секунд
(defun show_sensor (x)
(show
(format nil "CO2=~a TVOC=~a"
(first x)
(second x))
30000))
# раз в 33 секунды, запрашивает данные с сенсора и передает их в show_sensor
(periodic 33000
(quote
(request
"192.168.2.99"
54321
(quote (list
(co2-read)
(tvoc-read)))
'show_sensor)))
Загружаем эту программу в Pixel
$ python tools/client.py --ip 192.168.2.174 --mfile ulisp_scripts/red.ulisp --key YOUR_AES128_HEX_KEY
Наблюдаем как Pixel отрисовывает полученные с SensorPack показатели датчиков
Такая вот lisp среда позволяет работать с устройствами умного дома и реализовывать сценарии без центральной машины. И по заветам Raspberry PI — даёт пользователю возможность обучиться создавать доселе невиданное. По идее можно написать транслятор, берущий на вход автоматизации из-под Home Assistant и выплёвывающий lisp код. Это позволит избавиться от SPoF, но потребует довольно существенного вмешательства в устройство Home Assistant.
Интегрировать в Home Assistant такие устройства тоже несложно, пример тут [16]
PoC кода прошивки, скриптов, утилит и прочих артефактов производства тут [17]
Еще фото SensorPack с хвостом USB и антенной Wi-Fi
По ходу жизнедеятельности мне приходилось создавать базы данных, трансляторы, среды исполнения, dsl, но до сих пор не было случая применить lisp для пользы дела. Кажется здесь он вошел под правильным углом, предоставляя динамическую среду исполнения со сборщиком мусора и s-expression для кодирования структур (аналог json, но еще глубже вшиты в язык, любое выражение lisp — это s-expression [18]).
Пойду лепить более другие устройства на этом же протоколе, на очереди ESP32 и NRF51…
И параллельно допиливать прошивку до более продуктового состояния, если вдруг интересно присоединяйтесь!
P.S. Все нападки на Home Assistant выполнены с большой любовью, я там даже чуть комитер.
Автор: nestor_mahno
Источник [19]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/umny-j-dom/355492
Ссылки в тексте:
[1] ссылка на пост: https://habr.com/ru/post/496856/
[2] ссылка на пост: https://habr.com/ru/post/497880/
[3] ссылка на пост: https://habr.com/ru/post/503570/
[4] тут: https://github.com/rytilahti/python-miio/blob/fd563968baab5f4a1cca16566a2e79f169e9d08a/miio/gateway_scripts.py#L58-L90
[5] ESP8266: https://en.wikipedia.org/wiki/ESP8266
[6] модулях с разными формфакторами: http://wikihandbk.com/wiki/ESP8266:%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D0%B8#.D0.9C.D0.BE.D0.B4.D1.83.D0.BB.D0.B8
[7] esp201: http://wikihandbk.com/wiki/ESP8266:%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D0%B8/ESP-201
[8] подробнее тут: https://www.jaredwolff.com/finding-the-best-tvoc-sensor-ccs811-vs-bme680-vs-sgp30/
[9] дрова тут: https://github.com/adafruit/Adafruit_CCS811
[10] LED модули 8x8 пикселей на max7219: https://www.hackster.io/FilippoOnesti/esp8266-clock-using-max7219-led-matrix-display-b036c7
[11] hlk-pm03: http://www.hlktech.net/product_detail.php?ProId=59
[12] например такая: https://github.com/aholstenson/miio/tree/master/lib
[13] детали тут: https://github.com/rytilahti/python-miio/blob/master/miio/protocol.py
[14] Вот тут: https://github.com/bskaplou/iot_home_esp8266_POC/blob/master/tools/client.py#L21-L48
[15] uLisp: http://www.ulisp.com/
[16] тут: https://github.com/bskaplou/iot_home_esp8266_POC/tree/master/custom_components/hhg
[17] тут: https://github.com/bskaplou/iot_home_esp8266_POC
[18] s-expression: https://en.wikipedia.org/wiki/S-expression
[19] Источник: https://habr.com/ru/post/513128/?utm_source=habrahabr&utm_medium=rss&utm_campaign=513128
Нажмите здесь для печати.