tr3v3r / react-native-esc-pos-printer

An unofficial React Native library for printing on an EPSON TM printer with the Epson ePOS SDK for iOS and Epson ePOS SDK for Android
MIT License
137 stars 63 forks source link

simultaneously printing: Error: ERR_ILLEGAL #104

Open saranadshi5 opened 1 year ago

saranadshi5 commented 1 year ago

when printer multiple print as same time one of them printed and another one not printed and causing Error: ERR_ILLEGAL

tolypash commented 1 year ago

Same here @tr3v3r

manage-some commented 1 year ago

+1 Same

saranRajendiran commented 1 year ago

when printer multiple print as same time one of them printed and another one not printed and causing Error: ERR_ILLEGAL

I solved by adding into Queue instead of printing directly

tolypash commented 1 year ago

Also wrapped the package with a class that creates print jobs. But if I could send prints simultaneously somehow would be great :)

tr3v3r commented 1 year ago

Actually, the SDK itself allows printing on multiple devices

But the RN part doesn't have all the features like in single printing. I have a plan to rework it in the future

For now, you can take a look at this example. It provides this functionality: https://github.com/tr3v3r/react-native-esc-pos-printer/blob/main/example/src/MultiPrint.tsx

tolypash commented 1 year ago

Thanks for the response @tr3v3r ! Looks good! đź‘Ť Wanted to ask, do you recommend using instantiate for each printer on discovery or initPrinter before printing?

tr3v3r commented 1 year ago

Instantiate for multiple printing but as I said it could not contain some features. i.e. You have to disconnect manually and I'm not sure that the monitor feature working properly. So you can try at least :D

tolypash commented 1 year ago

@tr3v3r Sounds good, I will instantiate them then :)

saranadshi5 commented 1 year ago

@tr3v3r is there options to send multiple printing for a single printer? and Instantiate for multiple to connect printer is am right?

tolypash commented 1 year ago

@saranadshi5 I tested it by sending multiple print jobs one after the other and it works using instantiate. Only issue is with print errors not getting thrown.

ahmad71666 commented 7 months ago

when printer multiple print as same time one of them printed and another one not printed and causing Error: ERR_ILLEGAL

I solved by adding into Queue instead of printing directly

How to use queue here?

marab2 commented 7 months ago

We have successfully implemented a permanent solution for an issue on iOS and are currently working on resolving the same issue on Android. However, we are facing a challenge with the handleCommand function in Android, as it doesn't throw any errors like it does in iOS. We are hoping that @tr3v3r can help us with this, as the way the function is handled in Objective-C is different from how it's handled in Java. Below are snippets of both implementations for comparison.

