Кто вайб-кодит – налетай. Кто сам пишет – убегай...
Некоторое время назад заинтересовался я 3D-печатью. Но вместо того, чтобы взять, как все нормальные люди, какой-нибудь Bambu Lab P1S, я взял QIDI Q2. Зачем? Конечно, чтобы печатать TPU с использованием AMS тратить свое время на решение всевозможных возникающих проблем. Эта статья как раз об одной из таких проблем.
А в чем, собственно, проблема? Как вы, наверное, знаете (или сейчас узнаете), многие 3D-принтеры имеют небольшой экран на корпусе, который позволяет им управлять (помимо управления через веб-интерфейс или, например, через мобильное приложение). Ниже можно увидеть, как внешне выглядит QIDI Q2 и обратить внимание на экран в его верхней части.

Так вот. После приобретения, длительной распаковки, снятия всяких там заглушек и фиксаторов и подключения системы AMS, я обнаружил, что подключенный тачскрин не подает признаков жизни (экран не загорается, USB-порт на нем не функционирует).

При этом сам принтер работал, веб-интерфейс был доступен, можно было без проблем печатать. Так зачем же мне этот экран? Дело в том, что по какой-то одним разработчикам известной причине, экран позволяет делать некоторый набор действий, который недоступен через веб-интерфейс или каким-либо другим документированным простым способом, например: подключение к Wi-Fi (спасибо, что есть Ethernet), а также обновление прошивки. То есть серьезно, если посмотрите официальную wiki, то там описаны только варианты с подключением USB-флешки, либо с запуском обновления по сети, но исключительно с помощью этого экрана. И если невозможность подключить флешку и распечатать с нее, как в общем-то и подключение к Wi-Fi, и просмотр статуса печати - это то, с чем я мог мириться, то отсутствие возможности по простому обновить прошивку - немного напрягало.
Вы, наверное, скажете - так замени экран. И правда, это то, что я попробовал сделать в первую очередь: нашел человека, который продавал рабочий экран (правда с трещиной) для QIDI Q2, подключил его - ноль изменений. Если дело не в экране, значит дело в кабеле, которым он подключен! И все бы ничего, но этот плоский кабель подключения протянут внутри корпуса так, что по-простому его не вытащить.
Еще одним простым вариантом было посмотреть крепление кабеля к материнской плате принтера, но визуальный осмотр и перещелкивание кабеля в разъеме тоже ни к чему не привело.
Что же делать? Пользоваться хочется, а искать кабель, потом писать в поддержку (кстати, быстро отвечают) с запросом инструкции по замене, потом менять... В общем, по такому пути идти не хотелось. Зато к принтеру можно запросто подключиться по SSH (mks:makerbase - учетные данные по умолчанию), и на нем Debian 11 AArch64.
Linux linaro-alip 5.10.160 #1 SMP PREEMPT Thu Feb 27 14:22:34 CST 2025 aarch64 GNU/Linux
Идея возникла следующая: что-то в системе выводит на этот экран данные, обрабатывает нажатия и все такое, значит, можно попробовать выводить изображение куда-то еще и отправлять нажатия программным способом.
И тут можно было бы уйти в разработку на неопределенный срок, включая анализ, как все устроено, но мы же в 2026 году, поэтому воспользуемся LLM (а точнее, ChatGPT и Claude Code), чтобы все это реализовать максимально быстро (кстати, довести идею до рабочей реализации у меня заняло где-то 1.5 - 2 часа).
Изначально я просто закинул вывод dmesg в ChatGPT без дополнительных комментариев. На что, в том числе, получил следующий ответ:
Далее ChatGPT предложил посмотреть содержимое framebuffer из /dev/fb0, чтобы получить изображение, которое должно выводиться на экран. Пару попыток спустя, это проще всего удалось сделать с помощью утилиты fbcat, которая есть в стандартном репозитории Debian:
fbcat /dev/fb0 > /tmp/screen.ppm
Получаем нормальную картинку размером 480x272 с содержимым экрана.

Теперь интересуемся, как сделать так, чтобы взаимодействовать с этим экраном программно и реализовать интерфейс в виде отдельного веб-сервиса на Python, доступного по сети:

