Getting a USB receipt printer working on Linux

In this post, I’ll step through how to get a thermal receipt printer with USB interface appearing on Linux. The aim of this is to be able to point a driver such as escpos-php at the device. The printer used here is an Epson TM-T20, which is very common in point-of-sale environments.

I have previously written quite a bit about how to use thermal receipt printer protocols, but the previous printer I covered had only a network interface, not USB like this one:

2015-03-printer-back
2015-03-printer-top

The directions below are for Debian, but could be adapted for any other Linux.

Find the device file

Plug in your printer, and check that usblp sees it:

dmesg
[12724.994550] usb 8-4: new full-speed USB device number 5 using ohci-pci
[12725.168956] usb 8-4: New USB device found, idVendor=04b8, idProduct=0e03
[12725.168963] usb 8-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[12725.168968] usb 8-4: Product: TM-T20
[12725.168971] usb 8-4: Manufacturer: EPSON
[12725.168975] usb 8-4: SerialNumber: ....
[12725.175114] usblp 8-4:1.0: usblp1: USB Bidirectional printer dev 5 if 0 alt 0 proto 2 vid 0x04B8 pid 0x0E03

This kernel module makes your printer visible as a device file, so that it can be accessed in the old-fashioned way. Find the new device file under /dev/usb:

ls /dev/usb

In my case, this was /dev/usb/lp1. The next step is to see if you can write to it:

echo "Hello" >> /dev/usb/lp1

Chances are, you will get a permission denied error at this point, so find out what group the printer is in:

stat /dev/usb/lp1

Which will show output something like:

File: ‘/dev/usb/lp1’
  Size: 0         	Blocks: 0          IO Block: 4096   character special file
Device: 5h/5d	Inode: 220997      Links: 1     Device type: b4,1
Access: (0660/crw-rw----)  Uid: (    0/    root)   Gid: (    7/      lp)
...

This file is owned by group lp (“line printer”). If your username was bob, you would add yourself to this group using:

sudo usermod -a -G lp bob

If you plan to build a web-based point-of-sale system with this, then also add the www-data user to that group.

Now log out and back in, and the previous test should now be working:

echo "Hello" >> /dev/usb/lp1

Troubleshooting: Check usblp

If these steps don’t work, then your computer ether doesn’t have, or isn’t using usblp You’ll need to check a few things:

  • Install a different linux-image if the driver is not on your computer at all.
  • modprobe or insmod usblp
  • blacklist a vendor driver which has claimed the interface.
    • run lsusb -v and usb-devices (look for driver=)

Printing something useful

As a duplicated section from my earlier post, the printer uses ESC/POS, which means it accepts plaintext with some special commands for formatting.

A simple receipt-generator, foo.php, might look like this:

<?php
/* ASCII constants */
const ESC = "\x1b";
const GS="\x1d";
const NUL="\x00";

/* Output an example receipt */
echo ESC."@"; // Reset to defaults
echo ESC."E".chr(1); // Bold
echo "FOO CORP Ltd.\n"; // Company
echo ESC."E".chr(0); // Not Bold
echo ESC."d".chr(1); // Blank line
echo "Receipt for whatever\n"; // Print text
echo ESC."d".chr(4); // 4 Blank lines

/* Bar-code at the end */
echo ESC."a".chr(1); // Centered printing
echo GS."k".chr(4)."987654321".NUL; // Print barcode
echo ESC."d".chr(1); // Blank line
echo "987654321\n"; // Print number
echo GS."V\x41".chr(3); // Cut
exit(0);

And you would send it to the printer like this:

php foo.php > /dev/usb/lp1

Scaling this up

The codes are quite tricky to work with manually, which is why I put together the escpos-php driver. You can find it at:

The above example would be written using escpos-php as:

<?php
require __DIR__ . '/autoload.php';
use Mike42\Escpos\Printer;
use Mike42\Escpos\PrintConnectors\FilePrintConnector;
$connector = new FilePrintConnector("/dev/usb/lp1");
$printer = new Printer($connector);

/* Print some bold text */
$printer -> setEmphasis(true);
$printer -> text("FOO CORP Ltd.\n");
$printer -> setEmphasis(false);
$printer -> feed();
$printer -> text("Receipt for whatever\n");
$printer -> feed(4);