Here a snippit of both Objective C [What happening here is that when any failure print happens the iOS will try to reprint for 4 times, the whole ePson brand has this kind of failure and we haven't found a better way then this code to handle it, even if 4 devices are printing on the same printer still this code solve the problem with no printing missing part of the page or the whole page.

`- (void)printFromBuffer:(NSArray)buffer params:(NSDictionary )params onSuccess: (void(^)(NSString ))onSuccess onError: (void(^)(NSString ))onError { int result = EPOS2_SUCCESS;

if (self->printer == nil) {
    NSString *errorString = [ErrorManager getEposErrorText: EPOS2_ERR_PARAM];
    onError(errorString);
    return;
}

NSUInteger length = [buffer count];
for (int j = 0; j < length; j++ ) {
    result = [self handleCommand:[buffer[j][0] intValue] params:buffer[j][1]];

    if (result != EPOS2_SUCCESS) {
        [self->printer clearCommandBuffer];
        NSString *errorString = [ErrorManager getEposErrorText: result];
        onError(errorString);
        return;
    }
}
result = [self printData:params];

// Failure handling starting by MA & Georage
__block Epos2PrinterStatusInfo *info;
int count = 0;
//Note: Check if the process overlaps with another process in time.
while(result != EPOS2_SUCCESS && count < 4 && self->printer !=nil) {
    info = [self->printer getStatus];
    if (info.getConnection == 1) {
        count++;
[NSThread sleepForTimeInterval:(double)count];
        continue;
    }

        NSUInteger length = [buffer count];
        for (int j = 0; j < length; j++ ) {
            result = [self handleCommand:[buffer[j][0] intValue] params:buffer[j][1]];

            if (result != EPOS2_SUCCESS) {
                [self->printer clearCommandBuffer];
                NSString *errorString = [ErrorManager getEposErrorText: result];
                onError(errorString);
                return;
            }
        }

        result = [self printData:params];
    count++;

}

if (result != EPOS2_SUCCESS) {
    NSString *errorString = [ErrorManager getEposErrorText: result];
    onError(errorString);
    return;
}

[self->printer clearCommandBuffer];
NSString *successString = [ErrorManager getEposErrorText: EPOS2_SUCCESS];
onSuccess(successString);

}`

Now on the other hand on the Java there are no result = and we couldn't find any way to let the for (int curr = 0; curr < bufferLength; curr++) { throw error like the iOS, so we can hande, we tried everything, try catch everything possible, but it doesn't work at all, I hope that @tr3v3r can help us with it.

`public void printFromBuffer(ReadableArray printBuffer, final ReadableMap paramsMap, MyCallbackInterface callback) { if (mPrinter == null) { String errorString = EscPosPrinterErrorManager.getEposExceptionText(Epos2Exception.ERR_PARAM); callback.onError(errorString); return; }

try {
  int bufferLength = printBuffer.size();
  for (int curr = 0; curr < bufferLength; curr++) {
    ReadableArray command = printBuffer.getArray(curr);
    handleCommand(command.getInt(0), command.getArray(1));
  }
} catch (Epos2Exception e) {
  mPrinter.clearCommandBuffer();
  int status = EscPosPrinterErrorManager.getErrorStatus(e);
  String errorString = EscPosPrinterErrorManager.getEposExceptionText(status);
  callback.onError(errorString);
  return;
} catch (IOException e){
  mPrinter.clearCommandBuffer();
  callback.onError(e.getMessage());
  return;
}
try {
    Thread.sleep(100); // Sleep for 0.1 second to solve errors
  this.printData(paramsMap);
  String successString = EscPosPrinterErrorManager.getCodeText(Epos2CallbackCode.CODE_SUCCESS);
  callback.onSuccess(successString);
} catch (InterruptedException e) {
    e.printStackTrace(); // Handle the InterruptedException exception
  }
catch (Epos2Exception e) {
  int status = EscPosPrinterErrorManager.getErrorStatus(e);
  String errorString = EscPosPrinterErrorManager.getEposExceptionText(status);
  callback.onError(errorString);
}

}`

tr3v3r commented 7 months ago

@marab2 Hello. So the problem on a high level as I understood:

1) You have one printer but several mobile devices. (Phone1, Phone2, Phone3, Printer ) 2) All of them connect to this printer and try to Print 3) Phone1 -> printData -> Printer (Success),
Phone2 -> printData -> Printer (Failure), Phone3 -> printData -> Printer (Failure) Phone4 -> printData -> Printer (Failure) 4) Fort the Phones that are failing you're trying to retry printing 5) But for Android you can not detect the error to start retrying.

Is that correct? What method you're using to init printer?

marab2 commented 7 months ago

Hi @tr3v3r, Thanks for your quick response! We've been working with the TM-20 series and have encountered similar issues across the board. When printing, we're seeing random errors like ERR_LEGAL and ERR_PARAM. This happens regardless of whether it's one printer connected to multiple devices, or multiple devices connected to multiple printers trying to print multiple copies.

We've found that handling the failure with a while loop for 4 tries helps to resolve this issue permanently. However, we're experiencing the same problems with Android. For instance, one paper gets printed correctly, while the next one misses the logo or some other part. Interestingly, Android doesn't throw any error in the for (int curr = 0; curr < bufferLength; curr++) loop like it does in iOS, and we hope if you can help us get the Android to do the same thing as we try with everything we know with Java but it doesn't work.

Our project involves handling multiple printers, including Epson. Here's how we manage the printing process with Epson from start to finish.

// / Epson Printers / // import EscPosPrinter, { getPrinterSeriesByName, IPrinter, } from 'react-native-esc-pos-printer'; import {showToast} from '../Helpers';

