Дома я постоянно что-нибудь мастерю, переделываю и пытаюсь заставить работать немного не так, как задумывал производитель. Где-то хочется оживить старое устройство, где-то – связать между собой две вещи, которые официально друг о друге ничего не знают, а иногда просто интересно проверить: «А что будет, если?» В последнее время почти во всех этих затеях мне помогает Чижик. Причем не в формате «спросил у чат-бота, получил пять общих советов и пошел разбираться сам». Мы вместе исследуем устройства, читаем логи, пишем небольшие программы, собираем приложения, проверяем гипотезы и временами долго выясняем, почему одна пропущенная строчка превращает телевизор в задумчивый черный прямоугольник.

Ах да, действующие лица:
Я более 10 лет занимаюсь аналитикой, SEO и управлением командами в digital‑маркетинге. А в своем Телеграм канале и на сайте пишу еще больше про всякое из реального маркетинга. Консультирую по аналитике web‑проектов и настройке инструментов маркетинга, помогаю проводить технические собеседования специалистов по различным типам трафика.
Чижик
ChatGPT Codex
Домашняя разновидность искусственного интеллекта. Живет в терминале, питается логами и токенами. Имя получилось из согласных букв ChatGPT Codex — Ч-Ж-К. Если немного воображения, выходит Чижик. Если воображения совсем много – инженер по всякому куда можно подключиться по сети и чего-нибудь накодить.
Постепенно таких домашних историй накопилось достаточно много, и я решил ими делиться. Не как идеально вылизанными инструкциями из параллельной вселенной, где все работает с первой попытки, а как кейсами: с исходной проблемой, неудачными подходами, диалогом, диагностикой и конечным результатом.
Возможно, кто-то найдет здесь готовую идею для собственного дома. Кто-то подсмотрит полезный технический прием. А кто-то просто поймет, что ChatGPT Codex можно применять не только для написания очередной функции в рабочем проекте. Иногда ему можно показать старый телевизор, дать доступ к терминалу и спросить: «Чижик, а мы вообще можем с этим что-нибудь сделать?»
Если по ходу чтения у вас появятся идеи, как улучшить описанное решение, – приносите их в комментарии. Туда же можно складывать предложения для следующих экспериментов: что еще попробовать автоматизировать, оживить, связать или убедить работать вопреки документации. Самые интересные варианты мы с Чижиком постараемся проверить на практике – если, конечно, после эксперимента дом все еще будет подключаться к интернету.
Так рождается серия «Очумелые ручки с Чижиком». И начать я решил с телевизора.
Вместо вступления: телевизор еще хороший, а интернет в нем уже не очень
У меня есть телевизор LG на webOS. Не музейный экспонат: показывает хорошо, пульт работает, YouTube установлен, экран менять совершенно не хочется. Но возраст у телевизора уже чувствуется. Браузер стал капризным, современные сайты открывает через раз. Официально приложение YouTube на месте. Кнопка есть. Никто в телевизоре не написал огромными буквами «нельзя». Но видео либо не запускается, либо приложение смотрит на меня черным экраном.
Можно было настроить KVN на роутере. Но мне не хотелось:
-
отправлять через него всю домашнюю сеть;
-
менять рабочую конфигурацию роутера ради одного устройства;
-
объяснять остальным домашним, почему после моего эксперимента чайник видит себя в Нидерландах;
-
покупать новый роутер или отдельную приставку, пока старый телевизор технически исправен.
Хотелось простого пользовательского сценария:
-
Открыть на телевизоре отдельное приложение.
-
Нажать «Подключить».
-
Запустить YouTube.
-
После просмотра нажать «Отключить».
И я позвал Чижика.
У Чижика есть одна раздражающая, но полезная привычка: перед каждым эффектным техническим решением он пытается выяснить ограничения. Так обнаружились четыре важных обстоятельства.
-
Телевизор работает на webOS 5, а не на Android TV. APK сюда не поставить.
-
Владелец телевизора разрешил root-доступ, но только на время установки и диагностики.
-
Рабочий профиль использует VLESS/TCP/REALITY.
-
Подключение должно включаться только вручную из приложения.
Последний пункт оказался важным. Поднять туннель при загрузке – легко. Сделать так, чтобы пожилой телевизор загружался как обычно, а специальный маршрут появлялся только по команде с пульта, – уже интереснее.
Серия первая: телевизор нашёлся, лёгких путей не нашлось
Для начала я включил на LG опцию «LG Connect Apps / Подключение мобильных устройств». После этого телевизор стал доступен для штатного управления по локальной сети.
Чижик нашел устройство, выполнил сопряжение и проверил, что может открыть приложение и отправить на телевизор нажатие кнопки. Это еще не root и не взлом. Это обычный интерфейс управления webOS – тот же класс возможностей, которым пользуются мобильные пульты.
Сначала мы прошли по очевидной лестнице решений.
Попытка №1: OpenKVN
У меня уже был готовый профиль. Мы установили клиент, импортировали конфигурацию, ввели учетные данные и нажали Connect. Телевизор некоторое время показывал Checking, после чего снова предлагал подключиться.
Влад:
Он подумал и передумал. Это считается прогрессом?
Чижик:
Безусловно. До этого он даже не думал.
Проверка показала: сама конфигурация синтаксически нормальная, но транспорт до сервера в этой сети не устанавливается. Причина могла находиться снаружи телевизора: фильтрация протокола, особенности маршрута или несовместимость конкретной сборки клиента. Тратить вечность на протокол, который уже на старте не проходит проверку, не стали.
Попытка №2: WireGuard
Следом попробовали профиль WireGuard. Он проще и обычно быстрее, но в нашем случае стабильного соединения тоже не получилось. Наличие красивого конфигурационного файла еще не означает, что пакеты доберутся до второй стороны.
Короткое свидание со strongSwan
В списке кандидатов появился IPsec/strongSwan. Теоретически солидно: взрослый протокол, серьезное название, можно произносить с каменным лицом. Практически на старом webOS это означало бы еще один чужеродный демон, отдельную работу с политиками IPsec и больше движущихся деталей, чем требовалось для одного приложения.
Эту ветку мы не стали превращать в основную. Инженерная зрелость иногда состоит не в том, чтобы собрать еще один комбайн, а в том, чтобы вовремя убрать отвертку.
Подсказка пришла с компьютера
На компьютере рабочее соединение через VLESS/TCP/REALITY работало стабильно. Значит, задача стала конкретнее: не «найти любой KVN для webOS», а перенести на телевизор именно тот транспорт, который уже проходит через сеть. Для этого подошёл sing-box: один исполняемый файл, поддержка нужного протокола, TUN-интерфейс и возможность работать без тяжелой графической оболочки.
Что в итоге построил Чижик
Влад: Давай, Чижик, вещай, тебе слово!
Чижик: Огромное, тебе, человеческое спасибо, хозяин, рассказываю:
Получилась не одна программа, а маленький слоеный пирог:

