Unable to Print to Zebra ZQ620 Printer Using WebUSB API and Python Libraries

250 Views Asked by At

I am working on a project that involves connecting to a Zebra Technologies printer (Model: ZEBRA ZQ620) via USB. I want to be able to print information using JavaScript because I making a Extensions that would extract some data and than print it.

What's Happening:

I successfully request a device and open a session. I claim an interface (Claimed interface: 0 on configuration: 1). I send a control transfer (Successfully sent control transfer). I attempt to send a print command.

Issue:

Despite these seemingly successful operations, the printer doesn't execute the print command. The code reaches the point where it tries to send data to the printer but fails to print.

Driver Context:

Initially, I was encountering a "USB Access Denied" issue when using the printer's original drivers. I resolved this by using Zadig to replace the current driver with WinUSB. I'm not sure if this could be causing any problems.

Code:

   <!DOCTYPE html>
<html>

<head>
    <title>WebUSB Example</title>
</head>

<body>
    <h1>WebUSB Zebra Technologies Device Connection</h1>
    <button id="connect">Connect to Device</button>

    <script>
        let device;

        // Helper method to test all possible interface options
        async function tryAllInterfaces(device) {
            const configCount = device.configurations.length;
            for (let configIndex = 0; configIndex < configCount; configIndex++) {
                await device.selectConfiguration(configIndex + 1); // Configurations are 1-indexed
                for (let interfaceIndex = 0; interfaceIndex < device.configuration.interfaces.length; interfaceIndex++) {
                    try {
                        await device.claimInterface(interfaceIndex);
                        console.log(`Claimed interface: ${interfaceIndex} on configuration: ${configIndex + 1}`);
                        return { configIndex, interfaceIndex }; // If successful, return the indices
                    } catch (err) {
                        console.error(`Failed to claim interface ${interfaceIndex} on configuration ${configIndex + 1}: ${err}`);
                    }
                }
            }
            throw new Error('Could not claim any interface');
        }

        // Systematically try all the possible controlTransferOut configurations
        async function testControlTransfer(interfaceIndex) {
            const requestTypes = ['standard', 'class', 'vendor'];
            const recipients = ['device', 'interface', 'endpoint', 'other'];
            const requests = [0x00, 0x01, 0x09, 0x21];
            const values = [0x00, 0x01, 0x02];
            const indices = [0x00, 0x01, 0x02, interfaceIndex]; // Include the claimed interface index

            for (const requestType of requestTypes) {
                for (const recipient of recipients) {
                    for (const request of requests) {
                        for (const value of values) {
                            for (const index of indices) {
                              try {
                                await device.controlTransferOut({
                                  requestType: 'standard',
                                  recipient: 'other',
                                  request: 9,
                                  value: 0,
                                  index: 0 // Replace with the index that was successful in your tests
                                });
                                console.log('Successfully sent control transfer');
                              }  catch (error) {
                                console.error('Detailed error:', JSON.stringify(error, null, 2));
                              }
                            }
                        }
                    }
                }
            }
        }

        // Function to try all possible endpoints and send a test print
        async function tryAllEndpointsAndSendTestPrint() {
            if (!device) {
                console.error('No device connected.');
                return;
            }

            console.log('Attempting to send a test print on all possible endpoints.');

            const zplData = '^XA^FO50,50^A0N,50,50^FDHellodddddd, World!^FS^XZ';
            const buffer = new TextEncoder().encode(zplData);

            const claimedInterface = device.configuration.interfaces[0];
            const endpoints = claimedInterface.alternate.endpoints;

            console.log(`Number of endpoints: ${endpoints.length}`);
          
            for (const endpoint of endpoints) {
                console.log(`Trying endpoint number: ${endpoint.endpointNumber}, direction: ${endpoint.direction}`);
                if (endpoint.direction === 'out') {
                    try {
                        const result = await new Promise((resolve, reject) => {
                            // Set a timeout to reject the promise if it takes too long
                            const timeout = setTimeout(() => {
                                console.log(`Timeout on endpoint ${endpoint.endpointNumber}`);
                                reject(new Error('Operation timed out'));
                            }, 5000); // 5 seconds

                            device.transferOut(endpoint.endpointNumber, buffer)
                                .then(result => {
                                    clearTimeout(timeout);
                                    console.log(`Successfully transferred out on endpoint ${endpoint.endpointNumber}.`);
                                    resolve(result);
                                })
                                .catch(err => {
                                    clearTimeout(timeout);
                                    console.log(`Error during transfer out on endpoint ${endpoint.endpointNumber}.`);
                                    reject(err);
                                });
                        });
                        console.log(`Transfer result: ${JSON.stringify(result)}`);
                        return;
                    } catch (err) {
                        console.error(`Failed to transfer out on endpoint ${endpoint.endpointNumber}: ${err}`);
                    }
                }
            }

            console.error('Failed to transfer out on all endpoints.');
        }
  
        // Function to send a test print
        async function connectDevice() {
            try {
                device = await navigator.usb.requestDevice({
                    filters: [{ vendorId: 0x0A5F, productId: 0x014C }]
                });

                await device.open();

                const { configIndex, interfaceIndex } = await tryAllInterfaces(device);

                await testControlTransfer(interfaceIndex); 

                // After successfully testing control transfer, attempt to send a test print.
                await tryAllEndpointsAndSendTestPrint(); // Use this instead of sendTestPrint()

            } catch (error) {
                console.error('An error occurred:', error);
            }
        }
        document.getElementById('connect').addEventListener('click', connectDevice);
    </script>
</body>

</html>

What I've Tried:

I've looked for examples and guides that might shed light on how to interface with this specific Zebra model, but to no avail. I've tried multiple endpoint numbers for transferOut. I've checked for driver compatibility issues. I've verified that the ZPL commands are correct.

Logs:

Claimed interface: 0 on configuration: 1
Successfully sent control transfer
Attempting to send a test print on all possible endpoints.
Number of endpoints: 2

Other Approachs:

I have also tried using Python libraries like PyUSB, pyserial, Browser Print JavaScript Library and Zebra Python library to send print commands, but none of them have worked.

The Browser Print JavaScript Library initially seemed like a suitable solution, requiring users to run an additional program to establish a local server. Even with this setup, I've encountered issues where I couldn't send messages, files, or ZPL commands successfully. While the library is able to recognize the device, functions like "Write," "Send JPG," and "Send Files" are not operating as expected. Intriguingly, when I set up the environment from scratch on another computer, printing works fine. This leads me to suspect that the issue may be specific to my work computer. Although I have the necessary drivers installed, the problem might stem from previous reinstallations or deletions of drivers. Ideally, I would like to find a solution that enables printing without the need to run an additional program.

Python Code Sample:

Using EPL commands or ZPL command:

label = """
N
q457
Q228,32,-16
X10,10,2,432,220
A12,18,0,2,1,1,R,"asd"
A100,45,0,1,2,2,N,"asd"
A20,80,0,3,1,1,N,"asd"
B30,110,0,1,2,7,70,B,"asd"
P1
"""


from zebra import Zebra
z = Zebra("ZDesigner ZQ620 (ZPL)")
z.getqueues()
z.output(label)

I getting error saying that "Printer couldn't Print Lable"

Goals: I want to create a standalone extension where the user only needs to load the extension and install the Zebra driver to start printing.

Questions: Has anyone successfully printed to a Zebra printer using WebUSB or PyUSB? Which method would be the easiest and most standalone, so that other computers can easily set it up? Any other recommendations or insights would be highly appreciated.

0

There are 0 best solutions below