A modern, fully async Python library for controlling thermal printers via Bluetooth Low Energy (BLE).
- ✨ Fully async/await - Built with asyncio for non-blocking operations
- 🔌 Bluetooth Low Energy - Modern BLE communication via Bleak
- 📝 Type-safe - Full type hints with mypy support
- 🖼️ Image processing - Advanced image processing with multiple binarization methods
- 🏷️ Multiple paper types - Support for gap, mark, and continuous paper types
- 🔍 Device discovery - Built-in BLE device scanning
- 📊 Printer status - Monitor printer state and errors via notifications
- 🏠Home Assistant ready - Perfect for custom integrations
- 🎨 Easy to use - Clean, intuitive API with context managers
pip install thermalprinter-bleThis includes everything you need:
bleak- Bluetooth Low Energy communicationpillow- Image processing and text renderingnumpy- Fast array operations for image dithering
git clone https://github.com/yourusername/thermalprinter-ble
cd thermalprinter-ble
pip install -e ".[dev]"import asyncio
from thermalprinter_ble import ThermalPrinter, BLEDevice
async def main():
# Create printer with BLE connection
printer = await ThermalPrinter.create_ble("AA:BB:CC:DD:EE:FF")
# Print text
await printer.print_text("Hello, World!")
# Close connection
await printer.close()
asyncio.run(main())import asyncio
from thermalprinter_ble import ThermalPrinter, PrintSettings, PaperType
async def main():
# Configure printer settings
settings = PrintSettings(
width=384,
density=15,
paper_type=PaperType.GAP,
)
# Use context manager for automatic cleanup
async with await ThermalPrinter.create_ble(
"AA:BB:CC:DD:EE:FF",
settings=settings
) as printer:
await printer.print_text("Label Text", font_size=32)
await printer.feed_paper(lines=3)
asyncio.run(main())from PIL import Image
import asyncio
from thermalprinter_ble import ThermalPrinter
async def main():
async with await ThermalPrinter.create_ble("AA:BB:CC:DD:EE:FF") as printer:
# Print from file
await printer.print_image("qrcode.png")
# Print PIL Image
img = Image.open("logo.png")
await printer.print_image(img)
asyncio.run(main())import asyncio
from thermalprinter_ble import BLEDevice
async def main():
# Scan for devices by service UUID
devices = await BLEDevice.discover(timeout=10.0, service_uuid="0000ff00-0000-1000-8000-00805f9b34fb")
for address in devices:
print(f"Found printer: {address}")
asyncio.run(main())import asyncio
from thermalprinter_ble import ThermalPrinter
async def main():
# Create printer with serial connection
async with await ThermalPrinter.create_serial(
port="/dev/ttyUSB0", # or "COM3" on Windows
baudrate=115200
) as printer:
await printer.print_text("Serial Print Test")
asyncio.run(main())from thermalprinter_ble import PrintSettings, BinarizationMethod, PaperType
settings = PrintSettings(
width=384,
density=12,
brightness=140,
contrast=120,
paper_type=PaperType.GAP,
binarization=BinarizationMethod.DITHERING,
)
async with await ThermalPrinter.create_ble("AA:BB:CC:DD:EE:FF", settings) as printer:
await printer.print_image("photo.jpg")from thermalprinter_ble import (
ThermalPrinter,
ConnectionError,
PrinterError,
TimeoutError,
)
async def safe_print():
try:
async with await ThermalPrinter.create_ble("AA:BB:CC:DD:EE:FF") as printer:
await printer.print_text("Test")
except ConnectionError as e:
print(f"Connection failed: {e}")
except PrinterError as e:
print(f"Printer error: {e}")
except TimeoutError as e:
print(f"Operation timed out: {e}")from thermalprinter_ble import BLEDevice, ThermalPrinter
def handle_notification(data: bytes):
print(f"Received: {data.hex()}")
if data == b"\xaa":
print("Print completed!")
async def main():
device = BLEDevice(
"AA:BB:CC:DD:EE:FF",
notification_handler=handle_notification
)
async with ThermalPrinter(device) as printer:
await printer.print_text("Notification test")
asyncio.run(main())Main printer class.
Methods:
initialize()- Initialize printerprint_text(text, font_size)- Print textprint_image(image)- Print PIL Image or image filefeed_paper(lines)- Feed paper forwardget_status()- Get printer status (if supported)close()- Close connection
Class Methods:
create_ble(address, settings, auto_connect)- Create BLE printercreate_serial(port, baudrate, settings, auto_connect)- Create serial printer
Bluetooth Low Energy device connection.
Methods:
connect()- Connect to devicedisconnect()- Disconnectwrite(data)- Write datawait_for_notification(timeout)- Wait for notificationis_connected()- Check connection statusdiscover(timeout, name_filter)- Static method to scan for devices
Print configuration dataclass.
Fields:
width: int- Print width in pixels (default: 384)density: int- Print density 0-15 (default: 15)brightness: int- Brightness 0-255 (default: 128)contrast: int- Contrast 0-255 (default: 128)paper_type: PaperType- Paper type (CONTINUOUS, GAP, MARK)binarization: BinarizationMethod- Image binarization methodcompression: CompressionMethod- Image compression method
Enum for paper types:
CONTINUOUS- Continuous roll paperGAP- Label paper with gapsMARK- Black mark paper
This library implements a BLE thermal printer protocol based on reverse-engineering the DingDang NewPrint Android app. The protocol is compatible with various 58mm thermal printers that use the standard GATT service UUID 0000ff00-0000-1000-8000-00805f9b34fb.
Tested Printers:
- Fichero 4575 (Action)
Expected Compatible Printers:
- DingDang label/thermal printers
- Other 58mm BLE thermal printers using the same GATT service
For technical details, see:
BLUETOOTH_PROTOCOL.md- BLE GATT profile and UUIDsBLE_WRITE_ANALYSIS.md- Write operation analysis
pytestblack src/
ruff check src/
mypy src/pre-commit install
pre-commit run --all-filesMIT License - see LICENSE file for details
Contributions welcome! Please open an issue or PR.
- Protocol reverse-engineered from DingDang NewPrint Android app
- Tested on Fichero 4575 thermal printer
- Inspired by luckjingle-d1-printer
- Uses the excellent Bleak library for BLE communication
- BLE not working: Ensure Bluetooth is enabled and you have necessary permissions
- Device not found: Try increasing scan timeout or check device name filter
- Connection timeout: Printer may be out of range or already connected to another device
- Image too dark/light: Adjust
brightnessandcontrastin PrintSettings - Poor quality: Try different
binarizationmethods (DITHERING often works best) - Wrong size: Ensure image width matches printer width (typically 384 pixels for 58mm)
Linux: May need to run with sudo or add user to dialout group for serial access
macOS: Use device UUID instead of MAC address for BLE
Windows: Use COM port (e.g., "COM3") for serial connection