Печать из Telegram: переслал документ в чат — он выехал из принтера

В прошлой статье я научил старенький Samsung ML-1615 печатать по AirPrint. Удобно, но только пока ты дома. А хочется так: переслал документ в семейный чат с подписью «напечатай», пришёл домой, а он уже лежит в лотке. Сделал) Идём под кат…

Как устроено

Телеграм-бот у меня уже есть, его слушает Home Assistant. Через него приходят уведомления, через него же magnet-ссылки из чата уезжают в qBittorrent. Второго слушателя на одного бота Telegram не пускает, поэтому всё вешаем на HA. Он ловит сообщение с файлом, скачивает файл и отдаёт его маленькому HTTP-серверу в контейнере с CUPS, а тот отправляет файл на печать.

Схема печати из Telegram: сообщение из семейного чата попадает в Home Assistant, тот скачивает файл и шлёт его POST-запросом на print-server в контейнере с CUPS, откуда задание уходит через lp на принтер Samsung ML-1615
Путь документа из чата до лотка

Что ловить в Home Assistant

Тут есть тонкость. Обычный текст HA присылает событием telegram_text, а сообщение с файлом отдельным событием telegram_attachment. Подпись к файлу лежит в том же поле text, рядом с file_id, file_name и прочим, так что слово «напечатай» проверяется как в обычном сообщении.

Если не уверены, что именно прилетает, включите debug-лог интеграции Telegram Bot. В логе будет строчка Firing event telegram_attachment: {...} со всеми полями.

Сервер печати

В контейнере с CUPS крутится крошечный сервер на голом http.server из стандартной библиотеки Python, строк на 60. Умеет ровно одно:

POST /print
  X-Print-Secret: <секрет>
  X-File-Name: <имя файла>
  <тело — сырые байты документа>

→ lp -d ML1615 <файл>
→ {"ok": true}

Наружу через роутер порт не проброшен, слушается только локалка. Без общего секрета в заголовке сервер отвечает 403. Сам секрет лежит в файле с правами 600. Сверху systemd-юнит с Restart=on-failure.

Связка в Home Assistant

Автоматизация проверяет, что сообщение пришло из нужного чата и в подписи есть «напечатай»:

automation:
  - alias: "Печать документа из Telegram"
    trigger:
      - platform: event
        event_type: telegram_attachment
    condition:
      - condition: template
        value_template: "{{ trigger.event.data.chat_id == <ID вашего чата> }}"
      - condition: template
        value_template: "{{ 'напечатай' in (trigger.event.data.text | default('')) | lower }}"
    action:
      - service: shell_command.print_telegram_file
        data:
          file_id: "{{ trigger.event.data.file_id }}"
          file_name: "{{ trigger.event.data.file_name }}"

А shell-команда берёт у Telegram путь к файлу, скачивает его и отправляет на печать:

shell_command:
  print_telegram_file: >
    bash -c '
    FILE_PATH=$(curl -s "https://api.telegram.org/bot<ТОКЕН>/getFile?file_id={{ file_id }}" | python3 -c "import sys,json;print(json.load(sys.stdin)[\"result\"][\"file_path\"])") &&
    curl -s -o /tmp/tg_print_file "https://api.telegram.org/file/bot<ТОКЕН>/$FILE_PATH" &&
    curl -s -X POST "http://<IP контейнера>:9199/print" -H "X-Print-Secret: <секрет>" -H "X-File-Name: {{ file_name }}" --data-binary @/tmp/tg_print_file
    '

Что получилось

Пересылаю в семейный чат PDF с подписью «напечатай», и лист выезжает из принтера, пока я ещё смотрю в телефон. Работает откуда угодно, где есть Telegram, и никаких VPN и проброшенных портов не понадобилось.

Если вдруг перестанет печатать, смотрю по порядку: дошло ли событие до HA (debug-лог telegram_bot), дошёл ли запрос до сервера печати (журнал его systemd-юнита), а дальше уже CUPS.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *