Дешёвая и быстрая печать на чековом термопринтере

У нас, айтишников, часто возникает задача напечатать что-то простое и одноразовое — например, логин и пароль новому сотруднику, тикет для монтажника или что-то в этом роде. Тратить бумагу и картридж на подобное очень дорого. При этом есть принтеры с ультрадешёвой скоростной печатью, про которые редко кто вспоминает, хотя видим мы их все каждый день по много раз. Речь про чековые термопринтеры.

cnxzwl9axsgpzkwe7ffc916m2r8.png

Начну, пожалуй, с демки, чтобы вы могли оценить скорость печати — 20 см. в секунду:


(На видео принтер замедляется пару раз в секунду из-за того, что мой скрипт не успевает достаточно быстро засылать команды. Спасибо Тому Скотту за вдохновение:))

Этот принтер я добыл на Авито за полторы тысячи рублей. Модель Citizen CT-S2000, умеет печатать на лентах разной стандартной ширины — от 58 мм до 80 мм. Принтер имел на корпусе следы долгой работы на, кажется, ресторанной кухне, которые удалось оттереть мылом и спиртом. Впрочем, этот принтер фиг убьешь: если термоголовка и отрезной нож исправны, он вам ещё послужит, ломаться там больше особо нечему (а он еще и водостойкий!).

Рулон ленты шириной 80 мм и длиной до ста метров обойдётся вам меньше чем в сто рублей. Ленты 58 мм стоят ещё меньше. Также, т.к. этот принтер печатает нагревая бумагу в определенных местах, ему не нужны картриджи.

omgqh8sv-owk4y02kzmf2epsm3k.png

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

На сайте Citizen был богатый набор вариантов подключения — от нативного драйвера под Windows, PPD для CUPS, и до библиотек для Java. Нам с вами это всё не понадобится, потому что для максимальной простоты и скорости мы не будем рендерить задания на печать на сервере, а лишь будем слать команды принтеру на стандартном языке команд «ESC/POS».

Но сначала нам нужно один раз провести настройку принтера. Citizen предлагает настроить принтер через меню, которое он вам печатает (!) — экрана-то у него нет, или воспользоваться утилитой под Windows.

У моего принтера имеются интерфейсы USB и COM на 25 pin, под который не удалось быстро найти переходник с 9 pin — поэтому пользуемся USB. Драйвер под Windows установил виртуальный COM-порт, который мы выбираем в утилите настройки.

Внимательно просмотрите все параметры — нужно проверить тип бумаги (наклейки или обычная) и указать ширину заправленной в принтер ленты. Остальные настройки, типа яркости печати, тона встроенной пищалки и прочего — на ваш вкус.

bmvlz5w7tgztgtkuaiehv7qqffe.png

Чтобы не забивать себе голову синтаксисом языка ESC/POS, воспользуемся Python-библиотекой python-escpos. В моём случае принтером управляет одноплатный компьютер Orange PI PC с Debian, но настройки в любой ОС будут идентичны.

Командой lsusb узнаём ID принтера, в моём случае это был 2730:0fff:

# lsusb
Bus 006 Device 002: ID 2730:0fff Citizen

Также нам нужно выяснить USB endpoints, для этого подставляем ID в команду:

# lsusb -v -d 2730:0fff | grep bEndpointAddress
        bEndpointAddress     0x81  EP 1 IN
        bEndpointAddress     0x02  EP 2 OUT

Запоминаем полученные значения и создаём тестовый скрипт на Python:

from escpos import Usb
p = printer.Usb(0x2730, 0x0fff, 0, 0x81, 0x02)

Если ваш принтер есть в списке явно поддерживаемых библиотекой, например, Epson TM-T88III, то можно применить его профиль, где авторы явно прописали, что из возможностей поддерживается, а что — нет. Почитать документацию по подключению принтеров можно тут.

Пользование библиотекой — тривиально, она полностью избавляет вас от изучения ESC/POS:

""" Выбор встроенного шрифта, выравнивания, размера """
p.set(font='a', align=u'left', height=3)

""" Печать картинки (помните про ширину ленты и DPI!) """
p.image('/home/test/example.png')

""" Вывод текста (кириллицей-только если поддерживает принтер,
иначе лучше напечатать текст на картинке и печатать ее) """
p.text("Hello, world!\n")

""" Генерация QR-кода """
p.qr("https://gbougakov.dev", size=5, center=True)

""" Генерация бар-кода (читайте Википедию, чтобы 
правильно вычислить checksum) """
p.barcode('1324354657687','EAN13')
p.barcode('123456', 'CODE39')

""" Программная генерация бар-кода – если ваш принтер 
не умеет генерировать нужный тип аппаратно """
p.soft_barcode('code39', '123456')

""" Надрезать ленту: """
p.cut(mode='PART')

""" или отрубить напечатанный кусок целиком: """
p.cut()

""" послать напряжение на разъём для денежного ящика кассы
(обычно под них выведено два контакта в разъёме RJ-25): """
p.cashdraw(2)
p.cashdraw(5)

Про последнюю команду — чуть поподробнее. На всех чековых принтерах выведен разъём, который отвечает за то, что сразу после выбивания чека у кассира сам открывается ящик, куда он складывает полученные от вас деньги. Стандартное напряжение — 24 вольта, ток — до одного ампера.

flyjoi6utsdogrun5gj4ksho0di.png

Не пытайтесь от него запитать Raspberry Pi или что-то подобное — в момент печати принтер обесточивает разъём. Так что для того, чтобы запитать, например, стрелку из светодиодов «возьми чек тут!» — сойдёт, но не более.

Напоследок — пример применения. В прошедшие выходные моя школа праздновала свой очередной день рождения (аж 143-й), и по традиции старшеклассники устраивали разные конкурсы и развлечения для младших классов и выпускников. Я отвечал за «Бинго» — мой принтер по нажатию кнопки печатал билеты для игроков, а на доску выводились цифры. QR-код на билете позволял проверить, правильно ли игрок вычеркнул цифры в процессе игры:

n13azbda_konmwmibflra_g6vgu.jpeg

Для вандалоустойчивости Orange Pi был упрятан в фанерный подиум, накрепко прикрученный к принтеру, а команда на печать билетов была выведена на кнопки, подключённые к GPIO. Для подстраховки был добавлен I2C-экран, на который выводился IP-адрес Orange Pi, чтобы в случае чего знать, как зайти на него по SSH.

© Habrahabr.ru