В прошлой статье я рассказывал, как подружить колонку «Маруся» с Home Assistant через DIY Hooks: пишем руками YAML со списком устройств и HTTP-запросами, вставляем туда адрес Home Assistant и долгосрочный токен, заливаем через приложение «Маруся» на телефоне и дальше немножко шаманим, пока кнопка «Удалить» не превратится в кнопку «Выбрать». В конце я написал, что было бы неплохо иметь интеграцию, которая сама генерирует эти файлы и выкладывает их на vc.go.mail.ru, — тогда и статья была бы не нужна. Прошло четыре с лишним года, никто такую интеграцию не написал, поэтому пришлось самому. Статья, как видите, всё равно понадобилась, но теперь она про то, как поставить одну интеграцию и больше в приложение не заходить.

Что было не так

Пока колонка одна и устройств три, ручной YAML терпим. У меня колонок стало три: на кухне, в спальне и у сына. И тут выяснилось сразу несколько неприятных вещей. Каждая колонка живёт под своим аккаунтом VK — у кухонной свой владелец, у детской свой, — и у каждой должен быть свой набор устройств: детская управляет светом в детской, а не на кухне, и комната по умолчанию у каждой своя. Чтобы привязать конфигурацию, надо войти в приложение под аккаунтом колонки, а на одном телефоне это значит выйти, войти под другим, пошаманить с «Выбрать», выйти обратно. Любое новое устройство — снова по кругу: поправить YAML, загрузить, «Отключить сервис», подключить заново, выбрать. Токен Home Assistant при этом лежит открытым текстом в файле, который гуляет между компьютером, телефоном и облаком mail.ru. И ещё одно: соседняя интеграция yandex_smart_home умеет отдавать устройства в умный дом VK с полным протоколом, но она работает от одного аккаунта и без разных комнат по умолчанию на разных колонках, а мне нужно было именно это.

Что получилось

Интеграция Marusya DIY для Home Assistant, ставится через HACS. Она делает ровно то, что раньше делал человек с телефоном: собирает YAML с хуками, загружает его в кабинет DIY, отвязывает прежнюю конфигурацию, привязывает новую и нажимает «Выбрать». Человеку остаётся по разу войти в VK под каждым аккаунтом колонки и раз в год с небольшим дать интеграции сессию кабинета. Меняется список устройств — интеграция сама заливает новую версию и перепривязывает; не меняется — ничего не делает. Токен для хуков она заводит тоже сама: отдельного пользователя Home Assistant без прав администратора на каждый аккаунт колонки, так что в описании устройств никаких секретов нет, а удалишь запись — токен отзовётся.

Ограничения DIY Hooks никуда не делись: включить, выключить и спросить, включено ли. «Маруся, какая температура в спальне» по-прежнему не работает.

Установка

Как и раньше, Home Assistant должен быть доступен из интернета по https: хуки зовёт облако Маруси, а не колонка. Адрес интеграция берёт из «Настройки → Система → Сеть → Внешний адрес», или его можно задать в записи вручную.

Пока интеграция ждёт в очереди на включение в каталог HACS по умолчанию, её добавляют как пользовательский репозиторий: HACS → три точки → «Пользовательские репозитории» → адрес https://github.com/mpashka/hass-marusya, категория «Интеграция». Дальше находим «Marusya DIY», устанавливаем и перезапускаем Home Assistant.

HACS, страница Marusya DIY
HACS, страница Marusya DIY

Шаг первый: сессия кабинета

Кабинет DIY — это та самая страница vc.go.mail.ru/smarthouse/diy/, куда загружаются описания. Войти в него за человека интеграция не может: VK отдаёт кабинету код входа только на его собственный адрес, и обменять этот код может только браузер, в котором вы входили. Поэтому придётся один раз сходить в браузер: открываем кабинет, входим через VK, открываем инструменты разработчика (F12) → Application → Cookies → vc.go.mail.ru и копируем значение sh_data.

В Home Assistant: Настройки → Устройства и службы → «Добавить интеграцию» → Marusya DIY → «Сессия кабинета DIY» → вставляем. Живёт эта cookie около 13 месяцев; когда истечёт, на записи появится «Требуется повторная настройка», и проделать то же самое придётся ещё раз. Кабинет один на все колонки: как я писал в прошлый раз, аккаунт кабинета и аккаунт колонки не обязаны совпадать, и в одном кабинете спокойно лежат конфигурации для колонок разных людей.

Меню добавления интеграции
Меню добавления интеграции

Шаг второй: аккаунт колонки

Снова «Добавить интеграцию» → Marusya DIY → «Аккаунт колонки». Интеграция покажет ссылку входа в VK. Открываем её, входим под тем аккаунтом VK, к которому привязана колонка, и попадаем на пустую страницу oauth.vk.com/blank.html (или oauth.vk.ru/…) с длинным адресом. Этот адрес целиком копируем и вставляем в форму, а в поле «Название» пишем, как запись будет называться в Home Assistant, — удобно по комнате колонки. Всё.

Форма «Аккаунт колонки»
Форма «Аккаунт колонки»

Почему так криво, с копированием адреса? Честно пытался сделать красиво — чтобы VK сам вернул человека обратно в Home Assistant. Не выходит: вход идёт от имени приложения «Маруся», а VK для него принимает возврат только на свой blank.html. Встроить страницу входа во фрейм VK тоже не даёт, а своё приложение VK сервер Маруси не принимает — я проверил. Так что копирование адреса — это цена того, что вход вообще работает без телефона.

Если колонок несколько и они под разными аккаунтами — повторяем этот шаг для каждого аккаунта. Удобно делать это в разных профилях браузера или в окне инкогнито, чтобы VK не подставлял последний вход.