Немного повозившись и попробовав то, что ChatGPT посоветовал, чтобы понять, как обрабатывается ввод через тачскрин, я выяснил, что отдельного устройства ввода от имени этого тачскрина не существует (так как устройство физически не подключено), а в /proc/bus/input/devices видим следующее:
|
1 2 3 4 5 6 7 8 9 10 |
cat /proc/bus/input/devices I: Bus=0003 Vendor=32e6 Product=9221 Version=0000 N: Name="icspring camera: icspring camer" P: Phys=usb-ff440000.usb-1.2/button S: Sysfs=/devices/platform/ff440000.usb/usb2/2-1/2-1.2/2-1.2:1.0/input/input0 U: Uniq= H: Handlers=event0 B: PROP=0 B: EV=3 B: KEY=100000 0 0 0 |
То есть единственное доступное устройство ввода (хорошо, файл устройства ввода) - это /dev/input/event0, которое использует камера принтера.
Далее было проверено, есть ли в системе uinput, оказалось, что он отсутвует, и, вероятно, ядро собрано без его поддержки:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
mks@linaro-alip:~ls -l /dev/uinput /dev/input/uinput 2>/dev/nullll mks@linaro-alip:~$ modprobe uinput -bash: modprobe: command not found mks@linaro-alip:~$ sudo !! sudo modprobe uinput modprobe: FATAL: Module uinput not found in directory /lib/modules/5.10.160 mks@linaro-alip:~$ ps aux | grep -Ei 'qt|qml|weston|xorg|flutter|tslib|lvgl|directfb|sdl' mks 6448 0.0 0.4 8144 2184 pts/2 S+ 06:53 0:00 grep -Ei qt|qml|weston|xorg|flutter|tslib|lvgl|directfb|sdl mks@linaro-alip:~$ sudo !! sudo ps aux | grep -Ei 'qt|qml|weston|xorg|flutter|tslib|lvgl|directfb|sdl' mks 6459 0.0 0.4 8144 2236 pts/2 S+ 06:53 0:00 grep -Ei qt|qml|weston|xorg|flutter|tslib|lvgl|directfb|sdl mks@linaro-alip:~$ lsof /dev/input/event* 2>/dev/null mks@linaro-alip:~$ for p in /proc/[0-9]*/fd/*; do readlink "$p" 2>/dev/null; done | grep '/dev/input/' mks@linaro-alip:~$ |
Пришлось идти выяснять, какой процесс вообще работает с экраном (так как этот процесс, скорее всего, и чтением ввода с экрана занимается):
|
1 2 3 |
mks@linaro-alip:~$ sudo fuser -v /dev/fb0 USER PID ACCESS COMMAND /dev/fb0: root 955 F...m client |
Интересующий нас процесс и соответствующий файл: /home/mks/QD_Q2/bin/client. Делаем на него strings, закидываем в ChatGPT и получаем:

Помните, я выше писал про файл /dev/input/event0, который используется камерой? Эта же строка захардкожена в исполняемом бинарном файле client. То есть при штатной работе экрана, этот файл используется экраном, а камера использует, например, /dev/input/event1. А я как раз не могу его физически подключить, чтобы система его увидела.
Пришло время ленивого реверс-инжиниринга с использованием LLM. Копируем файл с устройства, закидываем в Ghidra, IDA, rizin (смешная третья опция), и т.п. Ищем, где используется вышеупомянутая строка.
Закидываем все это добро в ChatGPT, дополняем выводом декомпилятора для функций sub_78DA3C, sub_78DB04, получаем, в том числе, следующие варианты:
Мне ближе подход с патчингом, но не фактическим изменением, а скорее перехватом работы с файлом устройства через LD_PRELOAD (подгрузку дополнительной динамической библиотеки в процесс, которая перехватит некоторые системные функции и реализует необходимый функционал). Просим ChatGPT составить спецификацию на разработку такой штуки в виде MD-файла.
Вот файл, который мне сгенерировала LLM: QD_Q2_remote_click_spec.md.
Этот файл я уже зарядил в Claude Code, модель выбрал Opus 4.7 (reasoning - high). Из плагинов стояли только context7 и claude-mem, всякие там AGENTS.md, CLAUDE.md, agent skills и подобное - не использовал.
В итоге с первого раза получил собирающийся и работающий результат, но докинул пару запросов, чтобы скорректировать кое-что из личных предпочтений: использовать uv в качестве пакетного менеджера Python и добавить возможность не собирать .so-файл (не хотел ставить инструменты сборки на систему 3D-принтера) при запуске установочного скрипта, а указать существующий. Гонял LLM, конечно же, на отдельной виртуалке.
После установки на 3D-принтер и перезагрузки, обращаемся на IP-адрес принтера на порт 18080 и наблюдаем:
Все нормально работает, может быть, не идеально, но пользоваться точно можно. В общем, здорово, что в 2026 можно решить свою проблему за условные 20$ и пару часов, хотя, конечно, получения опыта и новых знаний от такого процесса - минимум.
Исходный код: qidi-q2-remote
Исходный код на Github: https://github.com/kaimi-/qidi-q2-remote










