Maker.io main logo

BLE Thermal "Cat" Printer with CircuitPython

2024-08-02 | By Adafruit Industries

License: See Original Project Programmers

Courtesy of Adafruit

Guide by Jeff Epler

Overview

circuitpython_ezgifcom-optimize_9

When I saw the "cat" printer in this Hackaday article, I simply had to ‎have one for myself. The original poster made a library for Arduino, ‎but I wanted to make a version that worked on CircuitPython ‎instead.‎

Big thanks go to GitHub user BitBank for the original Arduino ‎code, which was studied to implement this project.‎

Before trying this project, please check that your printer works by ‎using the official "iPrint" application, since there's a lot of technology ‎stacks involved

This project is designed for the Adafruit CLUE, but it should be ‎possible to adapt it to other CircuitPython boards that support ‎Bluetooth Low Energy (BLE).‎

I tried adapting the code to Adafruit Blinka, on a laptop and on a pi4, ‎but the code wasn't as reliable. It tends to just stop printing part way ‎through the image. So, stick with nRF52840-based CircuitPython ‎boards unless you want to debug it!‎

The CircuitPython code only supports the "Cat" printer model GD02, ‎not the other printers shown in the Hackaday article.‎

Parts

CircuitPython on CLUE

CircuitPython is a derivative of MicroPython designed to simplify ‎experimentation and education on low-cost microcontrollers. It ‎makes it easier than ever to get prototyping by requiring no upfront ‎desktop software downloads. Simply copy and edit files on ‎the CIRCUITPY flash drive to iterate.‎

The following instructions will show you how to install CircuitPython. ‎If you've already installed CircuitPython but are looking to update it ‎or reinstall it, the same steps work for that as well!‎

Set up CircuitPython Quick Start!‎

Follow this quick step-by-step for super-fast Python power :)‎

Download the latest version of CircuitPython for CLUE from ‎circuitpython.org

Click the link above to download the latest version of ‎CircuitPython for the CLUE.‎

Download and save it to your desktop (or wherever is handy).‎

download_1

Plug your CLUE into your computer using a known-good USB cable.‎

A lot of people end up using charge-only USB cables and it is very ‎frustrating! So, make sure you have a USB cable you know is good ‎for data sync.‎

Double-click the Reset button on the top (magenta arrow) on your ‎board, and you will see the NeoPixel RGB LED (green arrow) turn ‎green. If it turns red, check the USB cable, try another USB port, ‎etc. Note: The little red LED next to the USB connector will pulse red. ‎That's ok!‎

If double-clicking doesn't work the first time, try again. Sometimes it ‎can take a few tries to get the rhythm right!‎

board_2

You will see a new disk drive appear called CLUEBOOT.‎

Drag the adafruit-circuitpython-clue-etc.uf2 file to CLUEBOOT.‎

disk_3

disk_4

The LED will flash. Then, the CLUEBOOT drive will disappear, and a ‎new disk drive called CIRCUITPY will appear.‎

If this is the first time, you're installing CircuitPython or you're doing ‎a completely fresh install after erasing the filesystem, you will have ‎two files - boot_out.txt, and code.py, and one folder - lib on ‎your CIRCUITPY drive.‎

If CircuitPython was already installed, the files present before ‎reloading CircuitPython should still be present on ‎your CIRCUITPY drive. Loading CircuitPython will not create new ‎files if there was already a CircuitPython filesystem present.‎

That's it, you're done! :)

newdisk_5

Installing The Code

Once you've finished setting up your Adafruit CLUE with ‎CircuitPython, you can access the code and necessary libraries by ‎downloading the Project Bundle.‎

To do this, click on the Download Project Bundle button in the ‎window below. It will download as a zipped folder.‎

Download Project Bundle

Copy Code
# SPDX-FileCopyrightText: 2021 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import os

import board
import keypad
import ulab.numpy as np

from adafruit_ble import BLERadio
from adafruit_ble.advertising import Advertisement

from thermalprinter import CatPrinter
from seekablebitmap import imageopen

ble = BLERadio() # pylint: disable=no-member

buttons = keypad.Keys([board.BUTTON_A, board.BUTTON_B], value_when_pressed=False)

def wait_for_press(kbd):
"""
Wait for a keypress and return the event
"""
while True:
event = kbd.events.get()
if event and event.pressed:
return event