export const connectEpsonPrinter = async ( printer: any, data: any, copies: number, printers: [], init: boolean, setInit: any, setPrinting: any, ) => { if (!printers?.length) { showToast('No Epson printers discovered, please recheck'); setPrinting(false); return; } // Epson printer const pp: IPrinter | undefined = printers.find( (p: any) => p?.ip === printer?.ip, ); if (!pp) { showToast("We couldn't find your Eposn priter"); setPrinting(false); return; } if (!init) { await EscPosPrinter.init({ // @ts-ignore target: pp.target, // @ts-ignore seriesName: getPrinterSeriesByName(pp.name), language: 'EPOS2_LANG_MULTI', }); setInit(true); } let openDrawer = true; for (let i = 0; i < copies; i++) { await printOrder(data, pp, openDrawer); openDrawer = false; } setInit(false); EscPosPrinter.disconnect(); };

const printOrder = async ( items: any, printer1: IPrinter, openDrawer: boolean, ) => { try { if (printer1) { const printingAt = new EscPosPrinter.printing(); const printObj = await printingAt.initialize(); items.forEach((item: any) => { printObj.align('center');

    printObj.align('center');
    if (item.type === 'base64' && typeof item.data === 'string') {
      printObj.text('\x1B\x33\x10');
      printObj.image(
        {uri: 'data:image/jpg;base64,' + item.data},
        {width: 500},
      );
      printObj.newline();
    }
    if (item.type === 'text') {
      //To reduce white spacing in the EPSON
      printObj.text('\x1B\x33\x10');

      printObj.text(item.data);
      //To reduce white spacing in the EPSON
      printObj.text('\x1B\x33\x10');
      printObj.newline();
    }
    if (item.type === 'qr') {
      printObj.qrcode({
        value: item.data,
        level: 'EPOS2_LEVEL_M',
        width: 7,
      });
      printObj.newline();
    }
    if (item.type === 'cut') {
      printObj.cut();
    }
  });
  if (openDrawer) {
    printObj.addPulse();
  }
  await printObj.send();
}

} catch (error: any) { showToast('Error code3:', error.message); console.log('error', error); } };

tolypash commented 7 months ago

Just shedding some light here, we get the same sometimes but I made it so that on print fail it shows the error on screen in a top level modal and the print job can be retried. Also, I added delays between prints. I think best solution would be to get instantiate working, so that all printers are connected in the same time, to report errors properly on print to them, and some kind of auto-retry mechanism.

ahmad71666 commented 7 months ago

@marab2 to get it work, use promise, and add timeout like 800 900 milliseconds, that would work. I have implemented it, it works fine but when we "init" printer one by one it takes time, we have 4 printers, so the total of 1 minute and few seconds are required to print on all, You will have to print it one by one, if one printer is initialized and in use, and you send command to initialize another that will generate error, so try to do it in loop, but one after another and put delay in it..

marab2 commented 7 months ago

@tolypash It's not about init or instantiate we even tried different libraries, all of them has the same problem, I believe it's an issue with EPson it self, if just anyone help us to get the result= same like what it's in objective C code, we can solve the issue the same way in Java.

ahmad71666 commented 7 months ago

@marab2 well maybe, but the code is working on my side, with both init and instantiate but the instantiate method does not return errors...

tolypash commented 7 months ago

Yea it’s working for me as long as I put delays (sleep with useTimeout) between prints.

But sometimes it gets “stuck” and I have to restart app but that’s rare

I’d recommend you build a print service class that take a queue of print jobs and runs them with an interval @marab2

marab2 commented 7 months ago

@tolypash We have did that, and even the queue doesn't help. @tr3v3r I found a java file where the guy handles the error on each function can you please take a look https://github.com/nowarzz/rn-epson-tm82/blob/master/android/src/main/java/com/nowarzz/rrnepson/EpsonTM82.java

marab2 commented 7 months ago

@ahmad71666 @tolypash if you want to see the big fall for Epson, try to initial print command with 5 copies of print, and see how 1-2 copies will get lost. If it success in the first time, then do it again immediately.

ahmad71666 commented 7 months ago

@marab2 yes will do that, never tried this case though, all other libraries seems outdated or unstable, only this one works, but has issues...

tr3v3r commented 7 months ago

@marab2 if you need copies just do not disconnect from a printer! use any amount of copies within one buffer

printer .text() .cut() .send()

.text() .cut() .send() // <- repeat again without disconnecting ( 1 copy )

.text() .cut() .send() // <- repeat again without disconnecting ( 2 copy )

.disconnect()

P.S. Right now I'm trying to rework the printing approach.

So the new one will have better error handling and will have a job queue handle on the JS side.

Also could someone please test this (init but with multiple printing support)? It will speed up the process

tolypash commented 7 months ago

@tr3v3r Not sure if it's related but we are getting printer discovery error ERR_PROCESSING. Any ideas why?

"status": "ERR_PROCESSING" "methodName": "PrintersDiscovery.start" "name": "PrinterDiscoveryError" "timestamp": 0

UPDATE: Nevermind, an Expo OTA update has caused this. Need to update native modules as well via full update

manage-some commented 4 months ago

Instantiate for multiple printing but as I said it could not contain some features. i.e. You have to disconnect manually and I'm not sure that the monitor feature working properly. So you can try at least :D

Instantiate does not work as Init in some cases. For example with internet disconnects and reconnects

tr3v3r commented 3 months ago

released 4.0.0-beta.0. It should resolve all issues above

you can check the details here:

https://github.com/tr3v3r/react-native-esc-pos-printer/pull/139