thermoprint-homework/print_server.py

131 lines
4.2 KiB
Python

import time
from escpos.printer import Usb, Dummy
from escpos.exceptions import USBNotFoundError
from jobs.math_homework import MathHomeworkJob
from jobs.unit_conversion import UnitConversionJob
from jobs.chess_puzzle import ChessPuzzleJob
from jobs.maze import MazeJob
from jobs.division_cipher import DivisionCipherJob
from jobs.decimal_division import DecimalDivisionJob
from jobs.joke import JokeJob
from jobs.maze_multitarget import MazeMultitargetJob
from jobs.flush import FlushJob
# ==========================================
# CONFIGURATION
# ==========================================
# Replace these with your specific printer's values found via lsusb or Device Manager
# Example: 0x04b8 is Epson.
USB_VENDOR_ID = 0x0525
USB_PRODUCT_ID = 0xa700
# Input interface:
# `lsusb -vvv -d xxxx:xxxx | grep iInterface`
# iInterface 0
INPUT_ENDPOINT = 0x00
# Output interface:
# `lsusb -vvv -d xxxx:xxxx | grep bEndpointAddress | grep OUT`
# bEndpointAddress 0x01 EP 1 OUT
OUTPUT_ENDPOINT = 0x01
# Set to True to print to console instead of physical printer (for testing)
USE_DUMMY_PRINTER = False
def get_printer():
"""
Initializes the printer connection.
Returns a printer object.
"""
if USE_DUMMY_PRINTER:
return Dummy()
try:
# Initialize USB printer
# Generic printer with custom settings:
p = Usb(USB_VENDOR_ID, USB_PRODUCT_ID, 0, INPUT_ENDPOINT, OUTPUT_ENDPOINT, profile="default")
p.profile.profile_data['media']['width']['mm'] = 80
p.profile.profile_data['media']['width']['pixels'] = 512
# Specific printer based on a profile. See https://python-escpos.readthedocs.io/en/latest/printer_profiles/available-profiles.html
# p = Usb(USB_VENDOR_ID, USB_PRODUCT_ID, 0, INPUT_ENDPOINT, OUTPUT_ENDPOINT, profile="TM-T88V")
return p
except USBNotFoundError:
print("Error: Printer not found. Check USB connection and IDs.")
return None
except Exception as e:
print(f"Error initializing printer: {e}")
return None
JOBS = [
MathHomeworkJob(),
UnitConversionJob(),
ChessPuzzleJob(),
MazeJob(),
DivisionCipherJob(),
DecimalDivisionJob(),
JokeJob(),
MazeMultitargetJob(),
# keep this last:
FlushJob()
]
def run_tui():
print("==========================================")
print(" THERMAL PRINTER CONTROL CENTER ")
print("==========================================")
while True:
print("\nAvailable Jobs:")
for i, job in enumerate(JOBS):
print(f" [{i + 1}] {job.get_name()}")
print(" [q] Quit")
choice = input("\nSelect an option: ").strip().lower()
if choice == 'q':
print("Exiting...")
break
try:
idx = int(choice) - 1
if 0 <= idx < len(JOBS):
job = JOBS[idx]
else:
print("Invalid selection.")
continue
except ValueError:
print("Invalid selection.")
continue
if job:
job.configure()
copies_str = input("\nNumber of copies [1]: ").strip()
try:
copies = max(1, int(copies_str)) if copies_str else 1
except ValueError:
copies = 1
p = get_printer()
if p:
print(f"Printing {job.get_name()} ({copies} copies)...")
try:
for i in range(copies):
if copies > 1:
print(f" Printing copy {i + 1}...")
job.run(p)
# If using Dummy, print the output to console to verify
if isinstance(p, Dummy):
print(p.output.decode('utf-8', errors='ignore'))
print("Success! Job sent to printer.")
except Exception as e:
print(f"Print Error: {e}")
finally:
if not isinstance(p, Dummy):
time.sleep(0.5)
p.close()
if __name__ == '__main__':
run_tui()