Шаг третий: устройства

На записи аккаунта нажимаем «Настроить». Устройства можно задать тремя способами, и колонка увидит их все вместе.

Самый простой — метка. Заводим в Home Assistant метку, например «Маруся: кухня», выбираем её в форме, и дальше колонка видит всё, на чём эта метка висит. Новое устройство добавляется там же, где с ним и так работаешь: открыл окно сущности, повесил метку — через пару секунд Маруся о нём знает, в настройки интеграции ходить не надо. Имя берётся у сущности, комната — из её зоны (или комната по умолчанию), тип — по домену: light — свет, switch — выключатель, розетка с классом outlet — розетка, climate — термостат, скрипты, сцены и кнопки — одно действие «включи». Сущность, которую Маруся не поймёт (датчик, например), интеграция не отдаёт и называет в атрибутах «Состояния DIY», чтобы не гадать, куда она делась.

Второй — просто выбрать сущности списком в той же форме, если метку заводить не хочется.

Третий — YAML, когда нужно задать имя или тип точно. Формат намеренно короче, чем YAML Маруси: адреса, заголовки и токены интеграция подставит сама. Если сущность описана в YAML, описание из YAML главнее того, что интеграция вывела бы сама.

- entity_id: light.bedroom
  name: Свет
  type: light
- entity_id: switch.bedroom_heater
  name: Обогреватель
  type: other
  room: Спальня
- entity_id: script.cat_feed
  name: Корм кота
  type: other
  service: script/turn_on

В YAML type — тип устройства Маруси без префикса devices.types. (список типов — в README репозитория). Без service устройство получает три хука: включить и выключить (turn_on и turn_off домена сущности) и прочитать состояние. С service — один хук, который просто вызывает указанную службу: так удобно запускать скрипты. При сохранении интеграция проверяет, что сущности существуют, типы допустимые, а идентификаторы не повторяются, и если что-то не так — говорит, у какого устройства и что именно.

Форма «Настроить»
Форма «Настроить»

Через несколько секунд сущность «Состояние DIY» на записи станет «Привязано», в её атрибутах будет список устройств, которые приняла Маруся. Говорим «Маруся, включи свет» — и в журнале Home Assistant видно, что свет включил пользователь «Marusya DIY: <аккаунт>». Если что-то сломалось, «Состояние DIY» покажет ошибку с причиной и шагом, на котором она случилась, а если отказала привязка новой конфигурации — интеграция вернёт прежнюю, так что колонка без умного дома не останется.

«Состояние DIY» — привязано
«Состояние DIY» — привязано

Если конфиги генерирует скрипт

У меня описания колонок генерирует ansible из реестра устройств, и руками в форму я их не вставляю. Форма «Настроить» — это обычный options flow, поэтому его можно пройти через REST API Home Assistant (нужен токен администратора):

GET  /api/config/config_entries/entry?domain=marusya_diy     → entry_id по title
POST /api/config/config_entries/options/flow                 {"handler": "<entry_id>"}
POST /api/config/config_entries/options/flow/<flow_id>       {"default_room": "Кухня", "devices": "<YAML>"}

Ответ create_entry — принято, запись перезагрузится и синхронизируется сама; form с errors — отказ с причиной. Метку и список форма принимает теми же ключами — label и entities. Одна тонкость: форма заменяет параметры записи целиком, так что скрипт, отдающий только devices, снимет метку, выбранную руками. У меня записями владеет только ansible, и мне это не мешает. Повторный прогон с тем же описанием ничего не трогает, так что его можно гонять хоть на каждом деплое.

Как это устроено

Сразу признаюсь: у меня самого на всё это времени не хватило бы, поэтому я активно использовал робота — ИИ-агента. Он скачал приложение «Маруся», разобрал его и записал протокол, сам гонял пробы против кабинета DIY и сервера Маруси, написал интеграцию и полсотни тестов к ней, перепривязал через неё все три мои колонки, оформил заявку в каталог HACS и даже снял скриншоты для этой статьи в браузере без окна, размыв на них лишнее. Моя часть — ставить задачи, входить в VK там, где нужен пароль, решать, как оно должно работать, и проверять голосом, что свет на кухне действительно включается.

Никакого официального API тут нет. Робот скачал приложение «Маруся» для Android, разобрал его jadx и посмотрел, как оно входит и что делает на экране умного дома. Оказалось, что сессию Маруси можно получить из токена VK приложения «Маруся» двумя запросами к серверу регистрации, а запросы ничем, кроме этой сессии, не подписаны. Экран умного дома в приложении — это мини-приложение VK, которое ходит в API умного дома Маруси; привязка DIY там устроена как обычный OAuth, где сервером авторизации выступает сам кабинет DIY, а знаменитая кнопка «Выбрать» — это просто форма с идентификатором конфигурации. Загрузка YAML — форма кабинета, в которую можно передать текст, а не файл. Дальше всё сложилось: интеграция отвязывает DIY от аккаунта, начинает привязку, подтверждает её от имени кабинета, выбирает нужную конфигурацию и удаляет прежнюю.

Отсюда же главный риск: протокол неофициальный. Разбиралась версия приложения 1.91.5; если mail.ru поменяет сервер, интеграция перестанет работать, пока её не поправят. Подробности разбора, схемы и сценарии лежат в docs/ репозитория — если у вас что-то сломалось, там же видно, где искать.

Итого

Три колонки на трёх аккаунтах VK, у каждой свои устройства и своя комната, конфигурации генерируются из того же места, что и всё остальное в доме, а телефон с приложением «Маруся» больше не нужен ни для чего, кроме музыки. Интеграция лежит на GitHub под лицензией Apache 2.0; баги и пожелания — туда же, в issues.

Удачной автоматизации.