The Cat Facts Button

So, the other day I got my hands on a Dymo LabelWriter 450 label printer. It’s designed to print address labels and the like, using special rolls of adhesive-backed labels. At its core though, it’s just a fancy thermal printer – like those used to print receipts – so I wondered if I could use it to print on standard receipt paper.

Thankfully, Dymo were one step ahead of me. In their DYMO Label software, there is an option for continuous paper printing, and although they sell their own brand of expensive thermal paper, any paper will work (though there are a couple of caveats – more on that at the end).

I needed some content to test out this functionality, so, of course, I turned to cat facts, and designed a little ticket, which printed nicely from the Dymo software.

And then I had a thought – what if I had a button? A cat facts button.

Oh dear

The plan is fairly simple, we need a button, a database of cat facts, and a way to hook them up to the printer. The button is easy (I’ve got boxes of them), and the database will come later, but patching it all together will be a challenge.

First things first, the Dymo software has to go. I’m sure it’s possible to build a template and pull from a database, but it would likely end up as an unstable mess, and I don’t exactly want to dedicate my laptop to the task. Now, I’m not promising an elegant solution, not even a stable one, but it certainly works and doesn’t rely on a ripped apart mouse and applescript (I didn’t bother writing that project up).

NOTE: I’m recalling everything here from memory, and I’m not particularly good at any of this, so I might accidentally leave something out, or add in extra steps that are unnecessary but I did while troubleshooting. Sorry about that. If anyone is crazy enough to try this and runs into trouble, shout out and I’ll try to give you a hand.

Raspberry Pi to the rescue

I mean, it’s the obvious choice, right? So, I grabbed a pi and loaded it up with raspbian. Step one is to get it talking with the Dymo. Thankfully, Dymo provides Linux drivers and an SDK, but it’s a bit tricky to get it all working (for a n00b like me, at least).

First, we need to install CUPS. This is easy enough. Follow this howtogeek guide, but don’t install the printer just yet. We’ll also need an extra library for the drivers.

$ sudo apt-get install libcupsimage2-dev

Now we’ll need the Dymo SDK. Download it from here, and unzip it somewhere easy to access on the pi. Here’s where I learned that you can SFTP into the pi, without setting anything up – neat!

We’ll head on over to that directory, and compile and install the drivers

$ sudo ./configure
$ sudo make
$ sudo make install

Now we can set up our printer through the CUPS web interface – it’s fairly straightforward. Importantly, make sure to set the default page size to “Continuous, Wide” – that will save you a lot of trouble. I spent ages trying to get things to work specifying the page size every job, this makes things much easier. Also give the printer a simple name, like ‘dymo’. It makes the next step slightly simpler.

Head back to the command line, and make your new printer the default.

# lpadmin -d dymo

Told you it would make things simpler.

With all of that done, we can finally try printing something. Don’t be tempted to start the GUI, load up whatever the TextEdit equivalent is called and print something – the page size will cause headaches, remember?

Now, the Dymo software has some sample programs, but they’re written in C++. I thought about giving it a go, I really did, but it sounded like a bit of a PITA, so we’ll stick with the command line for now. Luckily, we also get sample syntax for printing to the dymo with lpr, but the page size issue creeps up with the samples again, so we’ll keep them for reference now, and just stick with the basics.

$ cd docs
$ lpr test.txt

Success! We can print text!

Let’s get prettier

So, out pi is talking to the printer, and we can print. That’s fine, but I want something a bit nicer. We could give postscript a go, but it’s just easier to render images and send them for printing. I threw together a quick little file in photoshop and sent it to the printer.

$ lpr t.png

Hmm….

So, it prints fine, but there’s a massive bit of space at the top, which we can’t have. I eventually figured out that this was caused by the printer trying to print the image in the centre of the page. Easy fix.

$ lpr -o position=top t.png

Much nicer. However in the process, I’d discovered one more issue: any image shorter than it was wide (I was trying to save paper) was printed out sideways. Oops.

$ lpr -o position=top -o orientation-requested=3 t.png

That’s better.

The button

So, we can print images. Now it’s time to print images on command. One of the reasons I chose the pi for this was because of its GPIO pins – this would make interfacing with a button easy, so I wouldn’t have to resort to sending keyboard commands or some other nonsense.

Now, of course, the major challenge here is that I’ve never used the pi’s GPIO before. But thankfully there’s a tutorials for that, and I get to learn python along the way.

By the way, I was really hoping that the Dymo SDK would have samples in python, but it didn’t. That’s mostly why I ditched the C++ samples – I didn’t want to have to write two pieces of code. We’re not aiming for 100% stability, but we’re not going for precariousness either.

