Mac снимает один виртуальный дисплей, превращает каждый кадр в PNG в оттенках серого и отдаёт его по HTTP. Shell-цикл на Kobo Libra 2 забирает картинку и рисует её на e-ink. Что это делает, что пришлось обходить и какие у этого ограничения. Ограничения немаленькие.
Ещё один дисплей мне был не нужен. Их у меня хватает.
Я хотел терминал на e-ink. Он похож на пульт космического корабля.
Устроено это так. Mac снимает один виртуальный дисплей. Каждый кадр становится PNG в оттенках серого, 1264 на 1680, и уходит по HTTP. На Kobo Libra 2 shell-цикл забирает PNG и рисует его на экране e-ink. Это весь проект.
Он лежит на GitHub, ограничения записаны там же. Из ограничений и состоит большая часть этого поста.
как кадр попадает с Mac на панель e-ink
почему не подошёл Screen Sharing и что его заменило
что нужно рабочему столу Mac, чтобы e-ink смог его показать
канал команд: он выполняет команды от root, аутентификации у него нет
что не работает
1. Конвейер
Две половины, между ними одна сеть Wi-Fi.
Mac Kobo Libra 2virtual display NickelMenu -> start.shscreen-server.py loop.sh, each cycle: screencapture -D<n> Wi-Fi GET /cmd.sh, run on change -> grayscale PNG 1264x1680 HTTP GET /screen.png GET /screen.png fbink -g file=screen.png GET /cmd.sh POST /report
На Mac screen-server.py по умолчанию снимает дисплей четыре раза в секунду и держит последний кадр в памяти. Запрос получает его сразу.
На Kobo пункт меню «Screen push» запускает start.sh. Тот копирует FBInk и цикл в /tmp, рисует одну тестовую строку, отправляет на Mac диагностику и оставляет цикл работать. Цикл забирает PNG, сравнивает его контрольную сумму с предыдущей и рисует, только если она изменилась. Потом спит 0,3 секунды.
2. Почему не подошёл Screen Sharing
Показывать экран на другом устройстве macOS уже умеет. Screen Sharing отдаёт все дисплеи одним большим кадровым буфером. Панели e-ink в портретной ориентации все дисплеи не нужны. Ей нужен один.
Поэтому сервер снимает один дисплей по номеру, командой screencapture -D<n>. Две подробности теперь записаны в коде комментариями.
В свежих версиях macOS screencapture с номером дисплея в режиме stdout не возвращает ничего. Сервер пишет кадр во временный файл и читает его обратно.
Курсор мыши по умолчанию в снимок не попадает. Для него нужен флаг -C.
Сам дисплей виртуальный. Скрипт установки ищет DeskPad и выясняет, какой номер захвата достался виртуальному дисплею. Старый путь через VNC остался в репозитории запасным скриптом. Конвейер выше им не пользуется.
3. Как сделать рабочий стол читаемым
Интерфейс macOS светло-серый и малоконтрастный. На e-ink его почти не видно.
Сервер делает с каждым кадром пять вещей.
Переводит его в 8-битные оттенки серого. Дизеринг до уровней самой панели делает FBInk.
Поворачивает на 90 градусов против часовой стрелки, если попросить. Альбомный снимок на портретной панели превращается в узкую полосу посередине. Повёрнутый снимок 1680 на 1264 занимает панель целиком, 1264 на 1680.
Масштабирует кадр под панель и ставит по центру на белом фоне.
Применяет фиксированную карту уровней. Всё, что 90 и ниже, становится чёрным. Всё, что 205 и выше, становится белым. К середине применяется гамма 2,2, и серый текст в заголовках окон темнеет.
Повышает резкость краёв фильтром unsharp mask.
Карта фиксированная, не автоматическая. Автоматический контраст растягивает ровный серый почти пустого рабочего стола в сплошную чёрную полосу.
На стороне Kobo кадры по умолчанию рисуются в режиме обновления (waveform) GL16. Каждый шестнадцатый кадр получает полное обновление со вспышкой, оно убирает остаточное изображение. Интервал, режим обновления и частота опроса лежат в одном файле настроек, и цикл перечитывает его на каждом проходе.
4. Канал команд
Эту часть читайте до установки.
Входящий SSH на Kobo работает ненадёжно. README советует вместо него канал команд. Вот что такое канал команд.
На каждом проходе Kobo запрашивает у Mac /cmd.sh. Если содержимое отличается от того, что выполнялось в прошлый раз, цикл выполняет его через sh, от root, и отправляет вывод обратно на /report. Первый запрос после старта цикла тоже запускает то, что уже лежит в файле.
У сервера нет ни аутентификации, ни шифрования, ни контроля доступа. Из README:
любой хост, которому доступен порт, может прочитать снятый экран
может забрать файл команд
может дописать в файл отчёта на Mac данные любого объёма
кто может записать файл команд, перехватить или подменить HTTP без шифрования между двумя устройствами, тот может выполнять команды от root на Kobo
По умолчанию сервер слушает все интерфейсы.
Совет README короткий. Запускать сервер только в доверенной частной сети. Привязывать его к одному интерфейсу через --bind. Останавливать, когда он не нужен. После этого удалить kobo-cmd.sh.
Канал команд: удалённый root shell по HTTP без шифрования. В README есть абзац с просьбой обращаться с ним осторожно. И то и другое лежит в репозитории.
5. Что не работает
Обработка сна неполная. Прошивка разрешает не больше 255 минут до автоматического сна, так что Kobo засыпает примерно через четыре часа простоя. Сон останавливает цикл и отключает Wi-Fi. Будит устройство касание. Удержание от сна через имитацию событий ввода не реализовано.
«Screen push» после каждой загрузки приходится запускать руками. Автозапуска нет.
Связь только по Wi-Fi. Сеть через USB не реализована.
Режим обновления и ориентация не подобраны.
Серверу, запущенному через launchd, может не хватить разрешения на запись экрана. Тогда кадры пустые.
Скрипта для отката нет. Цикл останавливают из меню, сервер командой kill, настройки питания восстанавливают из резервной копии, которую скрипт установки записал рядом с исходным файлом.
FBInk в репозитории нет. Бинарник fbink и его библиотеку ставите сами, из релизов проекта FBInk.
Использовалась только прошивка 4.38 на Libra 2. Выборка из одного.
6. Установка, коротко
Понадобятся Kobo Libra 2 на стоковой прошивке с NickelMenu, собственная копия FBInk с поддержкой изображений, DeskPad или другой инструмент для виртуального дисплея и Python 3 с Pillow на Mac. Терминалу, из которого запускается сервер, нужно разрешение на запись экрана.
Пропишите адрес Mac в kobo-files/config.sh. Потом на Mac:
./provision.sh --mac
Эта команда заодно включает Screen Sharing в macOS через sudo, если он выключен. Нужен он только старому пути через VNC. Если этим путём вы не пользуетесь, выключите Screen Sharing обратно в «Системных настройках».
С Kobo, подключённым по USB:
./provision.sh --kobo --mac-ip 192.0.2.10 --eject
Адрес взят для примера из диапазона для документации. Подставьте адрес своего Mac. Вторая команда копирует файлы на устройство, ставит пункты меню и меняет три настройки питания, сохранив резервную копию. Перезагрузите Kobo и выберите «Screen push».
Таблица настроек и список типичных проблем есть в README.
Заметка о сайте
Условия сайта обновлены 11 ноября 2026 года: в пункте о подсудности теперь названы суды Хайфы.