/* Bar-code at the end */
$printer -> setJustification(Printer::JUSTIFY_CENTER);
$printer -> barcode("987654321");
$printer -> cut();
?>

This would be sent to the printer by loading it from the web, or running the script on the command-line:

php foo2.php

40 Replies to “Getting a USB receipt printer working on Linux”

  1. Hi Mike,

    Heard that usblp is no longer and its depreciated. I have updated my version and now this is not working. How can this be resolved?

    Regards,
    Sharanga.

  2. As a note, I needed to restart web server after adding the lp group to www-data user. (Epson TM-88V).

  3. Hi, according Tod Euro sign issue 39 I habe used your custom charset custom850!

    It Sprints only two of the for currency symbols of your test, the Euro sign Saint part oft it …

  4. Thanks for your work on this. It works a treat on my CBM 1000II which has a built in USB interface. Only thing that would make it complete would be a dithered ‘greyscale’ image print rather than the one in place currently.

  5. Hello !, I’m working on PHP with my printer EPSON, I need to make a cut but can not. I can not implement ESC / POS business rules, but I would like to know how they can cut where I form by sending the ticket. Thank you very much!

  6. Worked fine for me.

    Currently forming part of a staff in/out list, using two cheap thermal printers, CUPS remote printing and your instruction / scripts above.

  7. Hallo Mike,
    Many thanks for that. I do, however, get an error with my ZJ-5890C: Barcodes and graphics (tried with your github code) just won’t work. Barcodes are just blank (or, its contents are printed as characters), and logos will print a few pixels, then stop and print “0p01L02” as text.
    Any hint would be greatly appreciated.
    Thanks.

  8. You can create a simple script to be able to print TXT files or dump text to the printer using copy&paste:

    unix2dos | iconv -c -f UTF-8 -t 437 > /dev/usb/lp0

    I named my script “thermo” and deposited it into /usr/bin.

    Now you can just copy your text and then type “thermo” into a console and press “Shift+Ins” and/or type whatever you want to print. Then press “Enter” and “Strg+d” to stop editing and start printing.

    unix2dos makes sure the printer receives CR+LF at every new line.
    iconv simply translates UTF8 into the common printer default codepage 437. The -c option makes sure that characters which can’t be printed are ignored rather than cause an error and stop. You might want to create a “thermotest” script without -c and actual printer output to make sure all characters can be printed before you attempt to print.

    You might also want to reformat a text file to match the short lines of the printer. I have called mine “thermof” (thermoFormated):

    fmt -cu -w32 –goal 30 | unix2dos | iconv -c -f UTF-8 -t 437 > /dev/usb/lp0

    fmt will eliminate line wraps which don’t match with your printer width and add new ones at the correct positions. You need to adjust the -w parameter to the width of your own printer (mine is obviously 32 characters wide). You can use –goal to make the print more dense to safe paper rather than more easy to read. A goal of 2 characters less than the printer width gives you maximum density

    Cowsay can accomplish the same as fmt but not as good. But it prints a nice ASCII-Art box around your text. I use this script I call “thermotux” to print short messages to coworkers:

    cowsay -W28 -f tux | unix2dos | iconv -f UTF-8 -t 437 -c > /dev/usb/lp0

    The problem is that cowsay removes all blank lines and combines lines even separated by multiple CR so while it is nice to print out adresses, phone numbers and brief memos, it can’t be used to print proper lists or even tables!

  9. On the site: “https://github.com/mike42/escpos-php”, your link for “Getting a USB receipt printer working on Linux” doesn’t work.

    The used link is: “http://s//mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux”, it should be “http://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux”.

  10. Hi mike…. help me please… :)

    Mike, i have write foo.php and located it at /var/www/html/foo.php

    I have execute foo.php using console like this command :
    php foo.php > /dev/usb/lp0
    and result is SUCCES. My Epson Printer TM220 can do printing and cut paper automatically.

    Then… i try printing by loading foo.php using browser.
    This is the problem; Printer is not printing the receipt, but in the screen appear information like this
    @EFOOCORP Ltd. EdReceipt for whatever dak987654321d987654321VA

    Mike… how can i do printing foo.php by loading it by browser.

    Thanks for u’r help

  11. @nky – It sounds like you need to check out the example foo2.php, also on this post, which will print directly to a file using the escpos-php library. Best of luck!

  12. Hi Mike,
    I am using TSC TTP 345 printer to print barcode. And I am unable to print.
    What is the possible problems ?
    Any help ………..

  13. I have android app which doesn’t have option for usb printer… but it can easily print by ip address… my printer is working fine on usb or Ethernet but is there any way that I can place some usb address at place of ip address to make it work for usb only.

  14. I tested this with an XP-58III with usb interface. Works well, now i just need a good POS software. Thank you for this article! Helped me a lot

  15. Hi Mike,
    I have a question. I downloaded the files at GitHub address. However, when I try to interpret the file “demo.php” on Linux (php demo.php) I obtain a series of errors. In particular the list is the following:

    PHP Fatal error: Uncaught Error: Call to undefined function Mike42\Escpos\PrintBuffers\mb_detect_encoding() in /var/www/html/Print/src/Mike42/Escpos/PrintBuffers/EscposPrintBuffer.php:95
    Stack trace:
    #0 /var/www/html/Print/src/Mike42/Escpos/Printer.php(979): Mike42\Escpos\PrintBuffers\EscposPrintBuffer->writeText(‘Hello world\n’)
    #1 /var/www/html/Print/example/demo.php(23): Mike42\Escpos\Printer->text(‘Hello world\n’)
    #2 {main}
    thrown in /var/www/html/Print/src/Mike42/Escpos/PrintBuffers/EscposPrintBuffer.php on line 95

    Can you please help me?
    Regards, Gianluca

  16. @Amir- Good question, I’ve got no idea. Things that come to mind include writing your own app using an Android USB API, or use a raspberry pi as a networked print server.

  17. Te mamaste carnal, neta me hiciste el paro con esto, me funciono de maravilla con una xprinter XP-Q200II POS-80.

  18. Hi Mike,

    I am extremely new both to POS printers and Linux: I’ve an IBM model 4610-2CR with RS-232 interface card which I tried connecting it to a raspberry pi 3 through usb to serial cable that includes FTDI chip. Whenever I enter the ‘dmesg’ in terminal, my printer doesn’t appears but it seems like FTDI-chip-cable does. I am not sure how to proceed any further.

  19. I have Zijiang ZJ-58 printer.i cannot connect my printer with my php codiegniter project . its showing an error like – failed to open strean(dev/usb/lp0. no such file or directory available. i want to connect this settings globally.

  20. Hello Mike,
    i hope that everything’s going well with you,
    please i have linux mint and i need to install the
    SPRT POS88VUF receipt printer on it.
    but the driver doesn’t work.

  21. These steps really apply to printers that are recognised by usblp, where you are providing your own print commands. If you’re having trouble deploying a vendor-provided driver, then you should probably contact the vendor for support.

  22. You can install it in CUPS as a raw device and then just lp -d Epson [textfile] (or possibly cat text | lp -d Epson) That’s how I talk to my Eltron printers in EPL2. In CUPS web interface it’s under “Make: Raw”, but in gnome-print it’s “Choose Driver: Generic” then “Raw Queue”.

  23. Hi Mike,
    I have a server using the rasberry pie having the database (WAMP Server) and my printer is connected and shared through the network using a window PC (192.168.0.113) and USB port at USB003.

    My POS system is the rasberry pie (192.1686.0.2). I run the software from the PC (192.168.0.113) where the printer is installed together.

    Is it possible for me to print at the windows pc and running the POS system (PHP) from the rasberry pie server?
    I had completed tested with the local windows only and it works. Currently I’m exploring for the networking printer.

    Thanks

  24. @Zamani – Absolutely. You need to share the raw printer on the Windows side, then install smbclient and try printing some text files over the network on the Linux side. Make sure that it all works, then use a WindowsPrintConnector from escpos-php to achieve the same result.

  25. Hi Mike,
    :) It takes me the whole day to finally succeed on printing over the network. THanks so much on the guide and the shared codes.

    Anyway, i have another question since I’m testing on another pc which has no password for login for Win10. I had check the cmd prompt and the name is user @administrator vs mine PC for debugging (having its name and its password). I also check the computer name and key in together This is the part where I had edited but still not able to print over the network using the line below and tested one by one.

    $connector = new WindowsPrintConnector(“smb://n1tr0/XP-80C”);
    $connector = new WindowsPrintConnector(“smb://Guest@n1tro/XP-80C”);

    Is there any potential problem on this line?

    // this is from github
    // Enter the share name for your printer here, as a smb:// url format
    //$connector = new WindowsPrintConnector(“smb://computername/Receipt Printer”);
    //$connector = new WindowsPrintConnector(“smb://Guest@computername/Receipt Printer”);
    //$connector = new WindowsPrintConnector(“smb://FooUser:secret@computername/workgroup/Receipt Printer”);
    //$connector = new WindowsPrintConnector(“smb://User:secret@computername/Receipt Printer”);

  26. Hi Mike,
    It took me 2 days to finally complete the debugging!! :)
    So much appreciate it .. as without your sharing, i do not think that i can achieve the goal…

    Thousand and million thanks!
    Z

  27. Hi Mike

    Great write-up. I have an ESCPOS compatible dot matrix printer I’m trying to hook up to a slitaz 4.0 machine. The catch is that the printer does not have a USB port and my laptop doesn’t have a serial port – instead I’m using a serial to USB adaptor.

    dmesg is showing the adaptor:

    usbcore: registered new interface driver usbserial
    USB Serial support registered for generic
    usbcore: registered new interface driver usbserial_generic
    usbserial: USB Serial Driver core
    USB Serial support registered for pl2303
    pl2303 2-2:1.0: pl2303 converter detected
    usb 2-2: pl2303 converter now attached to ttyUSB0
    usbcore: registered new interface driver pl2303
    pl2303: Prolific PL2303 USB to serial adaptor driver

    However usblp cannot see it – any suggestions?

  28. @Ryan – For USB/Serial, the OS does not know that the adapter is being used for a printer, so usblp wont kick in.

    Look into the stty command, and see if you can find a device file appearing when you plug in the adapter. The last serial/USB adapter that I used appeared as /dev/ttyUSB0.

  29. Hi Mike,

    Nice write up.
    My question is: is it possible to read status responses from an EPSON compatible printer connected on /dev/usb/lp0.
    I can print ok but reading from /dev/usb/lp0 just hangs
    lsusb -v shows interface as bi-directional.
    I have no problems doing this on the serial port that is also available on the printer

  30. Hello Mike.
    I am still getting this error in browser even if i followed all guide.
    In terminal, I can print test characters.
    But in browser, it still says “Permission denied error”
    For web user, I setted like this.
    sudo usermod -a -G lp www-data.
    If have solution, please help me thanks.

  31. Thank you very much, Mike.
    I spent days trying to get my Raspberry Pi to talk to a printer. It’s trivial under Windows and MS-DOS, but not Linux! The essential command
    sudo usermod -a -G lp pi
    seems to be missing everywhere else.
    I had to reboot before
    echo “Hello” >> /dev/usb/lp0
    worked.
    I used CUPS to install a generic driver for my HP LaserJet P2035

  32. Hello Mike
    I’m trying to get an XPrinter XP-365B to work connected on a RaspberryPi with Ubuntu 20.04 LTS. When I connect the USB cable it recognizes the printer correctly, yet when I try the “echo “Hello Printer” >> /dev/usb/lsp0″ it does nothing at all. No error message but it also doesn’t print.
    I have added the user to the group lp that the printer is in, rebooted the Raspi, the printer, reconnected it a few times but nothing.
    Is that a limitation of the ARM linux on the RaspberryPi or is there something else wrong? Do you have any ideas where I could start troubleshooting? The Raspberry Pi doesn’t have a GUI installed, it’s the console only.

    Surprisingly, it’s similar when I tried to print using your RawBT app from my Android phone. I can connect and pair the printer, but whenever I try to print from your app, it shows the print icon in the top status bar, but then nothing happens.

  33. I use the linux platform (server), but the printer is connected and shared on windows, I need to use the windowsPrintconnector class, how do I do it?

  34. Mike, question for you.
    I have followed your steps. I was able to install my printer in linux with the proper driver, found it in cups, can print a linux test page, reprint said test pages from Cups, got the permissions error, added my user but cannot print using the echo “Hello” to the printer via /dev/usb/lp0.

    It does nothing.
    Any thoughts?

Leave a Reply

Your email address will not be published. Required fields are marked *