*Полностью открытый IP-KVM, который собирается из двух плат без единой капли припоя, прошивается прямо из браузера и умеет уже почти всё, что умеет “взрослый” KVM-over-IP. В этой статье - вся история проекта: от “сервер не грузится, а монитор на антресоли” до маленького круглого экранчика, который показывает IP прямо на корпусе.
С чего всё началось
А началось всё с того, что коллега - пусть будет Олег - забэкал на Kickstarter JetKVM. Маленький аккуратный IP-KVM, приехал, работает, красота. Я посмотрел на это как гик: с одной стороны - реально классная штука, хочу такую же. С другой - за плечами был кое-какой опыт с ESP, руки чесались, и вместо “просто купить” включилось родное “а могу ли я сам?”.
Напомню на всякий, что такое IP-KVM и зачем он вообще нужен. Это коробочка, которая видит HDMI-выход вашей машины, притворяется для неё USB-клавиатурой и мышью и отдаёт всё это в браузер. Вы садитесь за ноутбук/планшет/телефон(O_o) на другом конце квартиры (или города) и видите ровно то, что было бы на мониторе - вплоть до BIOS и меню загрузки. Никакого агента, никакой ОС на целевой машине не нужно: ей вообще всё равно, есть ли там операционка.
Сценарий, ради которого это всё, знаком любому, у кого дома живёт сервер. Стоит где-то за коробками гипервизор/NAS, и в один прекрасный момент не грузится: не пингуется, по SSH молчит, веб-морда мертва. То ли BIOS ушёл в настройки, то ли ядро запаниковало, то ли ждёт нажатия F1 после новой планки памяти. Чтобы узнать - надо тащить к железке монитор с клавиатурой. А с IP-KVM ты просто открываешь браузер.
Штука известная и, в общем, не новая: собрать KVM на ESP пытаются давно - на ESP8266, на ESP32-S3, кто во что горазд. Упирается всё в видеозахват: вытащить HDMI на копеечном микроконтроллере - задача нетривиальная.
И тут появляется ESP32-P4 - довольно свежий чип от Espressif с интерфейсом камеры (MIPI-CSI), кучей PSRAM и USB 2.0 HS. Раз есть вход для камеры - значит, к нему можно прицепить мост HDMI->CSI и получить видеозахват. За копейки.
Но дело было не только в “дешевле”. JetKVM - правда хороший продукт, придраться особо не к чему. Но именно поэтому стало интересно: а можно ли на ESP сделать не “ну, для микроконтроллера сойдёт”, а по-настоящему качественное решение - в первую очередь по софту? Хотелось довести веб-консоль до уровня, на котором её не стыдно поставить рядом с полированными коммерческими продуктами: чтобы UI был отзывчивым, аккуратным и приятным, а не “инженерным интерфейсом на минималках”.
Так, вместо того чтобы просто заказать себе JetKVM вслед за Олегом, я сел паять… то есть, забегая вперёд, - как раз ничего не паять. Так родился ESP-KVM.
Ссылки сразу, чтобы не искать:
Сайт с прошивалкой и живым демо: https://espkvm.io/
Исходники: https://github.com/espkvm/espkvm
Откуда взялся видеозахват
Оказалось, что к той же мысли - “а давайте на P4” - пришёл не только я. jrowny в проекте p4kvm уже проделал самую муторную часть: поднял мост Toshiba TC358743 и вытащил кадры из CSI-приёмника ESP32-P4.
Изобретать этот кусок заново смысла не было, поэтому “железный” низ я взял у него, а всё, что выше - веб-консоль, ввод, безопасность, виртуальные носители, питание, сеть, интерфейс - написал с нуля.
Из чего это собрать
Вся прелесть в том, что паять не нужно (кроме опционального ATX - там пара проводков в готовый модуль оптопар). Нужны две платы и шлейф:
-
Waveshare ESP32-P4-ETH (Но лучше сразу брать ESP32-P4 Function EV rev 3.2 или другую p4x) - : ESP32-P4, 32 МБ PSRAM, 16 МБ флеша, 100-мегабитный Ethernet (для KVM за глаза), слот microSD и USB OTG. Плюс 40-пиновый разъём в стиле Raspberry Pi.
-
Geekworm C790 - мост HDMI->CSI на TC358743. Превращает HDMI-сигнал в поток, который понимает интерфейс камеры P4. Держит до 1080p и даже вытаскивает звук с HDMI по I2S (пока не задействовано).
-
Шлейф MIPI-CSI, которым эти две платы соединяются.
Плюс два USB-кабеля и HDMI. Итого - сумма, за которую готовый IP-KVM даже не улыбнётся в вашу сторону. Ладно, улыбнётся, NanoKVM. Но вы же здесь не за этим. Или за этим?
Важный нюанс с ревизией чипа. У меня плата с ESP32-P4 ревизии v1.3. От ревизии зависит очень многое, особенно скорость H.264: на свежих кремниевых ревизиях (v3.0+) встроен аппаратный конвертер цвета, и там картинка летает. На старых - нет, и это отдельная сага (см. ниже). Подробности - в HARDWARE-NOTES.
Прошивка за пять минут прямо из браузера
Вот тут я старался сделать по-человечески. Никаких idf.py flash, тулчейнов и танцев с бубном (хотя если хотите собрать сами - исходники открыты, всё описано).
-
Заходите на https://espkvm.io/ из браузера на движке Chromium (Chrome, Edge - им нужен Web Serial).
-
Втыкаете ESP32-P4-ETH в USB.
-
Жмёте кнопку прошивки, выбираете COM-порт - прошивальщик сам зальёт последнюю сборку.
Причём сборка берётся прямо из релизов на GitHub, собранных в CI. То есть вы прошиваете ровно тот бинарник, который публичный и воспроизводимый, а не “доверься мне, братан”.
Дальше - физика: шлейф между платами, HDMI с целевой машины в C790, USB от неё в OTG-порт P4 (по нему устройство притворится клавиатурой и мышью), Ethernet в сеть, питание. Через несколько секунд устройство поднимется под именем espkvm.local. При первом входе логин admin/admin, и консоль сразу заставит задать нормальный пароль - причём на уровне прошивки, а не только в интерфейсе (пока дефолтный пароль в силе, сессия дотягивается только до auth-эндпоинтов, устройство нельзя рулить по проводу).
Что оно умеет сегодня
Чтобы не растекаться - честный список того, что работает уже сейчас, без “скоро завезём”:
-
Видео с автоопределением режима. Меняется разрешение на целевой машине - картинка подстраивается сама. Видно и BIOS в 640x480, и загрузчик, и рабочий стол в 1080p. Уснула машина, выдернули HDMI, сменилось разрешение при загрузке - поток восстанавливается сам.
-
Два кодека: MJPEG (простой, ~20 fps) и аппаратный H.264 (экономный по трафику).
-
Точная мышь. Абсолютное позиционирование - курсор попадает ровно туда, куда кликнули, без “уплывания” из-за акселерации на целевой стороне. Есть и относительный режим для игр/pointer-lock.
-
Полноценная клавиатура, медиа-клавиши,
Ctrl+Alt+Delи другие макросы одной кнопкой, вставка текста с учётом раскладки. -
Работа с телефона. Нормальный мобильный интерфейс с тач-трекпадом и экранной клавиатурой, а не сломанная десктопная вёрстка. Ставится как PWA на домашний экран. Но там нужно добавить CA сертификат в браузер. Потому как сертификат самоподписанный. (Можно скачать в интерфейсе)
-
Несколько зрителей одновременно, управляет один - с “перехватом управления”.
-
Виртуальный привод. Грузите целевую машину с ISO/IMG на microSD или с маленького “спасательного” образа во встроенной флешке.
.isoотдаётся как CD-ROM, всё остальное - как флешка. На rev-3.x картой можно отдать целиком, на чтение-запись. Но со скоростью записи и чтения SD карты есть проблемы. К сожалению скорость минимальная. :( -
Управление питанием (ATX). Кнопки Power/Reset материнки через оптопары + чтение индикатора питания. И Wake-on-LAN в придачу.
-
Определение ОС целевой машины по тому, как она опрашивает USB-дескрипторы.
-
HTTPS с самоподписанным сертификатом (или своим), логин с PBKDF2, физический сброс пароля кнопкой, обновление прошивки по сети с откатом, тепловая защита, диагностика.
-
Home Assistant через MQTT - авто-обнаружение сенсоров и кнопок питания.
-
VPN: WireGuard или нативный Tailscale (об этом ниже - там тоже интересно).
Чего пока нет: звука с HDMI - мост его отдаёт, но для KVM это низкий приоритет (подробнее в конце).
А теперь про грабли
Расскажу обо что именно я споткнулся.
H.264 упёрся не туда, куда я думал
Логика подсказывала: аппаратный кодер H.264 -> мало трафика -> много кадров. На практике на моей ревизии чипа (v1.3) в блоке H.264 нет конвертера цвета, и кадр приходится гонять через отдельный аппаратный преобразователь RGB->YUV (PPA). А он упирается в пропускную способность PSRAM: конвертер таскает ~9 МБ на кадр, и когда он работает параллельно с энкодером, они дерутся за шину памяти.
Итог: 1080p по H.264 на старом кремнии выдаёт около 7 fps - довольно печально. Я даже развёл конвертацию и энкод на две задачи через два YUV-буфера в надежде распараллелить - прирост оказался копеечным (~6.7 -> ~7.3 fps), потому что бутылочное горлышко не в вычислениях, а именно в памяти. Поэтому MJPEG со своими ~20 fps остался основным вариантом, а H.264 - для узких каналов.
На rev 3.0+ эта проблема снимается встроенным конвертером - и там H.264 уже 22 fps. Но это уже другая плата, и до неё мы ещё дойдём.
microSD на этой плате - отдельная сага
На дефолтных 20 МГц карта нормально читает одиночные секторы: смонтировалась, показала каталог - вроде живая. Но валит любое многоблочное чтение - а именно так её читает USB-хост. То есть целевая машина образ прочитать не могла в принципе, при внешне рабочей карте.
Помогло только опускание шины до 4 МГц (медленно, ~1.5 МБ/с, зато читается 200 МБ без единой ошибки) и отказ от UHS/DDR-режимов. Запись на старом кремнии так и осталась ненадёжной, поэтому там карта только на чтение, а образы готовятся во внешнем картридере. На rev 3.x запись работает штатно - проверено на железе. Это известное ограничение ESP32-P4, а не мой косяк (я себя в этом убедил).
Кнопка сброса пароля чуть не убила сеть
Физический сброс пароля я повесил на кнопку BOOT (GPIO 35). Оказалось, этот пин делит функцию с Ethernet, и стоит захватить его после подъёма сети - сеть умирает намертво: устройство живёт, логи идут, но не отвечает даже на ARP. Пришлось читать кнопку ровно один раз, в узком окне сразу после старта, до инициализации Ethernet, и тут же отдавать пин обратно. Нашёл, как водится, не с первого раза.
Два устройства с дефолтным именем ссорились сертификатами
Устройство при первом старте само становится маленьким удостоверяющим центром, выписывает себе сертификат и подписывает его. Красиво - пока у вас не появилось два устройства с дефолтным хостнеймом espkvm: их самоподписанные CA получали одинаковое имя (CN), и, доверившись одному, браузер отвергал другой с ERR_CERT_AUTHORITY_INVALID. Лечится добавлением в имя CA суффикса из MAC-адреса и авто-перевыпуском.
Бонус: WebSocket, которого не было
Один из самых обидных. В какой-то версии в браузере вдруг отвалились H.264, клавиатура и мышь - при том, что все REST-роуты работали. Оказалось, таблица обработчиков HTTP-сервера была ровно на единицу меньше нужного: эндпоинты ATX её переполнили, а /video и /ws регистрировались последними - их-то молча и выкидывало. Поднял лимит с запасом.
Как проект оброс сетью: WiFi, Tailscale и WireGuard
KVM без нормального удалённого доступа - не KVM вовсе. Поэтому дальше история пошла в сторону сети.
WiFi. У ESP32-P4 нет своего радио. Но на плате ESP32-P4 Function EV рядом стоит ESP32-C6, и P4 общается с WiFi через него по SDIO. Появился выбор линка - Ethernet / WiFi / собственная точка доступа, - со сменой на лету из статус-бара. Плюс спасательный хотспот: если устройство не достучалось до своей сети, оно поднимает свою ESP-KVM-xxxx, а само продолжает ломиться в сеть и переподключается, как только та вернётся. И captive-портал - подключился телефоном к точке, консоль открылась сама, как в отеле.
Tailscale, нативно. Хотелось дотягиваться до устройства из любой точки без проброса портов и 100.x-адрес (или MagicDNS-имя), доступный откуда угодно, а обход NAT (через DERP/DISCO) берёт на себя. Под капотом - нативный ts2021-клиент (microlink), портированный на ESP-IDF 6. Сертификат консоли при этом перевыпускается так, чтобы быть валидным и по адресу в tailnet. Работает и с self-hosted control-сервером (Headscale/Ionscale).
Оба VPN-бэкенда живут на одном WireGuard-стеке и выбираются в рантайме - это отдельно пришлось разруливать, чтобы символы двух реализаций не конфликтовали в одной прошивке.
Вторая итерация железа: приехала новая плата
“Бутерброд из двух плат на проводах” просился в нормальный форм-фактор, а старый кремний v1.3 держал H.264 за горло. Поэтому я очень ждал плату ESP32-P4 Function EV ревизии 3.2 - со свежим кремнием, где H.264 наконец должен полететь.
Она приехала.
И новый камушек подтвердил ожидания. На rev 3.x картинка захватывается сразу в YUV422 прямо в оба энкодера, минуя проход цветоконвертации: это освободило ~4 МБ PSRAM и поставило H.264 и JPEG на один формат. Плюс третий буфер захвата, чтобы энкодер не ждал камеру. Результат: 1080p по H.264 поднялся с ~15 до ~22 fps, а на 720p - под 28-34. H.264, который на старой плате еле полз, здесь наконец стал юзабельным. Причём старый путь для rev <3.0 я аккуратно не трогал - обе платы продолжают работать.
Заодно у P4 Function EV есть ESP32-C6, ради которого и появился весь WiFi-функционал. Короче нормальный получился апгрейд. Не понятно только почему Espressif выпускает эту плату ка P4 хотя камушек при этом знатно переработан.
Маленький экранчик (IYKWIM)
Мне прилетел вполне резонный feature-request: когда устройство работает как “безголовая” коробочка где-то рядом с сервером, найти его IP - это лезть в DHCP-таблицу роутера, а проверить, что HDMI-сигнал ловится, - открывать веб-консоль. А хочется просто посмотреть на саму железку и всё понять.
Самое прекрасное в этом запросе было то что именно в этот момент я уже был на замершающем этапе добавления поддержки этих oled экранов.
Так в v0.21.0 появился маленький статус-дисплей. Втыкаете в пины крошечный OLED (SSD1306 или SH1106 - они авто-детектятся на той же I2C-шине, что и мост захвата), включаете в настройках - и устройство показывает прямо на панели свой IP, состояние линка, статус захвата и здоровье: циклом страницы с иконками и прогрессбарами температуры/RAM. Работает мимо энкодера, так что на стриминг не влияет. (Уже не влияет :) )
А потом я не удержался и добавил поддержку круглого цветного LCD GC9A01 - того самого “часового” кругляша. Он не только красивее, но и показывает больше: тот же статус плюс, например, адрес в Tailscale.
Оба варианта включаются одной галкой, а пины назначаются прямо из консоли: в этом же релизе настройки пинов стали выпадающими списками свободных GPIO, появилась вкладка Pins с полной картой (что зарезервировала плата, что вы назначили, что свободно), и ATX-пины тоже переехали на эту карту - чтобы ничего молча не столкнулось.
Как круглый GC9A01 выглядит вживую - на видео (без звука, просто короткая демонстрация):
https://www.youtube.com/watch?v=-snDjOOjbSA
Немного о безопасности
KVM - это полный доступ к машине, поэтому выпускать его в сеть “как есть” нельзя. Что сделано:
-
HTTPS с самовыпущенным CA (импортируете корневой один раз - браузер перестаёт ругаться, а заодно включается H.264, которому WebCodecs требует “защищённого контекста”). Можно и свой сертификат подсунуть.
-
Логин с PBKDF2-хешем пароля, ограничение перебора и обязательная смена дефолтного пароля - на уровне прошивки.
-
Физический сброс пароля кнопкой - логика простая: кто может дотянуться до кнопки, тот и так может выдернуть питание.
-
Весь интерфейс самодостаточный: никаких внешних CDN, шрифтов и запросов наружу. Устройство обязано работать в изолированной сети.
Не выставляйте это в публичный интернет. Логин и TLS есть, но security-review проект не проходил, а железка, держащая клавиатуру на чужой машине, стоит для атакующего дороже почти всего остального в сети. Держите её в доверенной сети или дотягивайтесь через VPN/Tailscale.
Что дальше и как поучаствовать
Из очевидного, чего пока нет, - звук с HDMI. Руки до него не доходят, для KVM звук - штука не то чтобы сильно важная (ну правда, часто вам нужно слышать зависший BIOS?), а вокруг хватает задач куда интереснее. Так что лежит и ждёт настроения. Полный roadmap - в репозитории.
С корпусом, кстати, тоже пока не очень. Я начал было рисовать его под Waveshare-“бутерброд” - а тут приехала плата совсем другого форм-фактора, и весь чертёж отправился в стол. Так что корпус пока отложен: смысла вылизывать коробку под железо, которое на глазах меняется, немного. Сначала - определиться с “эталонной” платой, потом уже одевать её.
Проект живой и открытый (Apache-2.0). Если хочется:
-
потрогать - прошивалка и интерактивное демо на https://espkvm.io/;
-
покопаться в коде - https://github.com/espkvm/espkvm, там же Issues и Discussions;
-
портировать на свою плату - есть PORTING.md, поддержка разных плат в проект уже заложена.
И напоследок - ради чего всё затевалось. Представьте: дома или на даче стоит машина, к которой в норме никто не подходит - NAS, медиасервер, ретро-ПК. Что-то пошло не так - а вы с телефона из метро заходите, видите зависший BIOS, жмёте пару клавиш, при необходимости монтируете загрузочный образ и переставляете систему. Или чините компьютер родителям в другом городе, не объясняя им по телефону, “какую кнопочку нажать”. Вот ради этих сценариев оно и делалось.
Спасибо, что дочитали. И если проект окажется полезным - скиньте ссылку на статью/проект другу-гику и звёздочку в репе поставьте если не жалко :)
Автор: Dexif
