TL;DR: https://github.com/ayoy/micropython-thermal-printer.

But I feel like I need to explain the whole thing from the very beginning.

A thermal printer?

So a couple of weeks ago I met with two old friends of mine to take part in the hackaton in Kraków, Poland. The hackaton was actually just an excuse to get together, take a little trip down memory lane, and have some potentially inspiring conversation over drinks. Mind you, we did some coding at the hackaton and even got the prize, but still, the late Saturday beers made the real impact.

That night I learned that there was a guy on the internet that made a thermal printer automatically print tweets he had been mentioned in. It just blew my mind how nicely this matched the definition of hacking, which is, by Wikipedia:

The act of engaging in activities (such as programming or other media) in a spirit of playfulness and exploration

Straight off I wanted to do a similar stuff myself. Not necessarily the Twitter thingy, but the possibilities are infinite. Plus when it comes to tinkering with electronics, in case of a thermal printer, the possible benefits like saving your time or making your life easier are inferior to the coolness of possessing the actual thermal printer.

I mean, do you know anyone that owns a thermal printer for personal use?

What's on the market

The go-to solution is the Adafruit's Mini Thermal Receipt Printer, and it's easily available in Europe too. There's a library for Arduino and Python provided by Adafruit, as well as some example code. At $50 however (or over €60 where I live) I deemed it a bit too pricey for a toy with no real-life application in mind (yet).

There are obviously plenty of thermal printers on AliExpress, so I went there and found one in a similar shape, hoping that it would come with the same internals and communication protocol too. Sacrificing availability for a lower price, I ordered it and patiently waited for the shipment.

4 weeks later

IMG_3101 2

When I unwrapped the package, I noticed that my printer had a different connector than the Adafruit printer. That wasn't a big deal though, as the only outlets you need for a thermal printer are power and serial port. You can even skip the printer TX pin if you won't be checking the paper status. All of these pins were provided on my printer's connector so I was ready to give it a spin.

IMG_3102

First test

I wanted to check if it works with Adafruit C++ library for Arduino. I set up a test circuit with ATMega-328P microcontroller, ran the example code and it worked! Well, sort of.

I could see the paper coming out of the printer, and it had words printed on it. Not all of them though, given what was in the source code. But as you can see from the photo, I powered it using the iPad charger that's reportedly capable of sourcing up to 2A@5V DC.

img_3105.jpg

The printer, according to datasheet needs around 1.5A at 5-9V DC, so technically it shouldn't be a problem. However a friend of mine that bought the same printer at the same time powered it with 8V DC and got a flawless printout, so I knew I needed to sort out the power supply.

In fact, the next day when I connected it to the shiny new 2A 9V DC power adapter, the example code for Adafruit Arduino library worked perfectly fine with all the features listed in the example program, such as printing barcodes, QR codes, and bitmaps.

Having confirmed that my printer works with Adafruit library, I went on to get it working with LoPy from Pycom.

MicroPython

As my WiPy is busy running the air quality monitor, and the LoPy4 hasn't been shipped yet, I managed to borrow two LoPy version 1 boards from a friend – mainly to evaluate LoRa, but also to try out the printer.

Adafruit were generous enough to put up a thermal printer library written in Python, so I based my work on it, and did the following changes to get it running:

  1. removed Python 2.x code since MicroPython is Python 3,
  2. removed writeToStdout(),
  3. replaced Serial with machine.UART,
  4. removed image printing method, because it depended on Python Imaging Library that apparently is not available in MicroPython.

 

[caption id="attachment_255" align="aligncenter" width="497"]IMG_3112 This is what happens when you omit a stop bit.[/caption]

 

Still not bad for the first try ;) The next step was to get the UART's stop bits right, and then it started to look similar to what I saw on the ATMega with Adafruit's library. I then followed up with some improvements, including:

  1. removing support for pre-2.68 firmware – my printer is 2.69 and I don't have older models to test with,
  2. disabling calls to wake() and reset() at initialization because they caused printing garbage in the first line printed after initialization,
  3. fixing sleepAfter() and wake() methods that used printer commands different from those specified in the datasheet. It was either a bug in the original library or a feature of older firmware versions. It might as well work just fine with my printer too, but I was in "check that everything is in line with the datasheet" mode as I was constantly getting some unwanted characters printed out here and there;
  4. parametrizing heat dots and heat interval settings – my printer had different settings than those hardcoded by default in the Python library;
    • there's an API for getting that info: calling testPage() will print the test page (!) that also contains information such as current temperature, operating voltage, firmware version plus heat dots, heat time and heat interval parameters.

And that's how I eventually got it right. The underscored indent before "Large" that is visible in the photo below got fixed in the meantime too.

IMG_3113

Just so you know, printing with the lib is dead simple. For regular text it boils down to just calling println():

from Adafruit_Thermal import *
from machine import Pin

printer = Adafruit_Thermal(pins=(Pin.exp_board.G14,
                                 Pin.exp_board.G15))
printer.println("You just print line by line")
printer.println("using 'println()'")

Text decorations like changing size, alignment, font weight or line spacing are all single-line commands too. There's an example code in the repository printing the text shown in the photos.

Remaining work

I still have to make printing bitmaps work, as my LoPy couldn't manage to do that due to memory allocation problem. It might be a device limitation (it's got 512kB of RAM but I guess some of it is already taken by MicroPython runtime) or a bug in the code, or the combination of those two. I'll give it another try in the next couple of days, maybe I could make a proper use of garbage collector... I'm still learning Python so I could as well be talking bullsh** – I'd appreciate any kind of help or guidance if that hurts your eyes.

UPDATE 2017-12-16: Printing bitmaps is now supported – read more in this blog post.

Disclaimer

I need to point out again that the printer I tested the library with is not the original Adafruit Mini Thermal Receipt Printer so your mileage may vary with their device. Given that I used Adafruit printer's datasheet as a reference and achieved satisfactory results, chances are it would work with their printer too.

If you happen to have that printer and would like to give it a spin with a MicroPython-powered microcontroller then I'd be happy to hear about your experience. And if you don't have the thermal printer yet, I wholeheartedly recommend getting one, as I believe it's a beginning of a great journey ;) Once again, you can get the MicroPython library from GitHub.

Thanks for reading through!