132 lines
4.8 KiB
Python
132 lines
4.8 KiB
Python
"""
|
|
A collection of Printers.
|
|
|
|
It has methods to discover printers, and provides an interface for the methods expected from printers.
|
|
"""
|
|
from collections.abc import Mapping, Set
|
|
import usb.core
|
|
import usb.util
|
|
from printer import Printer, EscPosPrinter, BrotherPrinter, PrinterType
|
|
|
|
class Printers():
|
|
"""
|
|
Finds and creates a set of Printer that can be used by the Workers to print.
|
|
"""
|
|
def __init__(self, app):
|
|
"""
|
|
Discover printers connected to the computer and return a Collection of Printer()
|
|
"""
|
|
self.app = app
|
|
self.printers = self._discover_printers()
|
|
|
|
def _discover_printers(self) -> Set[Printer]:
|
|
"""
|
|
Gets connected USB printer devices using the pyusb library.
|
|
|
|
We analyse the USB devices, get the ones that match
|
|
the printer class ( 7 ) and for Brother and EPSON printers,
|
|
try to create a Printer object that can be used by the Worker class
|
|
to execute prints.
|
|
|
|
Returns a set of Printer
|
|
"""
|
|
|
|
self.app.logger.debug("Discovering USB Devices connected to this system")
|
|
|
|
printers = set()
|
|
|
|
# Find all connected USB devices
|
|
devices = usb.core.find(find_all=True,custom_match=_FindClass(7))
|
|
if not devices:
|
|
self.app.logger.warning("No USB devices of class 7 ( printers ) found or pyusb could not access the bus.")
|
|
raise RuntimeError("No USB devices of class 7 ( printers ) found or pyusb could not access the bus.")
|
|
|
|
for dev in devices:
|
|
# Attempt to get the manufacturer and product strings
|
|
try:
|
|
manufacturer = usb.util.get_string(dev, dev.iManufacturer)
|
|
except Exception:
|
|
manufacturer = "Unknown"
|
|
|
|
try:
|
|
product = usb.util.get_string(dev, dev.iProduct)
|
|
except Exception:
|
|
product = "Unknown"
|
|
self.app.logger.debug("Looking at %s %s (%s:%s)", manufacturer, product, hex(dev.idVendor), hex(dev.idProduct))
|
|
|
|
if manufacturer == "EPSON":
|
|
try:
|
|
# We create a new EscPosPrinter()
|
|
self.app.logger.debug("Trying to creat a new EPSON printer")
|
|
prid = dev.idProduct
|
|
vendir = dev.idVendor
|
|
escpos_printer = EscPosPrinter(self.app, vendor_id=vendir, device_id=prid)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
# If the object creation is successfull, we add it to the list of Printers
|
|
printers.add(escpos_printer)
|
|
self.app.logger.debug("Found a %s printer" % manufacturer )
|
|
|
|
# We already found the type of printer,
|
|
# we don't need an extra comparaison.
|
|
continue
|
|
|
|
# or a Brother Printer
|
|
if manufacturer == "Brother":
|
|
try:
|
|
# We create a new BrotherPrinter()
|
|
self.app.logger.debug("Trying to creat a new BROTHER printer")
|
|
prid = dev.idProduct
|
|
vendir = dev.idVendor
|
|
brother_printer = BrotherPrinter(self.app, vendor_id=vendir,device_id=prid)
|
|
except Exception as e:
|
|
self.app.logger.error("Could not create a %s printer class with %s:%s" % product, dev.idVendor, dev.idProduct)
|
|
raise e
|
|
|
|
# If the object creation is successfull, we add it to the list of Printers
|
|
printers.add(brother_printer)
|
|
self.app.logger.debug("Found a %s printer" % manufacturer )
|
|
|
|
self.app.logger.debug("Found %s printers" % len(printers))
|
|
return printers
|
|
|
|
def any(self) -> Printer:
|
|
"""
|
|
Return a dict key: UUID, value: Printer, with any connected printer.
|
|
"""
|
|
if len(self.printers) > 0:
|
|
for i in self.printers:
|
|
return i
|
|
else:
|
|
raise RuntimeError("No printers available")
|
|
|
|
def get_printer(self, printer_type):
|
|
"""
|
|
Return a specific printer
|
|
|
|
printer_type -- a printer type
|
|
"""
|
|
return NotImplementedError()
|
|
|
|
|
|
class _FindClass():
|
|
def __init__(self, class_):
|
|
self._class = class_
|
|
def __call__(self, device):
|
|
# first, let's check the device
|
|
if device.bDeviceClass == self._class:
|
|
return True
|
|
# ok, transverse all devices to find an
|
|
# interface that matches our class
|
|
for cfg in device:
|
|
# find_descriptor: what's it?
|
|
intf = usb.util.find_descriptor(
|
|
cfg,
|
|
bInterfaceClass=self._class
|
|
)
|
|
if intf is not None:
|
|
return True
|
|
|
|
return False
|