Наверное, каждый из нас задумывался о том, как было бы классно, если бы кондиционер сам включался, когда мы приходим домой. Однако для управления всеми устройствами либо используют готовое решение из облака, либо приходится заморачиваться с покупкой микрокомпьютера, чтобы умный дом не стал глупым без интернета :) Но нужен ли для этого микрокомпьютер, если наверняка в шкафу лежит запылившийся планшет или смартфон, который когда-то работал и с более требовательными приложениями?..
С чего всё началось?
Все истории, которые мне рассказывали, всегда начинались с умных ламп, поэтому добавлю и свою лепту в копилку.
Ситуация банальная: необходимо было выключать и включать свет в аквариуме согласно расписанию. Задачка тривиальная, которую я решил, сравнив розетки с механическими таймерами и умные розетки. Поскольку на тот момент разница в стоимости была несущественной, то выбор пал на умную розетку.
И всё классно, все работает от приложения (стандартная Tuya), есть настройка расписания… но:
Хочется добавить немного интеграции со смартфоном, например, включение света по будильнику или в стандартное время. И с этого момента появилось желание разнообразить себе вечера настройкой и конфигурированием системы автоматизации.
При перебоях с интернетом розетка сама себя не включит, да и сам факт, что ради расписания ей нужно сходить в сеть или получить команду оттуда, немного расстраивает. К тому же параноик внутри говорит, что это не так секьюрно, как решение, развёрнутое в локальной сети.
Устройство
Наверное, самое простое — это купить Raspberry Pi и дальше можно без ограничения фантазии творить, ибо руководств и различных пошаговых инструкций полно. Но, покопавшись в шкафу, я нашёл прекрасный планшет Samsung GT-P3110. Отличный кандидат на замену Raspberry, да ещё и экран с сенсорным вводом — можно совместить с панелью управления.
Характеристики планшета
Постоянная память | 8 ГБ |
Оперативная память | 1 ГБ |
Чипсет | Texas Instruments – OMAP 4430 |
Частота | 1 ГГц |
Последний официальный ROM | Android 4.1.1 |
Последний неофициальный ROM | Android 7.0.1 |
Осталось лишь узнать, можно ли каким-то образом запустить тот самый Linux, на основе которого работает Android, и добавить в него нужное ПО. И именно такую возможность предоставляет приложение Termux. Из критических ограничений: для работоспособности необходим минимум Android 5 (API 21), а последние версии вообще работают только с Android 7 (API 24). Первое, что приходит в голову в этой ситуации — неофициальные прошивки (со всеми вытекающими). И именно для этой модели последняя неофициальная версия ПО была тем самым Android 7. До последнего не верил, что мне может так повезти… и как выяснилось, был прав.
Обновлённая до этой версии ОС работала крайне медленно. Мне планшет напоминал чем-то ноутбук 2005 года, пытающийся работать на современной ОС: всегда после включения надо сходить попить чаёк минут 30, пока он запускается. Здесь всё было так же. Спустя 30 минут на планшете можно было не спеша настраивать все параметры, ни о каких выходах в браузер речи не шло, две вкладки — и отклик на нажатие составляет около 5 секунд. Но всё же Termux был установлен, а также добавлен доступ по SSH, с помощью которого работа пошла значительно быстрее.
Система автоматизации
Далее нужно выбрать систему автоматизации. Поиск выдаёт в большинстве случаев лишь одну систему — Home Assistant. Ради справедливости, я нашёл альтернативы в виде Domoticz и ioBrocker. И, честно говоря, не стал углубляться в подробности, поскольку взглянув на интерфейс всё стало понятно. Да, возможно, в ioBrocker более обширная поддержка редких датчиков и прочее, но все эти достоинства меркнут, когда речь заходит о просто приятном внешнем виде, на который вы будете обращать внимание больше всего при работе с системой.
Внешний вид HA, Domoticz, ioBrocker
Итак, решено, системой автоматизации будет Home Assistant (сокр. HA). Недолго думая, я попробовал найти на просторах сети первопроходцев, которые пытались подружить Home Assistant и Termux, поскольку я был уверен в том, что не могу быть первым гениусом, задумавшим использовать Android-устройство, а не Raspberry или любой другой микрокомпьютер. И оказался совершенно прав, нашлись целых два счастливчика, кто не постеснялся написать статью по установке в далёком 2020 году.
Какие возникли трудности и опасения:
все взаимодействия происходили с аппаратами на официальных прошивках, что гарантировало их полную работоспособность;
в одной статье говорилось о необходимости 16 Гб памяти устройства, что вдвое больше, чем на моём планшете;
документация морально устарела и пришлось проделать множество дополнительных действий.
Действия по установке HA в Termux
Минимальные требования:
Android 7.0 +.
Память 8 Гб (влезет и на 6, но совсем без плагинов).
Стальные нервы =)
Для начала установим всё необходимое окружение:
# Проверяем обновления
pkg update
apt-get update
pkg upgrade
Также рекомендую все манипуляции проделывать через SSH, либо подключить аппаратную клавиатуру. Для включения SSH нужно выполнить следующие команды (можно почитать в официальной документации):
pkg install openssh
passwd # Необходимо установить пароль, так как пароль по умолчанию неизвестен
Теперь можно запустить SSH командой sshd
, при подключении используем порт 8022.
# Установим все необходимы для работы библиотеки
pkg install python nano make rust libcrypt libffi libjpeg-turbo # Обязательные
pkg install mosquitto termux-api # Рекомендую
Далее очень рекомендую все манипуляции проделывать в виртуальном окружении Python, чтобы библиотеки и всё прочее от HA установилось корректно. Для этого:
# Создаём виртуальное окружение
python -m venv hass
# Активируем виртуальное окружение
source hass/bin/activate
# Если среда более не нужна - можно её деактивировать с помощью:
# deactivate
Активируем среду и запускаем установку HA:
pip install --upgrade pip # Обновляем менеджер пакетов
pip install wheel # Обязательная библиотека
# Некоторые константы перед установкой
export CARGO_BUILD_TARGET="$(rustc -Vv | grep "host" | awk '{print $2}')"
export CRYPTOGRAPHY_DONT_BUILD_RUST=1
pip install homeassistant # Устанавливаем HA
И было бы всё хорошо, но далее нас могут встретить различные ошибки при установке, которые абсолютно индивидуальны и зависят от устройства.
У меня появилась проблема с orjson==3.7.5
из-за ошибки установки maturin==0.12.20
, а также с установкой numpy. Последняя устанавливается в Termux специфичный образом, который описан у них в вики, а решить проблему с corjson помогло это обсуждение.
pkg install binutils # Доустанавливаем пакет
# Пытаемся поставить проблемные библиотеки
pip install maturin==0.12.20
MATHLIB=m pip install numpy
После успешной установки пакета homeassistant (которая заняла несколько часов) мы преодолели только половину пути. Теперь надо запустить HA и снова исправлять различные появляющиеся ошибки. Для этого используем запуск с подробными логами: hass -v
. Ошибки опять индивидуальны, и, к счастью, у меня они не возникли.
После того, как всё исправлено и Home Assistant запустился, мы можем войти в него и завести аккаунт. На этом этапе я столкнулся с ошибкой, связанной с часовым поясом, из-за которой регистрация всегда обрывалась. В качестве решения необходимо было установить пакетpip install tzdata
.
Итоговый скрипт по установке можно посмотреть здесь.
Мне стало интересно, почему так мало статей на эту тему, хотя, казалось бы, очевидное решение — взять старый смартфон или планшет и реализовать на нём функции управления умным домом. Бонусом получаем всевозможные наборы датчиков с устройства, а также стационарную панель управления.
Итак, спустя несколько вечеров и попыток запуска я смог подключиться к HA в локальной сети! Радости не было предела!
Настраиваем Home Assistant
По настройке НА настолько много статей, что я просто приведу перечень того, что было сделано:
Установил HACS для возможности установки пользовательских интеграций.
Добавил системный монитор (systemmonitor) для отслеживания параметров системы (особенно памяти).
Изучил установку устройств Tuya в локальный контур. Установил LocalTuya и настроил розетку.
Скачал на смартфон приложение HA и добавил его интеграцию в систему. Не забыл внутри приложения настроить, какую информацию необходимо передавать в систему (информация о будильниках выключена по умолчанию).
Настроил автоматизацию.
Ура! Наша задача выполнена, теперь есть розетка с синхронизацей по будильнику, и всё это в локальном контуре. Но… где датчики планшета? Этот вопрос поставил в тупик. Хочется узнавать заряд батареи, информацию о WiFi-соединении (особенно учитывая стабильность ОС). Я нашёл два решения:
Самое логичное — установить приложение на планшет и подключить его к самому себе, разрешив доступ ко всем необходимым датчикам, а также подключиться по WebSocket, что позволит мгновенно получать обновления.
У Termux есть прекрасное расширение Termux:API, которое предоставляет доступ к дополнительным возможностям устройства. О них вам лучше всего расскажет документация.
Конечно, хотя первый способ и был самым удобным, но он реализовывал не все функции, которые есть в Termux:API, да и по опыту использования обнаружилась нестабильность работы из-за прошивки устройства (вот здесь она и подвела). Поэтому решил использовать оба способа вместе.
Подключаем Termux:API к Home Assistant. Простое решение
Для начала составим план, что мы хотим добавить:
Получение информации о батарее устройства с помощью команды
termux-battery-status
.Получение информации о WiFi-соединении устройства с помощью команды
termux-wifi-connectioninfo
.
Для начала я подумал, что раз есть пошаговые инструкции о том, как подружить Termux и HA, то наверняка есть и инструкции по работе с Termux:API и HA. Поиск не дал каких-то конкретных результатов, после чего я наивно пошёл посмотреть интеграции в HACS, где тоже ничего не нашёл.
Тогда я решил просмотреть документацию HA, где можно найти добавление новых компонентов. Меня интересовал компонент command_line, с помощью которого и реализовал задуманную функциональность.
Для начала возьмём ответ команды termux-battery-status
:
{
"health": "GOOD",
"percentage": 76,
"plugged": "PLUGGED_AC",
"status": "CHARGING",
"temperature": 32.900001525878906,
"current": -9223372036854775808
}
При реализации компонентов возникают следующие проблемы:
На входе получаем JSON, но в документации компонента нет ни слова, как его распарсить.
Мы получаем с нескольких датчиков информацию о батарее, которую нужно записать на разные платформы. Было бы очень расточительно вызывать эту функцию несколько раз, и поэтому нужна какая-то единая сущность для обновления.
Исходя из документации, необходимо перечислять все датчики в файле
configuration.yaml
, и при этом сортировать их по платформам, что неудобно, так как потом теряешься между зависимыми компонентами.
О решении проблем по порядку:
Оказывается, есть переменная
json_attributes
, в которой можно перечислить все имена наших JSON-полей. Данные будут храниться в атрибутах сенсора, который одновременно решит и вторую проблему с множественными вызовами. Но теперь появляется новая: как забрать значение атрибута?Чтобы забрать значение атрибута, при указании значения нужно вызывать функцию
state_attr('sensor name', 'attr name')
, в которой необходимо указать датчик, из которого мы пытаемся взять атрибут, а также имя атрибута.Последнюю проблему можно решить, добавив в файл конфигурации параметр, который указывает папку, где хранятся все ваши дополнительные конфигурации (я назвал её как и компонент —
packages
):
homeassistant:
packages: !include_dir_merge_named packages/
После этого вы можете создавать внутри объявленной папки YAML-файлы с вашими датчиками, но не забывайте в первой строке объявить название:
# Файл packages/battery.yaml
battery:
binary_sensor:
# ...
sensor:
# ...
С получением информации о WiFi всё аналогично. Итоговые файлы всех реализаций вы можете посмотреть в Github (включая файл конфигурации, если с ним возникли трудности).
После реализации базовых компонентов я добавил взаимодействие с Text-To-Speech для озвучивания некоторых событий. В HA есть встроенный TTS от Google, с которым первым делом поэкспериментировал и сделал выводы:
Для работы требуется доступ в Интернет, да ещё и очень стабильный.
Кеширует все записи в папке TTS, но не может их переиспользовать (а мы помним про память).
Низкое качество озвучивания.
В то же время, команды Termux:API предоставляли доступ к системным TTS, которые можно установить или использовать существующие. Для этого необходимо было добавить действие с помощью компонента shell_command, а также поля ввода текста, который нужно произнести.
Начнём с системного. Для просмотра всех предустановленных TTS я использовал команду termux-tts-engines
. В текущей ОС был предустановлен единственный движок: PicoTTS. При попытке воспроизвести любой текст Termux:API зависал и не реагировал в дальнейшем ни на одну команду, после чего был сразу отключён на уровне системы. И появилась необходимость установить любой другой, который мог бы работать без сетевого соединения. Поискав и посмотрев примеры озвучивания, я установил RHVoice, у которого небольшой размер и приемлемое качество произношения коротких фраз. Далее осталось всего лишь настроить компонент и автоматизации. Готово!
Но спустя пару дней опытным путем обнаружился недостаток: событие может произойти поздней ночью и разбудить всех. И если автоматизацию можно настроить на определённое время, то вот события ОС — нельзя; а поскольку громкость всегда максимальна, с её помощью проблему не решить. Так возникла задача регулировки громкости устройства с помощью HA, для чего у нас есть команда termux-volume
. И именно здесь у нас заканчиваются возможности работы со стандартным взаимодействием, поскольку HA не поддерживает работу с массивом, с помощью которого можно получить актуальную громкость устройства. Точнее, поддерживает только для установления значения, но не записи в атрибуты, чтобы можно было воспользоваться хаком, применённым для получения информации о состоянии батареи.
Настало время разобраться, как писать свои плагины, в частности для Termux:API.
Подключаем Termux:API к Home Assistant. Пишем интеграцию
И вот здесь начинается самая интересная часть — взгляд мобильного разработчика на Python-разработку интеграции для HA. Статей по разработке своих интеграций множество, и в том числе на Хабре. Если вы не знаете, как устроена стандартная разработка, то предлагаю прочитать предложенную ссылку, поскольку ничего нового я добавить не смогу.
Разберём каждый элемент отдельно:
API: обычно один огромный файл, в котором происходит взаимодействие с «внешним миром».
Coordinator: компонент для того, чтобы с помощью одного API-запроса получить данные для нескольких компонентов. То есть некое хранилище, которое также управляет обновлением набора привязанных к нему датчиков, не вызывая лишний раз запрос на обновление. Этому элементу посвящена всего лишь одна глава раздела документации, и я подозреваю, что именно поэтому новички не пользуются этой функциональностью, хотя добавить её совсем не трудно.
Platform: это заранее известный файл интеграции, в котором HA вызывает основные методы инициализации компонентов. Файлы должны быть точно такого же названия, как в перечислении из исходного кода.
Что не так в стандартной архитектуре решения?
Вся ответственность за выполнение команд и обработку ошибок ложиться на слой API. По сути, API становится God-object, который нужен всем для нормальной работы.
Опять мы видим разделение по платформам, а не по их логическим сущностям (например, в
sensors
у меня может быть информации и о сети, и о батарее).Необходимо в API и Coordinator дублировать данные со всеми вытекающими.
И все эти проблемы можно решить, добавив немного архитектуры из разработки Android-приложений:
Разделим ответственность не по платформам системы, а по сущностям (entities). Каждая сущность будет представлять любой компонент системы HA. Внутри себя сущность не хранит никаких дополнительных данных.
Все данные хранятся в Coordinator'е, который может общаться уже с API. Именно он обеспечивает единое состояние данных для каждого датчика.
API всё также общается с внешним источником и автоматически преобразует данные в нужные объекты. Также API обрабатывает некорректные запросы, например, таймаут или ошибки.
Также стоит прояснить некоторые особенности работы с HA:
Поскольку платформ у одной сущности может быть нескольких типов, то каждую такую группу необходимо инициализировать с помощью заранее известной функции, например,
async_setup_<component type>_entitites
. Тем самым реализация инициализации будет лежать в том месте, где идёт работа с этими датчиками.Для корректной работы при инициализации интеграции необходимо сохранить как объект API, так и все Coordinator'ы, таким образом они будут представлены в виде единой реализации.
Как можно заметить, изменилось совсем немного, просто немного упорядочили и привели в порядок связи. Но такие небольшие (и вроде бы очевидные) изменения очень сильно помогли в дальнейшем не путаться в связях между слоями и легче отлаживать, уменьшили количество ошибок при разработке.
Итоговый код можно посмотреть здесь и интегрировать его к себе.
Результат
Наша простая задачка превратилась в интереснейший путь изучения HA для работы на Android-устройстве:
Установили HA в Termux.
Написали YAML-конфигурацию для подключения базовых сведений об Android-устройстве и изучили работу с TTS.
Написали интеграцию, которая позволяет сделать всё, что описано в YAML, но:
Динамически менять иконки для наглядности.
Сделать рабочей кнопку обновления сенсоров (в любой момент получить актуальные данные).
Добавить возможность получения фотографий с камеры устройства и всего того, что недоступно с помощью YAML.
Что дальше?
Пока реализована лишь основа, которую отлично можно и нужно развивать, а именно:
Перенести все остальные возможности Termux в HA.
Добавить возможность подключать Zigbee-стик через OTG-кабель, чтобы добиться независимости датчиков от электричества (поскольку не будет привязки к энергозависимому хабу). Для этого требуется подменить стандартные команды к USB через
termux-usb
.Добавить возможность подключения удалённых устройств к Termux.
Это не говоря о таких мелочах, как публикация в HACS.