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 from jobs.word_search import WordSearchJob # ========================================== # 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(), WordSearchJob(), # 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()