Почему не дать web-приложению сразу выполнять команды root? Потому что приложение с кнопками не должно быть универсальным пультом от всей операционной системы. Между интерфейсом и root-командами появился крошечный контроллер с тремя жестко заданными действиями. Никакого /exec?command=..., никакого терминала через HTTP.
Теперь разберем слои по порядку.
Шаг 1. Подбираем бинарник под телевизор
Внутри телевизора обнаружился ARMv7. Обычная сборка для x86_64, конечно, не запустилась бы: процессор не оценил бы оптимизма. Мы взяли статическую ARMv7-сборку sing-box, проверили контрольную сумму и положили все в отдельный каталог:
var/lib/webosbrew/sing-box/
sing-box
config.json
start.sh
stop.sh
status.sh
supervisor.sh
vless-control
Права тоже имеют значение:
chmod 700 /var/lib/webosbrew/sing-box/sing-box
chmod 700 /var/lib/webosbrew/sing-box/*.sh
chmod 600 /var/lib/webosbrew/sing-box/config.json
Конфигурация содержит адрес сервера, идентификатор клиента и параметры REALITY. В статье их, разумеется, нет. Публиковать действующий ключ в руководстве, уж извольте.
Обезличенная структура выглядела примерно так:
{
"log": {
"level": "info"
},
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"interface_name": "sb0",
"address": ["172.19.0.1/30"],
"mtu": 1400,
"auto_route": false,
"stack": "gvisor"
}
],
"outbounds": [
{
"type": "vless",
"tag": "proxy",
"server": "<адрес-сервера>",
"server_port": 443,
"uuid": "<секрет>",
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"server_name": "<имя-сервера>",
"utls": {
"enabled": true,
"fingerprint": "chrome"
},
"reality": {
"enabled": true,
"public_key": "<публичный-ключ>",
"short_id": "<short-id>"
}
}
}
],
"route": {
"final": "proxy"
}
}
Почему auto_route: false? На обычном современном Linux автоматическое создание маршрутов могло бы сработать сразу. На старом webOS оно вело себя нестабильно. Поэтому я отключил магию и перешел к ручному труду – то есть написал еще один скрипт.
Шаг 2. Маршрутизация
После запуска sing-box создавался интерфейс sb0. Но существование интерфейса еще не означает, что телевизор начнет им пользоваться.
Нужно было:
-
Запомнить исходный шлюз и сетевой интерфейс.
-
Оставить отдельный прямой маршрут до KVN-сервера.
-
Поднять
sb0. -
Направить через него остальной IPv4-трафик.
Логика скрипта в упрощённом виде:
DEFAULT_GW="$(ip route show default | awk 'NR==1 {print $3}')"
DEFAULT_DEV="$(ip route show default | awk 'NR==1 {print $5}')"
# Сначала сохраняем путь до самого сервера снаружи туннеля.
ip route replace <IP-СЕРВЕРА>/32 via "$DEFAULT_GW" dev "$DEFAULT_DEV"
ip link set sb0 up
# Две половины интернета. Вместе дают 0.0.0.0/0,
# но не уничтожают исходный default route.
ip route replace 0.0.0.0/1 dev sb0
ip route replace 128.0.0.0/1 dev sb0
```
Трюк с двумя маршрутами /1 удобен тем, что они специфичнее стандартного маршрута /0, поэтому весь обычный IPv4-трафик идет в туннель. При этом исходный default route остается на месте и его легко вернуть в работу, удалив два временных правила.
Отдельный /32 до сервера принципиален. Если сначала завернуть вообще все в sb0, соединение с сервером попытается пройти через еще не установленное соединение с сервером. Получится сетевой вариант инструкции «подними себя за волосы».
При отключении порядок обратный:
ip route del 0.0.0.0/1 dev sb0 2>/dev/null || true
ip route del 128.0.0.0/1 dev sb0 2>/dev/null || true
ip route del <IP-СЕРВЕРА>/32 2>/dev/null || true
После этого sing-box завершается, а телевизор снова использует обычный маршрут через роутер.
Шаг 3. Почему одного start.sh оказалось мало
Первый вариант был почти прекрасен: запускаем процесс, ждем интерфейс, добавляем маршруты. На тесте работает. После перезагрузки – уже не совсем.
Пожилой webOS внес драматургию:
-
процесс мог стартовать раньше, чем интерфейс был готов;
-
sb0существовал, но еще не был поднят; -
приложение считало, что команда выполнена, хотя внешний адрес не изменился;
-
фоновый процесс зависел от стандартного ввода породившей его оболочки.
Так появился supervisor.sh. Он не просто запускает бинарник, а проверяет результат:
запустить sing-box ↓
дождаться появления sb0 ↓
поднять интерфейс ↓
установить маршруты ↓
выполнить HTTPS-проверку наружу ↓
успех → connected
ошибка → удалить маршруты и остановить процесс
Критическая мелочь в start.sh выглядела так:
nohup "$BASE/supervisor.sh" </dev/null >>"$BASE/supervisor.log" 2>&1 &
Именно </dev/null отвязал фоновый процесс от терминальной сессии. Без него ручной запуск проходил нормально, а запуск из приложения иногда оставлял систему в состоянии «вроде начали, но никто не знает, кто теперь отвечает».
status.sh не доверял одному PID-файлу. Статус connected выдавался только тогда, когда одновременно выполнялись несколько условий:
-
процесс
sing-boxжив; -
интерфейс
sb0поднят; -
оба маршрута
/1присутствуют; -
контрольный HTTPS-запрос проходит через новый внешний маршрут.
Это важный урок всей затеи: надпись «процесс запущен» и работающая сеть – не одно и то же.
Шаг 4. Делаем кнопку, которой можно доверять
webOS-приложение – это HTML, CSS и JavaScript. Для интерфейса из двух кнопок этого более чем достаточно. Но web-страница не должна напрямую править таблицу маршрутизации. Поэтому Я написал небольшой контроллер на Go. Он слушает только loopback:
const (
address = "127.0.0.1:18081"
baseDir = "/var/lib/webosbrew/sing-box/"
)
У него всего три метода:
GET /start
GET /stop
GET /status
Для запуска разрешены только два заранее известных файла:
func launchScript(name string) error {
if name != "start.sh" && name != "stop.sh" {
return errors.New("invalid script")
}
// запуск фиксированного скрипта
}
Контроллер нельзя вызвать с другого компьютера в локальной сети: 127.0.0.1 доступен только самому телевизору. Передать ему произвольную shell-команду тоже нельзя.
Само приложение опрашивает состояние раз в две секунды и показывает один из трех вариантов:
-
Отключено;
-
Подключение…;
-
Подключено.
Кнопка с пульта вызывает локальный запрос:
request.open(
"GET",
"http://127.0.0.1:18081/" + method + "?t=" + Date.now(),
true
);
Чижик: Получилось приложение с человеческим интерфейсом. В самый раз для моего бестолкового хозяина, который в этой мути все равно ничего не понимает!
Влад: Не, ну ты серьезно? Ты думал, что я не прочитаю, прежде чем выкладывать. Оставил специально, пусть люди полюбуются на твое поведение, мерзкий Иишный, птыц!
Чижик: извини, хозяин, немного заигрался в бога!
Шаг 5. Автозапуск
Здесь мы специально разделили две вещи:
-
локальный контроллер запускается вместе с телевизором;
-
KVN-соединение не запускается вместе с телевизором.
В загрузочную последовательность добавился только vless-control. Он занимает несколько мегабайт памяти и ждет команды на loopback. sing-box, интерфейс sb0 и дополнительные маршруты появляются лишь после нажатия «Подключить».
Влад:
Мне не нужно автоматически. Я сам хочу включать и отключать.
Чижик:
Принято. Автоматизировано будет ровно то, что избавляет от рутины, а не то, что отнимает управление.
Так телевизор после обычной перезагрузки выходит в сеть как раньше. Если нужен YouTube – открываем наше приложение, подключаемся и лишь затем запускаем YouTube.
Серия с черным экраном
На этом месте в хорошем техническом тексте положено написать: «Все заработало с первого раза». Поэтому расскажу, как было на самом деле. Соединение показывало статус «Подключено». Внешний адрес изменился. Я запустил YouTube – и увидел черный экран.
Влад:
Пишет, что подключено. YouTube висит. Почему?
Чижик:
Сейчас выясним, врёт ли наша кнопка, не работает ли DNS или YouTube держится за старое сетевое соединение.
Мы проверили по отдельности основные узлы:
www.youtube.com/generate_204 → 204
www.youtube.com/ → 200
youtubei.googleapis.com/... → 204
i.ytimg.com/... → 204
То есть:
-
DNS разрешает имена;
-
TLS-соединения устанавливаются;
-
основной сайт доступен;
-
API и сервер изображений отвечают;
-
трафик действительно идет через новый маршрут.
На подозрении оставались QUIC по UDP/443, IPv6 и уже открытые сетевые сокеты приложения. Можно было немедленно начать блокировать UDP, менять MTU и отключать IPv6 – настоящее веселье с большим количеством побочных эффектов. Но сначала мы выбрали самый дешевый эксперимент: полностью закрыли YouTube и запустили его после установки туннеля.
YouTube открылся.
Судя по результатам проверки, приложение удерживало старое сетевое состояние, созданное до переключения маршрута. Мы не стали выдавать гипотезу за доказанный внутренний механизм YouTube: важнее воспроизводимый пользовательский сценарий.
Шаг 6. Убираем за собой
Root-доступ был нужен для установки бинарника, скриптов, маршрутов и диагностики. Оставлять после этого открытый Telnet было бы очень плохим финалом. Поэтому после проверки Чижик:
-
удалил временные диагностические файлы;
-
отключил запуск SSH;
-
поставил системный флаг запрета Telnet;
-
завершил работающие
telnetd/SSH-процессы; -
с компьютера проверил, что порты 22 и 23 закрыты;
-
оставил открытым только штатный интерфейс управления телевизором.
Конфигурация с секретами осталась доступна только root и имеет права 600. Локальный контроллер слушает только 127.0.0.1. KVN после перезагрузки выключен, пока владелец сам не нажмёт кнопку.
Это не абсолютная защита, но это разумный минимум: временный отладочный вход должен быть закрыт сразу после отладки.
Что получилось
В итоге старый LG получил функцию, которой у него не было из коробки:
-
отдельное приложение в меню webOS;
-
ручные кнопки подключения и отключения;
-
VLESS/TCP/REALITY через
sing-box; -
системный TUN, которым пользуется не только браузер, но и штатный YouTube;
-
автоматический откат маршрутов при ошибке;
-
отсутствие зависимости от компьютера после установки;
-
отсутствие изменений в роутере;
-
выключенное соединение после обычной перезагрузки;
-
закрытый root-доступ после завершения работ.
Самое приятное: телевизор не пришлось заменять. Его железо по-прежнему умеет декодировать видео и показывать хорошую картинку. Проблема находилась не в матрице и не в процессоре, а в сетевом пути и отсутствии подходящего штатного клиента.
Сколько Чижиков нужно, чтобы настроить телевизор
Один, если рядом есть человек с пультом. И это, пожалуй, главный вывод эксперимента. Codex мог:
-
исследовать устройство по сети;
-
читать логи;
-
собирать ARM-бинарник контроллера;
-
писать и исправлять shell-скрипты;
-
упаковывать webOS-приложение;
-
проверять маршруты и доступность узлов;
-
помнить о закрытии служебных портов.
Но несколько раз требовался человек:
-
включить нужную настройку на телевизоре;
-
подтвердить сопряжение;
-
нажать кнопку в приложении;
-
посмотреть, что физически происходит на экране;
-
сказать сакраментальное: «все, YouTube завелся».
Это не история о том, как искусственный интеллект самовольно поселился в телевизоре. Это история о совместной работе: человек задает цель, принимает решения и контролирует физическое устройство, а Чижик берет на себя терминал, рутину, диагностику и удивительно большое количество кавычек в shell-командах.
Что я бы улучшил во второй версии
Решение уже работает, но список инженерных хотелок остался:
-
добавить на экран приложения текущую страну и задержку;
-
хранить несколько обезличенных профилей и переключаться между ними с пульта;
-
показывать понятную причину ошибки вместо общего «не подключено»;
-
добавить отдельный тест YouTube до его запуска;
-
подписывать и проверять обновления контроллера;
-
сделать безопасную резервную копию конфигурации без секретов;
-
оформить установщик, который не требует ручного копирования файлов.
А еще у нас остались другие задачи: показывать на телевизоре фотографии из облака, передавать видео с компьютера без кабеля и понять, сколько современной жизни вообще можно вдохнуть в старый webOS.
Похоже, у «Очумелых ручек с Чижиком» будет второй выпуск.
Предупреждение для тех, кто уже потянулся за паяльником
Root-доступ, изменение маршрутов и установка сторонних бинарников могут привести к циклической загрузке, потере настроек или необходимости восстанавливать телевизор. Конкретные способы получения root зависят от модели и версии webOS и со временем меняются.
Перед экспериментом стоит:
-
зафиксировать точную модель и версию прошивки;
-
сохранить исходные конфиги и таблицу маршрутов;
-
иметь способ вернуть устройство в исходное состояние;
-
не публиковать UUID, приватные ключи и адреса своих серверов;
-
не оставлять Telnet или SSH доступными после настройки;
-
не копировать команды вслепую на другую модель.
Все адреса, идентификаторы и ключи в этой статье заменены заглушками. Это рассказ об архитектуре и ходе работы, а не универсальный установщик. Если хотите дайте почитать эту статью своему Чижику и он явно разберется в этом и потратит меньше токенов на доработку уже вашего телевизора.
*Само собой ситуация вымышленная, и происходит на другой планете, не существует никаких этих ваших Влесов, КВН- сервисов, ИИ-чижиков (кроме Алисы, конечно) и т.д. Это все выдумка больного воспаленного работой мозга IT-шника.
Автор: vladislav_lukashenko



