Хабрахабр

Умный дом в контейнерах (ioBroker + Zigbee в Docker)

Вступление

Некоторое время пользовался несколькими стандартными реле Sonoff, управляющими светом через Google Home Mini. Но в итоге захотелось большего. Стандартного функционала не хватает, решил постепенно делать систему на чем-то более гибком. Выбрал ioBroker.
Сначала, как водится, смотрел, выбирал, проверял кусочки функционала. Когда по отдельности основное нужное заработало, начал собирать воедино. И, естественно, столкнулся с проблемами.
Основные сложности:

  • Что именно выбрать? Ведь есть много способов реализовать задуманное. И даже в выбранном решении много вариантов…
  • Нет готовых инструкций, как собрать воедино именно выбранный мной набор решений и именно в моих конфигурациях.

Что я выбрал, почему, с какими сложностями столкнулся и как их решить, и пойдет речь.
Забегая вперед, опишу, как запускал ioBroker в докере на старом ноутбуке и прокидывал в него Zigbee, чтобы взаимодействовать с датчиками Xiaomi напрямую, без шлюза. Стандартные инструкции не привожу, только свои «шишки».

Так что буду благодарен за советы и исправления 🙂 Поскольку пока это не продуктив, вполне можно что-то менять.

Хотелки и ход моих мыслей

Были релюшки Sonoff (заведенные в eWeLink), какой-то удлинитель (Tuya SmartLife), Xiaomi gateway с несколькими датчиками (Mi Home), колонка Google Home Mini.
eWeLink и SmartLife нормально подцепились в Google Home, слушались голосовых команд типа «Включи свет над столом». Mi Home не завелся (в Google Home мало устройств Xiaomi поддерживается).
Поставил ioBroker, подцепился к Xiaomi Gateway, в принципе все заработало. Все красиво, скрипты проверил, пишутся (выбрал Node-Red), решил на этом все делать.

Поэтому меня несколько напрягло, что для ioBroker надо nodejs, какие-то npm, с которыми я раньше дела не имел. Однако я не профессиональный админ, могу разобраться, как готовое поставить, но тонкостей типа какие библиотеки и компоненты при этом куда ставятся не знаю (и глубоко вникать не хочу). я все запустил, но в душе остался страх, что оно хотя и работает, но я не понимаю как. Есть сложности с версиями (типа стандартным yum из репозитория ставится слишком старый nodejs и т.п.).
Ну т.е. А ведь помимо ioBroker я хотел и другие системы на ноут взгромоздить.
Поставлю, к примеру, апдейт на что-то, вроде заработает. И если, к примеру, при апгрейде что-то сломается, я не буду знать, как чинить. Придется откатывать бэкап на месяц назад. А через какое-то время окажется, что работает плохо. Причем бэкап не только этой системы, но и всех других, ибо я не понимаю до конца, где от какой системы исполняемые файлы, где конфигурационные, где сами данные…

Код в контейнере. Очень меня это напрягало, поэтому решил использовать Докер. Легко бэкапить.
Вышла новая версия? Данные отдельно, директория подмонтирована на хосте. Разные системы друг другу не мешают. Да хоть на другой виртуалке легко проверить, как новая версия контейнера с данными из этой директории заработает. Опять же, легко перенести на что-то другое (ioBroker в контейнере и на Synology работает, и на одноплатниках). Легко откатить бинарники какой-то системы назад. Красота!

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

Установка

Хостовая операционка не критична, скачал CentOS (по старой памяти помнил, что для всяких сетевых задач она вполне стабильно и безглючно работала). Актуальной оказалась версия Cent OS 8.
Поставил. Сделал базовые настройки типа имени хоста, fail2ban (просто привычка, хотя хост пока только в локалке). Поставил Docker. Останавливаться на этом не буду. Пример инструкции.

Но какую выбрать сеть? Пора запускать ioBroker. Но потом решил отказаться от этой затеи:
Host или Macvlan?
Сначала хотел Macvlan, чтобы каждый контейнер получил свой IP адрес от роутера.

  • При Host, конечно, нужно явно указывать, какие порты пробрасывать, следить, чтобы не пересекались с другими контейнерами. Но
  • iptables придется настраивать внутри каждого контейнера. В том числе после каждого перезапуска с другими параметрами, апгрейда/замены. А в режиме Host «единая точка управления безопасностью».
  • Я все-таки планирую делать его доступным не только из домашнего WiFi. И в таком случае удобнее сделать доступным извне один хост (и а-ля port-mapping на нем), чем настраивать это для нескольких.

В настоящий момент проверил ZeroTier One. Установил его только на хост. Обращение к IP адресу этого хоста (не локальному, а выданному ZeroTier) и порту 8082 с мобилки по GPRS при запущенном клиенте ZeroTier прекрасно открывает интерфейс vis).

Что-то пошло не так.
docker logs ioBroker показывает, что на последнем шаге отсутствует подключение к внешним ресурсам. Так что стандартно
docker run -d --name ioBroker -p 8081:8081 -p 8082:8082 -v /opt/iobroker/:/opt/iobroker/ --device=/dev/ttyACM0 --env-file /opt/ioBroker_env.list --restart=always buanet/iobroker:latest
Упс. Не получается разрезолвить имя.
docker exec -it ioBroker bash показывает, что ping по IP из него прекрасно проходит, а по имени нет.

