Sales@CyberCityCircuits.com

Printing Receipts with Python and PySerial

Screenshot 2023-02-19 at 8.17.05 PM

Let’s dive into how to use a serial receipt printer with Python 3. We’ll start with installing the PySerial library and setting up the connection variables. Then, we’ll walk through various commands and functions such as printing a string, printing a list of strings, rotating text, changing text size, and even printing upside down. With these tools, you’ll be able to add physical outputs to your scripts, making it a useful skill for a wide range of applications.

To the right is an video demo I made where I recreated the text scroll from Star Wars: A New Hope.

Okay first we need to install the PySerial library using PIP.


1
'pip install pyserial'

Now we need to set the variables for the script.  You can easily change these values to what you need.

Setting Up the Connection

‘com’ is for the serial com port you are using.
‘baud’ is the baud rate of your printer.
‘width’ is the character width of your printer.
‘cutfeed’ is how many lines to feed before cutting.


1
2
3
4
5
#Set Variables
com = 'COM1'
baud = 38400
width = 42
cutfeed = 6

This starts the printer communications.  Remember as you go you will need to run ‘ser.close()’ to end the connection. 

If you don’t close your connection each time you use it and the script crashes, you may have issues restarting the script because the com port was left open.


1
2
3
4
ser = serial.Serial(com, baud, timeout=0, parity=serial.PARITY_NONE)

if ser.isOpen():
     ser.close()

close() – Closing the Connection

This makes closing the connection easier as you go.  If you try closing the connection while it is already closed it will cause issues.  This method will check if it is open before closing it.


1
2
3
4
5
#closes the serial connection
#you must end any print process with this command.
def close():
     if ser.isOpen():
          ser.close()

cutpaper() – Cutting the Paper

This is the cut paper command.  It is dependent on a command (linefeed) we haven’t added yet.  Basically it will feed a count of lines and the cut the paper.  The line ‘ser.write(b”\x1D\x56\x00″)’ is the serial command to trigger the cutter.


1
2
3
4
5
6
7
8
#cuts the paper
def cutpaper():
     if not ser.isOpen():
          ser.open()
     line = range(cutfeed)
     for i in line:
          linefeed()
     ser.write(b'\x1D\x56\x00')

end() – Cut and Close

This command is a shortcut to cut paper and end the connection.


1
2
3
4
#shortcut to cutpaper and close the connection
def end():
     cutpaper()
     close()

init() – Resets ESC/POS Defaults

The ‘init’ command resets different settings we can send to the printer.  Later we can change the text size, direction, etc.  This resets it back to the defaults.


1
2
3
4
5
#resets all commands sent to printer
def init():
     if not ser.isOpen():
          ser.open()
     ser.write(b'\x1B\x40')

linefeed() – Force a Line Feed

This will feed a single line.  This is a dependency for the ‘cutpaper’ command.


1
2
3
4
5
#Feeds a single line.
def linefeed():
     if not ser.isOpen():
          ser.open()
     ser.write(b'\x0a')

prt(item) – Printing a String

Finally we get to a print command.  This takes an argument (a string) and prints it on the paper and then it runs the ‘linefeed’ command.  The text will be default justified.


1
2
3
4
5
6
#prints a string
def prt(item):
     if not ser.isOpen():
          ser.open()
     ser.write(item.encode())
     linefeed()

prtcent(item) – Centered Single String

The ‘prtcent’ command takes a string and centers it before printing it.  For this to work properly it is important that your ‘width’ variable is correct.  If you have many strings to print centered I would use ‘setjust(2)’ and ‘prt()’.


1
2
3
4
5
6
#prints a centered string
def prtcent(item):
     if not ser.isOpen():
          ser.open()
     ser.write((item.center(width)).encode())
     ser.write('\n'.encode())

prtlst(item) – Printing a List of Strings

This command will take a list object.  It goes through each string in the list and prints it.  Use the ‘setjust(2)’ command to make it centered.  I really like this one and it makes things a lot easier when doing a large body of text.


1
2
3
4
#prints a list.
def prtlst(item):
     for i in item:
          prt(i)

rotatecw(item) – Rotating the Text

This command will rotate the text clockwise.  It takes an argument.  Using ‘1’ will rotate the text and using ‘0’ will set it back to normal.


1
2
3
4
5
6
7
8
#rotates characters clockwise
def rotatecw(item):
     if not ser.isOpen():
          ser.open()
     if item == 0:#cancels
          ser.write(b'\x1B\x56\x48')
     elif item == 1:#rotates
          ser.write(b'\x1B\x56\x49')

setjust(item) – Justification

This command can justify the text for use with the ‘prt’ command.
‘0’ will left justify
‘1’ will right justify
‘2’ will center justify


1
2
3
4
5
6
7
8
9
10
11
12
#sets justification
def setjust(item):
     if not ser.isOpen():
          ser.open()
     if item == 0:#left
          ser.write(b'\x1B\x61\x00')
     elif item == 1:#right
          ser.write(b'\x1B\x61\x02')
     elif item == 2:#center
          ser.write(b'\x1B\x61\x01')
     else:
          print('Invalid Entry')

setsize(item) – Changing the Text Size

This will change the size of the text.  This comes in real handy.
‘0’ is normal size
‘1’ is double size
‘2’ is triple size

The key to it is in the last set in the command sent: b’\x1D\x21\x00′

Changing the ’00’ to ’11’ will double the size.  You can make the characters wider or taller by changing those individually.  The first character is the width and the second is the height.


1
2
3
4
5
6
7
8
9
10
11
def setsize(item):
     if not ser.isOpen():
          ser.open()
     if item == 0:#Size Normal
          ser.write(b'\x1D\x21\x00')

     elif item == 1:#Size Double
          ser.write(b'\x1D\x21\x11')

     elif item == 2:#Size Triple
          ser.write(b'\x1D\x21\x22')

upsidedown(item) – Printing Upside Down

This will make your text upside down.  Passing a ‘1’ will make roll it upside down and ‘0’ will make it normal again.  This can come in handy if your printer is mounted on the wall or something.


1
2
3
4
5
6
7
8
9
10
#print text upside down
def upsidedown(item):
     if not ser.isOpen():
          ser.open()

     if item == 0:#right side up
          ser.write(b'\x1B\x7B\x02')

     elif item == 1:#upside down
          ser.write(b'\x1B\x7B\x01')

Using a serial receipt printer can be a great tool for physical output from your scripts. From cutting paper to rotating text and changing text size, the possibilities are endless. With the proper setup and use of the functions outlined in this article, you can easily bring your scripts to life with a physical output. Whether it be for personal projects or for use in a professional setting, having the ability to use a serial receipt printer can greatly enhance the functionality of your scripts.

Reference: Epson ESC/POS Application Guide (1997)

Posted in

Signup Form

Would you like to sign up for our mailing list?
Something went wrong. Please check your entries and try again.