Root на Яндекс Станции без вскрытия: свой LLM в колонке

Помните волну экспериментов с перепрошивкой Android TV — лаунчеры, деинсталляция лишнего софта, root? Кажется, очередь дошла до умных колонок. У меня под рукой оказалось три Яндекс Станции трёх поколений, и идея простая: сохранить привычные возможности Алисы, но научить колонку выполнять команды умного дома через собственный мост и LLM. Корпуса вскрывать не пришлось.
Контекст: три подопытных
| Колонка | Модель | Платформа | Особенность |
|---|---|---|---|
| Станция Лайт 1 | YNDX-00025 | yandexmicro, Amlogic AXG | уже была на стенде с прошлых серий |
| Станция Миди | YNDX-00054 | cucumber | root берётся прямо с factory-образа, без даунгрейда |
| Станция Мини 1 (2019) | YNDX-0004 | yandexmini, Amlogic A113X | RAM 236 МБ, NAND 256 МБ — главный герой дня |
Целевая архитектура: на колонке работает Quasar Bridge — форк quasar-bridge на Go. Он перехватывает голосовой WebSocket колонки, запросы по умному дому обрабатывает локально через LLM и Home Assistant (по MCP — Model Context Protocol, протоколу подключения инструментов), а музыку и погоду честно проксирует в Яндекс. ASR и синтез речи остаются облачными — их трогать незачем.
Исходная проблема
Прошивки Яндекса, выпущенные после 21 октября 2026 года, перестали принимать подменный сертификат стенда. То есть проверенный путь «поднял DNS-сервер — получил ADB» для свежих версий закрыт. Нужно было вернуть доверие устройства, не вскрывая корпус.
Требования к решению:
- root без разборки и пайки;
- Алиса остаётся Алисой: музыка, погода, ответы — как раньше;
- голосовые команды умного дома идут через мой LLM, а не через облачный сценарий;
- доступ закрепляется: переживает OTA и перезагрузки.
Почему DNS, а не USB
Для Мини 1 существует USB-путь (TPL-загрузчик Amlogic), и я честно начал с него: поставил инструменты, поднял виртуальную машину с x86_64 — и обнаружил, что Mac вообще не видит устройство. Ни нативно, ни в виртуалке с пробросом USB.
Копать дальше (кабель? порт? ревизия платы?) не стал: причина так и не установлена, это честно фиксирую как неразобранную ветку. DNS-метод быстрее и уже оплачен инфраструктурой.
| Путь | Плюсы | Минусы |
|---|---|---|
| USB-root (TPL) | не нужна сеть и стенд | Mac не видит устройство; диагностика кабелей — отдельный квест |
| DNS-подмена + откат | отлажено на двух колонках, без вскрытия | нужен стенд и factory-образ |
| Пайка UART | универсально | корпус, гарантия, руки |
Стенд и factory-образ как тайм-капсула доверия
Стенд — самописный DNS/HTTPS-сервер из арсенала сообщества
hackalice.me. Он подменяет три домена
(quasar.yandex.net, quasar.yandex.ru, scbh.yandex.net), отдаёт настоящий
ответ Яндекса с одной инъекцией — включённым сетевым ADB, — и умеет раздавать
прошивки для отката. Всё остальное форвардится в реальный интернет.
Ключевая мысль: заводской (recovery) образ старый — 2019 года — и он по-прежнему доверяет подменному серверу. Поэтому цепочка универсальна:
- сброс колонки (питание → зажать кнопку микрофона → питание → ~5 секунд до жёлтой подсветки) грузит factory-образ 2019 года;
- factory доверяет стенду, стенд предлагает откат на целевую прошивку;
- колонка скачивает 56 МБ образа, ставит его и приходит на
get_sync_infoуже с включённымadbd.
Установщик прошивок при этом отказался принимать файл: он ждёт сигнатуру PK/070701, а образ Мини — xz-сжатый cpio. Доверие восстановили контрольной суммой: crc32 совпал с официальным metadata.json, файл положили руками.
[OTA-AUTO] у колонки 1.3.4.12.532420178.20191021, у нас
1.305.4.16.3237824040.20250721 — отдаю манифест прошивки
>>> [OTA] файл отдан ПОЛНОСТЬЮ (56040760 б) <<<
Root подтверждён:
$ adb connect 192.0.2.18:5555
$ adb shell id
uid=0(root) gid=0(root)
От сброса до root — минут пятнадцать.
Грабли по дороге
Каждая — проверена на живом железе и стоила времени.
Привязка через приложение. Приложение «Дом с Алисой» требует Wi-Fi на телефоне, но его запросы к подменённым доменам умирают по TLS — вечный спиннер. Лечение: телефон в ту же сеть и вручную прописанный DNS 1.1.1.1. Тонкость iOS: ручной DNS применяется не сразу, помогает переподключение Wi-Fi.
busybox без gzip. tar -z на колонке отвечает invalid option -- 'z'.
Распаковка пакетов — только через zcat | tar -xf -. А env не умеет -u:
обёртки пакетного менеджера делают unset LD_LIBRARY_PATH вместо этого.
Read-only rootfs. Любые правки /etc начинаются с
mount -o remount,rw /.
Hostname в роутере. MikroTik не показывал имя колонки, потому что dhcpcd
шлёт FQDN-опцию вместо option 12. В /etc/dhcpcd.conf — hostname <имя> плюс
fqdn disable, затем dhcpcd -n wlan0.
Детектив про OTA-цикл
Через какое-то время после перевода Мини на домашнюю сеть она начала мигать синим каждые секунд десять. Лог объяснил: колонка скачивала свежую прошивку (52 МБ), установка падала на подменённом ключе подписи — и цикл повторялся.
[updates] Downloading …/1.373.4.16.4829693628.20261104.zip …
[updates] Update is allowed by backend
[updates] Executing OTA script ...
Штатный блокировщик обновлений здесь бессилен: он вырезает updatesd, а на
прошивке 1.305 updatesd поднимается через updater_switcher из launch.json —
задачу, о которой скрипт не знает. Удаление скачанного образа тоже не спасает:
колонка просто качает заново.
Лечение — убрать задачу updater_switcher из launch.json, убить процессы,
снести /bkupgrade/update_*.img и перезагрузиться. С тех пор — тишина.
Мозги: Gemma против Gemma
Какую LLM подсунуть бриджу? Решил не верить вкусам и прогнать локальный бенчмарк: 16 фраз на моке Home Assistant MCP (комнаты, синонимы, устройства), temperature 0, ответ строго в JSON.
=== google/gemma-3-27b-it === итог: 15/16 верных, 1.75 с, 0.2522 ₽
=== google/gemma-4-26b-a4b-it === итог: 15/16 верных, 0.70 с, 0.2087 ₽
Качество одинаковое, латентность — в 2,5 раза лучше у Gemma 4 26B A4B (MoE-архитектура: 4B активных параметров), цена ниже на 17%. Все три колонки переведены на неё.
Попутно — две правки в форке, без которых жить плохо:
- Нормализация service. Gemma 4 честно копирует сервис из промпта полным
именем, и склейка домена давала несуществующий
light.light.turn_on; - Retry подтверждения. Zigbee-выключатель обновляет состояние с задержкой, и мгновенная сверка ловила старое — «Не удалось подтвердить выполнение команды». Теперь до трёх чтений состояния с паузой 400 мс.
И одно осознанное ограничение: инвентарь планировщика урезан до света
(QUASAR_HOME_DOMAINS=light) — 9 устройств вместо 177 сущностей. Токенов
меньше, и исчез класс ошибок «модель сматчила запрос на чужой switch».
Шторы и пылесос голосом пока недоступны — мне не нужно.
Экономика команды приятная: ~1090 входных токенов, из которых 1024 попадают в автоматический кэш префикса (тариф ниже примерно на порядок), плюс 20–60 выходных. Доли копейки за команду.
Результаты
- Три колонки с root, SSH (dropbear на порту 2222, вход только по ed25519-ключу)
и Entware; доступ закреплён
chattr +iи переживает перезагрузки. check-backendsна всех трёх:LLM: ok; Home Assistant: 177 entities.- Алиса не потеряла ни одной штатной функции; команды умного дома идут через мой мост.
Ограничения и открытые вопросы
- Одна фраза срабатывает на нескольких колонках сразу. Причина не подтверждена,
арбитража в бридже нет; журналы
conversations.jsonlпишутся — разберу по корреляции времени. - USB-путь для Мини так и не исследован (кабель? порт?) — запасной вариант, если DNS-метод когда-нибудь закроют.
- Секреты на колонках лежат в открытых конфигах — нужна ротация и нормальное хранение.
Выводы
Свобода колонки — это не «сломать и заменить», а интерфейсы: factory-образ как тайм-капсула доверия, DNS как точка входа и нормальный API бриджа сверху. Паяльник остался в ящике, а модели выбирает бенчмарк, не вкус.