For a recent pet project I needed to add a thermal printer. I decided to go with adafruit mini thermal printer and nodejs, runned by raspberry pi zero. Once you got the printer, you need to setup it. For the tutorial, I presume that you are familiar with NodeJS and basic electronics.
Printer setup
Here is list of products, you will need to make it run:
- Adafruit thermal printer
- Female DC power adaptor
- 5-12V 2Amps power supply – you can buy one from Adafruit, or make your own, but more on that later.
- Thermal paper – 5.56cm wide. Very common one, can be bought from any office supplies store.
- Serial to USB ( UART ) board – you can buy one from Sparkfun( FTDI is good option ). I already had the CP2102 USB to UART Bridge controller by Silicon Labs, so I’m using this in the tutorial. You need it to connect the printer to the USB of the computer. The printer can be connected to Arduino or Raspberry Pi without it, but I prefer to develop on my iMac and use the Raspberry Pi just as production board, so being able to connect the thermal printer to my iMac/Macbook comes in handy.
As I mention, first you need to power the board. Adafruit recommends 5-12V and 1.5-2 Amps DC charger, but I didn’t have one. What I decided to do is just create my own. I used old, non working USB cable and male DC adapter ( $0.50 at any hardware store ). You need to cut the usb cable, remove the data wires ( two in the middle ) and then solder the positive wire ( usually red ) into the inner plate of the adapter, and the ground ( usually black ) to the outer plate of the adapter. Here is a pic:
or you can just use ready usb to DC cable. Many phone charger have output of 5V/2Amps, but USB from a computer is working, too. My iMac outputs just 0.9Amps to the usb, but it is enough to power the printer. If you’re creating your own cable, always measure with multitool if the cables are soldered properly.
We’re ready to power the printer. The printer comes with two sets of cables: red and black for the power and black, yellow and green for communication. Connect the red and black cables to the female DC power adapter. If everything is working, after connecting the female and male power adapters, green light should blink on the printer. Disconnect the power, press and hold the printer button, then connect the power ( while still pressing the printer button ) and it should print system information – examples of different charsets, operating degree, voltage and most importantly – the baudrate ( should be 19200 ), which will be needed by the nodejs.
After successfully running the printer, connect the black, yellow and green data cables to the USB2UART bridge. The black wire should go to ground, the green in RXD and the yellow in TXD.
Great! You can then connect the bridge to the USB, and list it out. On OSX I use two commands to find usb devices:
-
system_profiler SPUSBDataType
– to get list of all plugged USB devices
-
ls /dev/{tty,cu}.*
– to get list of available serial ports. If you see something like /dev/tty.SLAB_USBtoUART, you’re ready to go with NodeJS.
NodeJS Setup
The Packages I’m using are node-serialport for serial data communication, ThermalPrinter for printing and IconV for characters encoding. I needed to install node-serialport using
npm install --save-dev serialport
to install it properly. Create new file and require the libs:
var SerialPort = require('serialport').SerialPort, Printer = require('thermalprinter'), Iconv = require('iconv').Iconv;
It is ready to connect to the printer. Find the printer using ls /dev/{tty}.* and the baudrate ( from the previously printed system information ) and setup it:
var printer; var iconv = new Iconv('UTF-8', 'CP866//TRANSLIT//IGNORE'); //Need this for the cyrillic //Connecting to the serial port var serialPort = new SerialPort('/dev/tty.SLAB_USBtoUART', { baudrate: 19200 }); var printerOptions = { maxPrintingDots: 12, heatingTime : 180, heatingInterval: 180, commandDelay : 0 }; serialPort.on('open', function() { printer = new Printer(serialPort, printerOptions); printer.on('ready', onPrinterReady); }); function onPrinterReady() { //Cyrillic printer.setCharset(8); printer.setCharCodeTable(7); printer.printLine('Hello World').print();}
If you run this, you should see “Hello World” printer with the thermal printer. The printer options we pass are as follows : maxPrintingDots: how many dots will be printed at a time. More dots, faster printing. The heatingTime is interesting – The more heating time, the less speed, but the text looks bolder. All three parameters ( maxPrintingDots, heatingTime and heatingInterval ) takes number from 0-255. Here is test with different heatingTime applied:
After the printer is ready, a charset can be set. For Cyrillic, I use charset ‘8’. Here is list of all available charsets that the printer supports :
0 - CP437 [USA, european standard] 1 - KataKana [Katakana] 2 - CP850 [Multi-lang] 3 - CP860 [Portuguese] 4 - CP863 [Canada - french] 5 - CP865 [Nordic] 6 - WCP1251 [Cyrillic] 7 - CP866 Slavic 2 8 - МИК [Slavic / Bolgarian] 9 - CP755 [Eastern Europe, Latvia 2] 10 - [Iran, Persian] 11 - reserved 12 - reserved 13 - reserved 14 - reserved 15 - CP862 [Hebrew] 16 - WCP1252 [Latin 1] 17 - WCP1253 [Greeсу] 18 - CP852 [Latin 2] 19 - CP858 [1 + european languages, latin symbols] 20 - Иран Ⅱ [Persian] 21 - Latvia 22 - CP864 [Arabic] 23 - ISO-8859- 1 [Western Europe] 24 - CP737 [Greece] 25 - WCP1257 [Baltic] 26 - Thai 27 - CP720 [Arabic] 28 - CP855 29 - CP857 [Turkish] 30 - WCP1250 [Central Europe] 31 - CP775 32 - WCP1254 [Turkish] 33 - WCP1255 [Arabic] 34 - WCP1256 [Arabic] 35 - WCP1258 [Vietnamese] 36 - ISO-8859- 2 [Latin 2] 37 - ISO-8859- 3 [Latin 3] 38 - ISO-8859- 4 [Baltic] 39 - ISO-8859- 5 [Cyrillic] 40 - ISO-8859- 6 [Arabic] 41 - ISO-8859- 7 [Greece] 42 - ISO-8859- 8 [Arabic] 43 - ISO-8859- 9 [Turkish] 44 - ISO-8859- 15 [Latin 9] 45 - [Thai 2] 46 - CP856 47 - CP874
If you try to print cyrillic after just setting the charset, it won’t work. We need one more thing: to send the printer Buffer with converted characters. Because the thermalprinter package does not support converting cyrillic chars to buffer, I’m using IconV package and also extended Printer object. The ThermalPrinter class works like this, it takes array of commands(Buffers) which sends to the printer. So in order to print cyrillic, we just need to add to the commands queue array of commands ( buffers ) we want to print. It’s couple of lines of code:
Printer.prototype.printCyrillic = function(text) { var commands = []; text.split('').forEach(function(char) { commands.push(iconv.convert(char)); }); return this.writeCommands(commands); }; Printer.prototype.printCyrillicLine = function(text) { return this.printCyrillic(text).writeCommand(10); };
Now, we’re able to properly print cyrillic characters! Let’s test it, this is the complete code:
var SerialPort = require('serialport').SerialPort, Printer = require('thermalprinter'), Iconv = require('iconv').Iconv; var printer; var printerIsReady = false; var iconv = new Iconv('UTF-8', 'CP866//TRANSLIT//IGNORE'); var serialPort = new SerialPort('/dev/tty.SLAB_USBtoUART', { baudrate: 19200 }); var printerOptions = { maxPrintingDots: 12, heatingTime : 180, heatingInterval: 180, commandDelay : 0 }; Printer.prototype.printCyrillic = function(text) { var commands = []; text.split('').forEach(function(char) { commands.push(iconv.convert(char)); }); return this.writeCommands(commands); }; Printer.prototype.printCyrillicLine = function(text) { return this.printCyrillic(text).writeCommand(10); }; serialPort.on('open', function() { printer = new Printer(serialPort, printerOptions); printer.on('ready', onPrinterReady); }); function onPrinterReady() { printer.setCharset(8); printer.setCharCodeTable(7); printerIsReady = true; printer.printCyrillicLine('Здравей Свят').print(function(){ process.exit(); }) }
Gotchas
Congrats on printing cyrillic chars with Adafruit’s thermal printer. It’s fun and you can do a lot of creative things with it, but there are some gotchas. Out of the box, you don’t have proper words break, so you have to write our own. The ThermalPrinter library includes images printing, but its broken, so I’m writing my own. Web pages can be printed, but in a hacky way – by creating a screenshot of the page at 384px width and then feeding it as an image to the printer.
I’m currently working on writing a parser that takes certain HTML tags and CSS Styles and converts them to proper printer commands – so you can easily pass html and have it printed out.