So, all said and done, we’ll need to hook a button up between GPIO pin 20 and +3.3v, and an LED up between pin 21 and +3.3v with an appropriate resistor – I’m using a 410 ohm and it hasn’t blown up yet. No real reason for those pins, other than they are the two at the bottom so I figured it would be harder for me to get lost and short something out.

Oh, actually – let’s have another quick aside. How awesome is Python’s interactive mode? That’s the coolest thing ever!

Back to the project. At this point, I can now print an image at the push of the button. Now, I’m sure there’s ways to print directly from python, but lpr was working on the command line, so we’ll just throw it in here too.

subprocess.call(["lpr", "-o orientation-requested=3", "-o position=top", "r.png"])
print.py (excerpt)

I am positive that there is a better way to do this. But hey, this works I suppose.

Dynamic images?

We’re so close. Push a button, and we can spit out an image from the printer. But, we want that image to be different, random even, on each button press. What to do?

I thought about laying out text in python, but I absolutely did not want to dive into that rabbit hole. I suppose I could have put together a bunch of pre-rendered images and picked one at random, but that was a lot of work. And then I remembered a similar project by James Adam.

HTML. Of course. I know HTML, I know CSS, I know PHP, finally we’re in familiar territory!

Unfortunately, we’re working at a higher level and with a different architecture than James was with his printer, so we can’t just copy his code, but that affords us a few advantages. Firstly, as we’ve already configured, all the image processing and printer communication stuff has been done for us in the drivers. Secondly, we don’t need to worry about separate servers to render the webpage as an image – we can do all that on the pi with a little program called webkit2png.

That’s a perfect name for a piece of software. It tells you exactly what it does – turn a page, rendered by webkit, into a png. Wonderful.

So, we’ll install that and play around until we can get it to work. I’ll just use the web server on my laptop. The default apache homepage provides an encouraging message.

$ webkit2png --output=r.png --cookiepath=. http://dominic.local
$ lpr -o position=top -o orientation-requested=3 r.png

Neato.

So, so close!

I mean, really close. I updated the little python script to run webkit2png before the print, and now a button press triggers the pi to fetch a webpage, render it as a png, and send that png to the printer!

Now we just need to build the web page, and to do that, we’ll need a repository of cat facts.

It seems I’m not the only crazy person on the planet. Ross Delinger has written a little web app to send cat facts via twilio. It’s on github, and there’s a convenient .csv with 170 or so facts. So I stole that. Not sure if that’s dodgy or not, so I haven’t included it in the download. You’ll have to source the catfacts.csv yourself.

Then it’s a simple matter of throwing something together in PHP that pulls a random fact from the file, and we’re good to go.

The CatFacts Button

It works!

But, before I give you the script, there’s a couple of things to mention:

First of all, you’ll probably want to run this in the CLI mode, especially if you want it to run at startup. To do that, we’ll need to run it inside Xvfb, otherwise webkit2png will error out.

$ xvfb-run --server-args="-screen 0, 300x300x24" python print.py

Secondly, keen eyed linux veterans will have noticed that I’ve been running everything in a root shell. That’s just how I roll, but it’s probably not a great idea. RPi.GPIO needs elevated privileges though, so give this a whirl:

$ xvfb-run --server-args="-screen 0, 300x300x24" sudo python print.py

Finally, you’ll likely want to run this as startup so that you can just plug in the pi and have it do its thing. I don’t know how to do that yet, but I’ll update when I do.

Download

Here’s my print.py. It’s not very good, so let me know if you come up with a better way of doing things. But, it does work, which is a start.

By default, it will print cat facts from the orismology.me server, so make sure your pi has an internet connection.

At the start, I mentioned the thermal paper, and that there might be a few things to look out for. As a rule, any thermal paper will work inside the Dymo, provided that it will physically fit width-wise. I think 57mm is a standard size, and it seems to work perfectly. Dymo sells their own brand of paper, and the only difference (other than the price) between it and the standard stuff from officeworks is the size of the core. It’s a lot smaller on standard paper, and won’t fit on the dymo spindle. You’ll need to either re-spool it, or find an alternative way of suspending the roll inside the printer. No biggie, and worth it for the cost savings.

Next Steps

Well, I’m going to make a nice box for the button, but beyond that there’s more that can be done here.

The beauty of this project, is that we can now print anything thanks to our HTML input method, just change the page on the web server, and we change the printer’s output.

If we wanted something more self-contained, it would be fairly trivial to install apache and php on the pi itself and simply request localhost for the content.

Or, we could go in the other direction, and set up a polling system like James did.

For now though, I’m just happy with my little button that prints out cat facts.