Но ни telnet, ни curl в контейнере нет, проверить не могу. Гуглю, нахожу кучу ссылок про то, как докер неправильно подставляет DNS сервер, Правлю /etc/docker/daemon.json, разбираюсь с dnsmasq – ничего не помогает.
Закрадывается мысль, вдруг что-то блокируется на сетевом уровне. Можно, конечно, вручную указать нужные хосты в /etc/hosts, но это слишком трудоемко, лучше проверю другие версии. Установить тоже не просто – yum install не работает же.

Но нет.
Вспоминаю, что доступность порта еще можно проверить с помощью wget. Например, тупо стопаю firewalld на хосте в надежде, что все откроется. И не может ничего скачать даже по IP. И он есть в контейнере! Ну, значит точно проблема не в DNS, а в iptables. Даже к web интерфейсу домашнего роутера не может подключиться.

В итоге все заработало после добавления интерфейса докера в доверенную зону:
sudo firewall-cmd --permanent --zone=trusted --change-interface=docker0
sudo firewall-cmd --reload

Вот даже интересно, это я где-то проглядел в инструкциях?
Или взял бы не CentOS 8, а что-то другое, проблемы бы не было (в других OS не фаерволится по умолчанию)?
Или это настолько для всех очевидно, что в инструкциях не пишут, один я долго тупил?

Zigbee

Итак, мой ioBroker в контейнере, и у него опубликовано только несколько портов. Сейчас это админка 8081 и vis 8082, потом добавится mqtt 1883 и, возможно, что-то для поддержки Tuya (видел такой драйвер, но пока не разбирался).
Увы, для взаимодействия с устройствами Xiaomi через его шлюз нужны мультикасты, а с этим в такой конфигурации сложности. Поэтому решил прокинуть в контейнер USB stick. Тоже обычная операция.
В командной строке вы уже видели --device=/dev/ttyACM0 именно для этого. Устройство в контейнере появилось. В ioBroker активировал штатный драйвер «Zigbee для Xiaomi и других устройств», но он не заработал.

Захожу в контейнер, добавляю iobroker в эту группу – не помогает.
Вижу подсказки, что надо установить пакет serialport через npm.
Не могу, нет прав. Гугль подсказывает, что для доступа к serial порту нужно добавить пользователя в группу dialout. установка начинается, а потом аварийно завершается).
Наконец, до меня доходит, что надо в командной строке указать явно, в какую директрию ставить.
npm install -g serialport --production --save --prefix "/opt/iobroker"
Устанавливается, но не помогает. Гуглю дальше.
Bluefox собственной персоной кому-то подсказывает, что это нужно делать из директории /opt/iobroker/node_modules/iobroker.javascript/ — у меня нет такой, да и все равно нет прав на установку (ну т.е.

Проверяю (изнутри контейнера, конечно):
test -w /dev/ttyACM0 && echo success || echo failure
Success. Начинаю подозревать, что все-таки надо разбираться с правами доступа. все-таки Докер правильно устройство прокинул.
sudo -H -u iobroker test -w /dev/ttyACM0 && echo success || echo failure
Опаньки! Т.е. Несмотря на предварительное добавление его в группу dialout.
ls -l /dev/ttyACM0 выдает
crw-rw----. Failure
bash внутри контейнера запускается под рутом, А вот из под пользователя iobroker доступа к порту нет. Что еще за 18 вместо названия группы? 1 root 18 166, 0 Nov 3 18:14 /dev/ttyACM0

Ха!

1 root dialout 166, 0 Nov 3 15:15 /dev/ttyACM0
Оказывается, на основном хосте в /etc/group dialout:x:18, а в контейнере dialout:x:20
Хотя я в группу с таким названием и добавил пользователя, толку никакого, номер не тот. На основном хосте все правильно: crw-rw----. Так что создал еще группу с идентификатором 18, и добавил пользователя уже в нее:
groupadd -g 18 serial
usermod -a -G serial iobroker

И на этом мои разборки завершились 🙂
Спокойно отвязал все датчики от Xiaomi gateway, привязал к ioBroker. Перестартовал все для пущей уверенности.

Вижу их, как объекты в самом ioBroker:

Считываются показания в vis:

И картинка меняется:
При замыкании контактов на датчике протечки данные поступают.

Соответственно хоть email или еще что-то шлется, засылается голос или MP3 файл на колонку GH Mini:
И в Node-Red сигнал приходит.

Зеленым показываются последние изменения.
Flip90 поменялся – это понятно. Кстати, при просмотре объектов меня ждал сюрприз:

Это я повернул Xiaomi Cube на другую грань. Но, оказывается, есть еще flip90_from и flip90_to – с какой на какую грань он повернулся.
Получается, что от кубика по идее можно получить еще больше сигналов управления. Этот сигнал и ловится для управления. Например, если нарисовать стрелочки на гранях (как бы по кругу), можно отслеживать не просто «поворот на 90», но и в какую сторону (от себя или к себе, влево или вправо).

И для других жестов есть подобная дополнительная информация (Top side on flip 180°, Top side on slide, Top side on tap) Для flip180 так же работает.

Но в стандартном Mi Home информации о гранях не было. Не то, чтобы было позарез нужно. Раньше только про дополнительное действие fall (свободное падение) знал, которое было, но из Mi Home исключили (видимо, слишком часто роняли). Вроде и при прежнем подключении через Xiaomi Gateway тоже не видел, не знал, что у каждой грани есть номер.

Финал

Все, что мне нужно, работает. Дальше можно наводить красоту, писать скрипты, подключать Tuya, запускать контейнер с Blynk для других проектов…
И, возможно, что-то переделывать с учетом ваших комментариев 🙂

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть