mmote.ru/content/posts/niimbot-proto/index.md
MultiMote 8e798a4832
Some checks failed
Build and deploy mmote.ru / Build-And-Deploy (push) Has been cancelled
niimbot-proto
2024-07-28 23:10:28 +03:00

12 KiB
Raw Blame History

title description date draft tags categories featured_image lastmod telegram_entry_id type
Изучаем протокол принтеров Niimbot Изучаем протокол принтеров Niimbot и печатаем этикетки, отправляя пакеты 2024-06-29T21:10:28+03:00 false
bluetooth
niimbot
термопечать
Niimbot B1
Niimbot B110
реверс-инжиниринг
javascript
typescript
web
reverse-engineering
miniature.jpg 2024-07-28T23:10:05+03:00 default

После того, как поигрались с niimprint, захотелось чего-то большего. У меня появилась идея написать полноценный веб-интерфейс для печати, в котором можно будет и рисовать этикетки, и печатать. Для этого я решил изучить протокол принтеров.

ПРЕДУПРЕЖДЕНИЕ

Данный проект предназначен только для ознакомительных и образовательных целей. Проект не связан с компанией Niimbot, не поддерживается ей и не предназначен для использования в коммерческих целях без согласия владельца.

Структура пакета

Сейчас в моём владении два принтера D110 и B1. Вооружившись Wireshark и Android телефоном, снял дампы обмена данными с принтером по bluetooth. Для этого нужно было включить опцию "Bluetooth HCI Snoop Log" в настройках разработчика, а потом на компьютере после печати запустить adb bugreport <filename>.

Изучив пакеты и сверившись с другими открытыми источниками, получилась такая структура пакета:

niimbot packet

  • Prefix префикс 0x03, присутствующий только при одной команде - Connect.
  • Head всегда 2 байта 0x55 0x55.
  • Command ID команды (пакета).
  • Data length количество байтов данных, идущих далее.
  • Data непосредственно данные в количестве Data length.
  • Checksum вычисляется с помощью XOR всех байтов от Command до последнего байта Data.
  • Tail всегда 2 байта 0xAA 0xAA.

Типы пакетов

На данный момент мне удалось идентифицировать следующие типы пакетов:

ID команды Наименование ID ответа
0x01 PrintStart 0x02
0x03 PageStart 0x04
0x05 PrinterLog 0x06
0x0b AntiFake 0x0c
0x13 SetPageSize 0x14
0x15 PrintQuantity 0x16
0x1a RfidInfo 0x1b
0x1c RfidInfo2 0x1d
0x20 PrintClear 0x30
0x21 SetDensity 0x31
0x23 SetLabelType 0x33
0x27 SetAutoShutdownTime 0x37
0x28 PrinterReset 0x38
0x40 PrinterInfo 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e
0x54 RfidSuccessTimes 0x64
0x58 SoundSettings 0x68
0x70 GetVolumeLevel / WriteRFID 0x71
0x83 PrintBitmapRowIndexed ⚠ Без ответа
0x84 PrintEmptyRow ⚠ Без ответа
0x85 PrintBitmapRow ⚠ Без ответа
0x8e LabelPositioningCalibration 0x8f
0xa3 PrintStatus 0xb3
0xa5 PrinterStatusData 0xb5
0xaf PrinterConfig 0xbf
0xc1 Connect 0xc2
0xda CancelPrint 0xd0
0xdc Heartbeat 0xdd, 0xdf, 0xde, 0xd9
0xe3 PageEnd 0xe4
0xf3 PrintEnd 0xf4

Далее рассмотрим основные пакеты подобнее.

0x01 PrintStart

Начало последовательности пакетов для печати. Формат данного пакета отличается в разных версиях протоколов. Варианты:

  • V1. 1 байт данных. Пример: 0x01.
  • V3. 2 байта данных. Итоговое количество страниц. Пример: 0x00 0x02 (2 страницы)
  • V4. 7 байта данных. Пример: 0x00 0x02 0x00 0x00 0x00 0x00 0x00 (2 страницы)
    • 2 байта - итоговое количество страниц.
    • 4 байта - всегда нули.
    • 1 байт - цвет страницы (назначение неизвестно).
  • V5. 8 байт данных. Пример: 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 (2 страницы)
    • 2 байта - итоговое количество страниц.
    • 4 байта - всегда нули.
    • 1 байт - цвет страницы (назначение неизвестно).
    • 1 байт - вероятнее всего, плотность.

Возвращается ответ с ID 0x02. Данные ответа (1 байт):

  • 0x01 - успех
  • 0x00 - ошибка

Важно знать

Протокол обмена данным варьируется между разными моделями

В основном это касается набора пакетов при непосредственно печати. Изучив код приложения, можно сделать вывод, что есть пять вариаций протокола + вариации для самих моделей.

proto files

Вероятно, протокол обмена данными может варьироваться даже в пределах ревизий одной модели

Это можно увидеть в декомпилированном коде приложения:

protocol tasks

Принтер искусственно занижает плотность печати при использовании неправильной или отсутствующей RFID метке

Вот тут довольно интересно. Принтеры и приложения ведут себя по разному.

Метки нет вообще:

  • Niimbot Android
    • Этикетку создать невозможно в принципе.
  • Niimbot Windows
    • D110 - не поддерживается, хоть и может печатать по usb.
    • B1 - печатать можно, игнорируя предупреждения, плотность очень низкая.
  • Сторонние проекты
    • D110 - печатает без проблем с нужной плотностью.
    • B1 - печатает с низкой плотностью.

Метка есть, но от бумаги размером, который не поддерживается принтером:

  • Niimbot Android
    • D110 - печатать можно, игнорируя предупреждения, плотность очень низкая (подлость самого приложения).
    • B1 - аналогично с D110.
  • Niimbot Windows
    • D110 - печатать можно, игнорируя предупреждения, плотность очень низкая.
    • B1 - печатать можно, игнорируя предупреждения, плотность очень низкая.
  • Сторонние проекты
    • D110 - печатает без проблем с нужной плотностью.
    • B1 - аналогично с D110.

Что касаемо самой метки - считывание происходит при закрытии крышки. Принтер видит метку даже если она снаружи корпуса. Так что можно просто приложить метку снаружи, закрыть корпус и печатать на чём попало.

Источники

  • Тут и тут нашлась библиотека jcprintersdk для Java. Библиотека обфусцирована.

  • kjy00302/niimprint - утилита на Python для печати изображений на принтерах niimbot.

  • AndBondStyle/niimprint - доработанный форк niimprint. Также благодаря автору и человеку с неизвестным мне ником удалось получить актуальную версию jcprintersdk с низкой обфускацией путём декомпиляции Android приложения.

  • ayufan/niimprint-web - малофункциональный, но полезный проект печати через браузер.