def show(s):
"""
Display a message on the screen
"""
board.DISPLAY.auto_refresh = False
print("\n" * 24)
print(s)
board.DISPLAY.auto_refresh = True


def show_error(s):
"""
Display a message on the screen and wait for a button press
"""
show(s + "\nPress a button to continue")
wait_for_press(buttons)


def find_cat_printer(radio):
"""
Connect to the cat printer device using BLE
"""
while True:
show("Scanning for GB02 device...")
for adv in radio.start_scan(Advertisement):
complete_name = getattr(adv, "complete_name")
if complete_name is not None:
print(f"Saw {complete_name}")
if complete_name == "GB02":
radio.stop_scan()
return radio.connect(adv, timeout=10)[CatPrinter]


image_files = [
i
for i in os.listdir("/")
if i.lower().endswith(".pbm") or i.lower().endswith(".bmp")
]
image_files.sort(key=lambda filename: filename.lower())


def select_image():
i = 0
while True:
show(
f"Select image file\nA: next image\nB: print this image\n\n{image_files[i]}"
)
event = wait_for_press(buttons)
if event.key_number == 0: # button "A"
i = (i + 1) % len(image_files)
if event.key_number == 1: # button "B"
return image_files[i]


printer = find_cat_printer(ble)

def main():
try:
filename = select_image()

show(f"Loading {filename}")

image = imageopen(filename)
if image.width != 384:
raise ValueError("Invalid image. Must be 384 pixels wide")
if image.bits_per_pixel != 1:
raise ValueError("Invalid image. Must be 1 bit per pixel (black & white)")

invert_image = image.palette and image.palette[0] == 0

show(f"Printing {filename}")

for i in range(image.height):
row_data = image.get_row(i)
if invert_image:
row_data = ~np.frombuffer(row_data, dtype=np.uint8)
printer.print_bitmap_row(row_data)

# Print blank lines until the paper can be torn off
for i in range(80):
printer.print_bitmap_row(b"\0" * 48)

except Exception as e: # pylint: disable=broad-except
show_error(str(e))
image_files.remove(filename)

while True:
main()

View on GitHub

After downloading the Project Bundle, plug your Adafruit CLUE into ‎the computer's USB port. You should see a new flash drive appear in ‎the computer's File Explorer or Finder (depending on your operating ‎system) called CIRCUITPY. Unzip the folder and copy the following ‎items to the CLUE's CIRCUITPY drive.‎

Several sample images are included, continue on to "Using The ‎Code" to print them. To prepare your own images, visit "Creating ‎Images".‎

code_6

Using The Thermal Printer

printer_7

Power on the printer (you can tell it's powered on when the blue LED ‎blinks), then power on your CLUE.‎

The CLUE will wait until it can connect to the printer.‎

Then, the CLUE's built-in display allows you to choose an image to ‎print. (Just the image name is shown, not the image itself.)‎

Tap the "A" button to move to the next file in the list. When you ‎reach the end of the list, you'll be sent back to the first file.‎

Tap the "B" button to send the selected file to the printer. While the ‎print is in progress, button presses are ignored.‎

When the image is done printing, the CLUE will return to the ‎screen where you can select an image to print.‎

Creating Your Own Images

You need to prepare your images as black & white (also known as ‎‎1BPP) files in "bmp" or "pbm" format. The width must be exactly 384 ‎pixels, while the height can be unlimited (as long as the file fits on ‎the CLUE CIRCUITPY drive).‎

Different image and photo editing programs have different steps to ‎prepare an image. Here you can see how to use the free and open ‎source GIMP photo editing software to prepare an image, but you ‎should be able to use any software that can write compatible "bmp" ‎files!‎

Open your original image.‎

open_8

Resize the image to be 384 pixels wide. Let your image editor ‎calculate the height automatically or the image will be distorted.‎

resize_9

Convert the image to 1 bit per pixel, using your choice of dithering ‎methods.‎

convert_10

Export the image as a "bmp" file on the CIRCUITPY drive. Your CLUE ‎will automatically reset, and you can choose the newly uploaded file ‎for printing!‎

export_11

制造商零件编号 4500
CLUE NRF52840 EXPRESS
Adafruit Industries LLC
¥365.90
Details
制造商零件编号 2185
CABLE A PLUG TO MCR B PLUG 6.56'
Adafruit Industries LLC
¥40.29
Details
Add all DigiKey Parts to Cart
TechForum

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.

Visit TechForum