# lx-d02 Печать на Bluetooth-термопринтере **LX-D02** (он же Funny Print, Xiqi, DOLEWA и другие бренды) без приложения на смартфоне: - **как на обычном принтере Windows**: из Блокнота, браузера, Word, из меню «Печать»; - **картинки правым кликом** в проводнике, растянутые на всю ширину ленты; - **из командной строки**: `python lxd02.py "Привет"`; - **из Home Assistant**: действие `lxd02.print_text` с очередью, которая переживает выключенный принтер и перезапуск HA. Принтер работает только по BLE (Bluetooth Low Energy): USB-порт у него лишь для зарядки, и Windows без этого проекта его как принтер не видит. Протокол разобран в [ValdikSS/printer-driver-funnyprint](https://github.com/ValdikSS/printer-driver-funnyprint), управление потоком сделано по образцу [klimromanyuk/funnyprint](https://github.com/klimromanyuk/funnyprint). Подробный рассказ, как это сделано: [блог «Доктор Лексиум»](https://www.lexium.ru/). ## Что нужно - Python 3.9+ и Bluetooth на компьютере. - `pip install -r requirements.txt` - Принтер включён и **не подключён к телефону**: LX-D02 держит только одно соединение, и пока открыто Funny Print, компьютер его не найдёт. Проверка: `python lxd02.py "Привет"` должен напечатать строку. На Python 3.9 bleak 1.x падает при импорте, поэтому в `requirements.txt` стоит `bleak<1.0`. На более новом Python ограничение можно снять. ## Печать из командной строки ``` python lxd02.py "Первая строка" "Вторая строка" python lxd02.py фото.jpg скриншот.png ``` Текст печатается шрифтом DejaVu Sans (кириллица есть). Картинки растягиваются на ширину ленты (48 мм, 384 точки), альбомные поворачиваются вдоль ленты, чтобы выйти крупнее, полутона передаются растром. Принтер ищется по имени `LX-D02`. Чтобы не тратить на поиск несколько секунд, задайте MAC: `set LXD02_MAC=AA:BB:CC:DD:EE:FF` (MAC покажет любой BLE-сканер, например nRF Connect на телефоне). ## Принтер в Windows Как это устроено: Windows печатает на принтер с драйвером **POS-58** (стандартный драйвер 58-мм чековых принтеров), драйвер раскладывает страницу на ленту 58 мм и отдаёт её командами ESC/POS в порт `127.0.0.1:9100`. Там их принимает `windows/print_server.py` и печатает по Bluetooth. Почему не встроенные драйверы Windows: «Microsoft Print to PDF» знает только офисные форматы, и лист A4, ужатый до 48 мм, нечитаем. IPP Class Driver принимает только стандартные названия бумаги, самое узкое из которых A6. ### Драйвер Драйвер POS-58 обычно идёт с любым дешёвым 58-мм чековым принтером, ищите «POS-58 driver» на сайте Xprinter или продавца. Проверено с `POS-58 11.2.0.0` (Zjiang, `pos58.inf`). Сам принтер POS-58 не нужен, нужен только драйвер. ### Установка В PowerShell **от имени администратора**: ```powershell Set-ExecutionPolicy -Scope Process Bypass .\windows\install.ps1 ``` Скрипт: - добавляет принтер **LX-D02** на драйвере POS-58 и порту `127.0.0.1:9100`; - ставит в Планировщик задание «LX-D02 print server» (сервер стартует при входе в систему); - добавляет в меню картинок пункт «Print on LX-D02» и ярлык в «Отправить». Удаление: `.\windows\install.ps1 -Uninstall`. Журнал: `windows\print_server.log`. ### Советы - **Бумага.** У драйвера по умолчанию лента 3276 мм. Пусть вас не пугает превью: сервер срезает белое сверху и снизу и сжимает пустые промежутки до 6 мм. Для удобного превью выберите в настройках печати размер 58×210. - **Поля.** Ставьте поля «Минимальные» (в браузере) или 0 (в редакторах). Левое поле сервер убирает сам, но правое срежет драйвер: печатная полоса 48 мм начинается от левого края листа, а браузер с обычными полями сдвигает текст вправо. - **Картинки** лучше печатать правым кликом, а не из браузера или «Фотографий»: те раскладывают картинку по листу, и она выходит мелкой или обрезанной. - Странный результат? Последнее задание сохраняется в `windows\last_job.bin`, `python windows\print_server.py --test windows\last_job.bin` покажет его картинкой. ## Home Assistant Нужен Bluetooth на хосте HA (встроенный адаптер или прокси ESPHome). Скопируйте `custom_components/lxd02` в `/config/custom_components/`, добавьте в `configuration.yaml` и перезапустите HA: ```yaml lxd02: mac: AA:BB:CC:DD:EE:FF ``` Действие: ```yaml action: lxd02.print_text data: text: "Привет из Home Assistant" size: 28 # размер шрифта, 10..120 density: 3 # плотность, 0..7 feed: 40 # прогон ленты после текста separator: true # линия под текстом ``` Задания попадают в очередь на диске (`/config/.storage/lxd02`). Если принтер выключен, вне зоны или занят телефоном, задание ждёт, и очередь печатается, как только HA снова увидит принтер. Пока очередь не пуста, HA пробует раз в минуту. Действие не падает, если принтера нет: ищите `LX-D02` в журнале HA. ### Пример: чат MeshCore на ленте Печатает входящие сообщения канала `my_channel` из интеграции MeshCore: отправитель и время, ниже текст, под ним черта. Свои исходящие пропускаются: интеграция присылает их заново на каждое обновление статуса доставки. ```yaml triggers: - trigger: event event_type: meshcore_message event_data: message_type: channel conditions: - condition: template value_template: "{{ trigger.event.data.channel | lower == 'my_channel' and not trigger.event.data.outgoing | default(false) }}" actions: - action: lxd02.print_text continue_on_error: true data: size: 24 separator: true text: "{{ trigger.event.data.sender_name }} · {{ now().strftime('%d.%m %H:%M') }}\n{{ trigger.event.data.message }}" mode: queued max: 20 ``` ### Если Bluetooth на хосте зависает На ТВ-приставках встроенный чип раз в несколько недель может зависнуть (`hci0: Opcode 0x0c03 failed: -110` в `dmesg`, HA пишет `NotReady`). Помогает перепривязать чип к драйверу. Пример сторожа на systemd для чипа на UART (`hci_uart_bcm`): ```sh #!/bin/sh # /usr/local/sbin/bt-watchdog.sh: run every minute by bt-watchdog.timer D=/sys/bus/serial/drivers/hci_uart_bcm up() { hciconfig hci0 2>/dev/null | grep -q "UP RUNNING"; } up && exit 0 sleep 20 # HA/BlueZ may be resetting the adapter itself up && exit 0 logger -t bt-watchdog "hci0 down, rebinding serial0-0" echo serial0-0 > $D/unbind 2>/dev/null sleep 2 echo serial0-0 > $D/bind sleep 8 timeout 5 bluetoothctl power on >/dev/null 2>&1 ``` Имена драйвера и устройства у вас могут отличаться: смотрите `/sys/bus/serial/drivers/`. ## Протокол коротко | | | |---|---| | Имя в BLE-рекламе | `LX-D02` | | Сервис / запись / уведомления | `FFE6` / `FFE1` / `FFE2` | | Ширина печати | 384 точки, 48 байт на строку, по две строки в пакете из 96 байт | | Рукопожатие | принтер шлёт вызов `5a0a`, ответ `5a0b` + байт CRC16 от MAC × 10 | | Управление потоком | `5a08` пауза (буфер полон), `5a05` + номер строки (дослать с неё), `5a06` готово | Весь протокол: `custom_components/lxd02/printer.py`, самопроверка `python printer.py`. ## Лицензия MIT, см. `LICENSE`.