Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only detecting 1 or 0 printers #40

Closed
rissois opened this issue Nov 19, 2021 · 21 comments
Closed

Only detecting 1 or 0 printers #40

rissois opened this issue Nov 19, 2021 · 21 comments
Labels
help wanted Extra attention is needed

Comments

@rissois
Copy link

rissois commented Nov 19, 2021

QUICK STARTING QUESTION: Does this package work with the TM-T20II?

I found some businesses kind enough to let me test printing on their systems. I created a new React Native app solely for testing the package, and copied App.tsx directly from the example.

At the first location, EscPosPrinter.discover() only returned one printer at random. I could discover additional printers by reloading the app.
At the second location, EscPosPrinter.discover() did not discover any printers. I printed the Network Settings ticket from one of the printers and tried to connect directly through the IP address there, but received ERR_CONNECT.

Both locations were using the same POS system, and the POS system readily displayed all printers on the network. Terminal command arp -a verified that I could detect devices at both locations as well.

Unfortunately, my programming skills are too weak to contribute directly to this code, but I wanted to report this issue as it may help identify some bug within the code.

My App.js was copied directly from the example, but modified from tsx to js:

/* eslint-disable quotes */
/* eslint-disable prettier/prettier */
import React, { useState, useEffect, useCallback } from 'react';
import Encoder from 'esc-pos-encoder';

import { StyleSheet, View, Button } from 'react-native';
import EscPosPrinter, {
  getPrinterSeriesByName,
  IPrinter,
} from 'react-native-esc-pos-printer';
import { base64Image } from './base64Image';

export default function App() {
  const [init, setInit] = useState(false);
  const [printer, setPrinter] = useState(null);

  useEffect(() => {
    EscPosPrinter.addPrinterStatusListener(status => {
      console.log('current printer status:', status);
    });
  }, []);

  useEffect(() => {
    console.log(printer);
  }, [printer]);

  return (
    <View style={styles.container}>
      <Button
        title="Discover"
        onPress={() => {
          console.log('discovering');
          EscPosPrinter.discover()
            .then(printers => {
              console.log('done!', printers);
              if (printers[0]) {
                setPrinter(printers[0]);
              }
            })
            .catch(console.log);
        }}
      />

      <Button
        title="Get lines per row"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          if (printer) {
            if (!init) {
              await EscPosPrinter.init({
                target: printer.target,
                seriesName: getPrinterSeriesByName(printer.name),
                language: 'EPOS2_LANG_EN',
              });
              setInit(true);
            }

            const status = await EscPosPrinter.getPrinterCharsPerLine(
              getPrinterSeriesByName(printer.name),
            );

            console.log('print', status);
          }
        }}
      />

      <Button
        title="Start monitor printer status"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          if (printer) {
            if (!init) {
              await EscPosPrinter.init({
                target: printer.target,
                seriesName: getPrinterSeriesByName(printer.name),
                language: 'EPOS2_LANG_EN',
              });
              setInit(true);
            }

            const status = await EscPosPrinter.startMonitorPrinter();

            console.log('Printer status:', status);
          }
        }}
      />

      <Button
        title="Stop monitor printer status"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          if (printer) {
            if (!init) {
              await EscPosPrinter.init({
                target: printer.target,
                seriesName: getPrinterSeriesByName(printer.name),
                language: 'EPOS2_LANG_EN',
              });
              setInit(true);
            }

            const status = await EscPosPrinter.stopMonitorPrinter();

            console.log('Printer status:', status);
          }
        }}
      />

      <Button
        title="Print from data"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          const encoder = new Encoder();

          encoder
            .initialize()
            .line('The quick brown fox jumps over the lazy dog')
            .newline()
            .newline()
            .newline();

          try {
            if (printer) {
              if (!init) {
                await EscPosPrinter.init({
                  target: printer.target,
                  seriesName: getPrinterSeriesByName(printer.name),
                  language: 'EPOS2_LANG_EN',
                });
                setInit(true);
              }

              const printing = new EscPosPrinter.printing();

              const status = await printing.data(encoder.encode()).cut().send();

              console.log('print', status);
            }
          } catch (error) {
            console.log('error', error);
          }
        }}
      />
      <Button
        title="Test print chaining"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          try {
            if (printer) {
              if (!init) {
                await EscPosPrinter.init({
                  target: printer.target,
                  seriesName: getPrinterSeriesByName(printer.name),
                  language: 'EPOS2_LANG_EN',
                });
                setInit(true);
              }

              const printing = new EscPosPrinter.printing();
              const status = await printing
                .initialize()
                .align('center')
                .size(3, 3)
                .line('DUDE!')
                .smooth(true)
                .line('DUDE!')
                .smooth(false)
                .size(1, 1)
                .text('is that a ')
                .bold()
                .underline()
                .text('printer?')
                .bold()
                .underline()
                .newline(2)
                .align('center')
                .image(require('./store.png'), {
                  width: 75,
                  halftone: 'EPOS2_HALFTONE_THRESHOLD',
                })
                .image({ uri: base64Image }, { width: 75 })
                .image(
                  {
                    uri: 'https://raw.githubusercontent.com/tr3v3r/react-native-esc-pos-printer/main/ios/store.png',
                  },
                  { width: 75 },
                )
                .barcode({
                  value: 'Test123',
                  type: 'EPOS2_BARCODE_CODE93',
                  width: 2,
                  height: 50,
                  hri: 'EPOS2_HRI_BELOW',
                })
                .qrcode({
                  value: 'Test123',
                  level: 'EPOS2_LEVEL_M',
                  width: 5,
                })
                .cut()
                .send();

              console.log('printing', status);
            }
          } catch (error) {
            console.log('error', error);
          }
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  box: {
    width: 60,
    height: 60,
    marginVertical: 20,
  },
});

@tr3v3r
Copy link
Owner

tr3v3r commented Nov 22, 2021

@rissois Hi! Could you please try to update to version 1.5.0 and try to increase discovery timeout to 10 sec i.e. ?

 EscPosPrinter.discover({ scanningTimeoutIOS: 10000, scanningTimeoutAndroid: 10000 })
            .then(printers => {
              console.log('done!', printers);
              })        

@rissois
Copy link
Author

rissois commented Dec 2, 2021

@tr3v3r Thanks for the response, and sorry for the delay.

I upgrade to Version 1.5.0 and increased the scanningTimeoutIOS to 10 seconds. Both issues persisted:
One restaurant fails to return any printer.
The other restaurant returns only one printer at a time.

Printing out a network status sheet and hardcoding the name, mac address, ip address, and target (presumed target = 'TCP:'+ip) also failed for the restaurant that does not discover. The error [Error: ERR_CONNECT] occurred during await printing.data(encoder.encode()).cut().send(). However, their current POS system is easily detecting the printers via WiFi and printing.

Please advise if there are any further tests I can perform to help troubleshoot this. Thanks.

@chukiatt
Copy link

chukiatt commented Dec 4, 2021

i have same problem

@tr3v3r
Copy link
Owner

tr3v3r commented Dec 6, 2021

@rissois Hi!

I can confirm that TM-T20II is supported as well as multiple printers discovery ( since we have such functionality in our app ). Can you confirm that during the search the printers are not reserved by someone else? ( I mean not printing/connected at the moment of searching from another device ).

Have you tried on Android?

Could you please share the exact code you're using?

@chukiatt
Copy link

chukiatt commented Dec 6, 2021 via email

@rissois
Copy link
Author

rissois commented Dec 6, 2021

@tr3v3r

Thanks again for getting back to me. Unfortunately I do not have an Android device to test with, if I speak to my friend later this week perhaps they can lend me one.

Yes, each restaurant has 4-6 printers, and while I am testing none of the printers are actively in use.

Please find below the code exactly as it is in my app, with restaurant information deidentified as #

import React, { useState, useEffect, useCallback } from 'react';
import Encoder from 'esc-pos-encoder';

import { StyleSheet, View, Button } from 'react-native';
import EscPosPrinter, {
  getPrinterSeriesByName,
  IPrinter,
} from 'react-native-esc-pos-printer';
import { base64Image } from './base64Image';

// Discovered these printers one-by-one
const restaurant1 = [
 {
    bt: "",
    ip: "###.###.###.###",
    mac: "##:##:##:##:##",
    name: "TM-T20",
    target: "TCP:###.###.###.###",
    usb: "",
    station: "Bar",
  },
  {
    bt: "",
    ip: "###.###.###.###",
    mac: "##:##:##:##:##",
    name: "TM-T20",
    target: "TCP:###.###.###.###",
    usb: "",
    station: "Kitchen",
  },
  {
    bt: "",
    ip: "###.###.###.###",
    mac: "##:##:##:##:##",
    name: "TM-T20",
    target: "TCP:###.###.###.###",
    usb: "",
    station: "Server station",
  },
];

// Unable to find any printers
const restaurant2 = [];

export default function App() {
  const [init, setInit] = useState(false);
  const [printer, setPrinter] = useState(null);
  useEffect(() => {
    EscPosPrinter.addPrinterStatusListener(status => {
      console.log('current printer status:', status);
    });
  }, []);
  useEffect(() => {
    console.log(printer);
  }, [printer]);

  const printSpecific = useCallback(async p => {
    const encoder = new Encoder();

    encoder
      .initialize()
      .line('The quick brown fox jumps over the lazy dog')
      .newline()
      .newline()
      .newline();

    try {
      console.log('pre-init');
      await EscPosPrinter.init({
        target: p.target,
        seriesName: getPrinterSeriesByName(p.name),
        language: 'EPOS2_LANG_EN',
      });
      console.log('post-init');
      setInit(true);
      console.log('pre-print');
      const printing = new EscPosPrinter.printing();
      console.log('post-print');
      const status = await printing.data(encoder.encode()).cut().send();

      console.log('print', status);
    }
    catch (error) {
      console.log('error', error);
    }
  }, []);

  return (
    <View style={styles.container}>
      {
        restaurant1.map(p => {
          return <Button
            key={p.station}
            title={`Print ${p.station}`}
            color={'blue'}
            onPress={() => {
              printSpecific(p)
            }}
          />;
        })
      }
      <Button
        title="Discover"
        onPress={() => {
          console.log('discovering');
          // EscPosPrinter.discover()
          EscPosPrinter.discover({ scanningTimeoutIOS: 60000, scanningTimeoutAndroid: 10000 })
            .then(printers => {
              console.log('done!', printers);
              if (printers[0]) {
                setPrinter(printers[0]);
              }
            })
            .catch(console.log);
        }}
      />

      <Button
        title="Get lines per row"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          if (printer) {
            if (!init) {
              await EscPosPrinter.init({
                target: printer.target,
                seriesName: getPrinterSeriesByName(printer.name),
                language: 'EPOS2_LANG_EN',
              });
              setInit(true);
            }

            const status = await EscPosPrinter.getPrinterCharsPerLine(
              getPrinterSeriesByName(printer.name),
            );

            console.log('print', status);
          }
        }}
      />

      <Button
        title="Start monitor printer status"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          if (printer) {
            if (!init) {
              await EscPosPrinter.init({
                target: printer.target,
                seriesName: getPrinterSeriesByName(printer.name),
                language: 'EPOS2_LANG_EN',
              });
              setInit(true);
            }

            const status = await EscPosPrinter.startMonitorPrinter();

            console.log('Printer status:', status);
          }
        }}
      />

      <Button
        title="Stop monitor printer status"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          if (printer) {
            if (!init) {
              await EscPosPrinter.init({
                target: printer.target,
                seriesName: getPrinterSeriesByName(printer.name),
                language: 'EPOS2_LANG_EN',
              });
              setInit(true);
            }

            const status = await EscPosPrinter.stopMonitorPrinter();

            console.log('Printer status:', status);
          }
        }}
      />

      <Button
        title="Print from data"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          const encoder = new Encoder();

          encoder
            .initialize()
            .line('The quick brown fox jumps over the lazy dog')
            .newline()
            .newline()
            .newline();

          try {
            if (printer) {
              if (!init) {
                await EscPosPrinter.init({
                  target: printer.target,
                  seriesName: getPrinterSeriesByName(printer.name),
                  language: 'EPOS2_LANG_EN',
                });
                setInit(true);
              }

              const printing = new EscPosPrinter.printing();

              const status = await printing.data(encoder.encode()).cut().send();

              console.log('print', status);
            }
          } catch (error) {
            console.log('error', error);
          }
        }}
      />
      <Button
        title="Test print chaining"
        disabled={!printer}
        color={!printer ? 'gray' : 'blue'}
        onPress={async () => {
          try {
            if (printer) {
              if (!init) {
                await EscPosPrinter.init({
                  target: printer.target,
                  seriesName: getPrinterSeriesByName(printer.name),
                  language: 'EPOS2_LANG_EN',
                });
                setInit(true);
              }

              const printing = new EscPosPrinter.printing();
              const status = await printing
                .initialize()
                .align('center')
                .size(3, 3)
                .line('DUDE!')
                .smooth(true)
                .line('DUDE!')
                .smooth(false)
                .size(1, 1)
                .text('is that a ')
                .bold()
                .underline()
                .text('printer?')
                .bold()
                .underline()
                .newline(2)
                .align('center')
                .image(require('./store.png'), {
                  width: 75,
                  halftone: 'EPOS2_HALFTONE_THRESHOLD',
                })
                .image({ uri: base64Image }, { width: 75 })
                .image(
                  {
                    uri: 'https://raw.githubusercontent.com/tr3v3r/react-native-esc-pos-printer/main/ios/store.png',
                  },
                  { width: 75 },
                )
                .barcode({
                  value: 'Test123',
                  type: 'EPOS2_BARCODE_CODE93',
                  width: 2,
                  height: 50,
                  hri: 'EPOS2_HRI_BELOW',
                })
                .qrcode({
                  value: 'Test123',
                  level: 'EPOS2_LEVEL_M',
                  width: 5,
                })
                .cut()
                .send();

              console.log('printing', status);
            }
          } catch (error) {
            console.log('error', error);
          }
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  box: {
    width: 60,
    height: 60,
    marginVertical: 20,
  },
});

@chukiatt
Copy link

chukiatt commented Dec 6, 2021 via email

@tr3v3r
Copy link
Owner

tr3v3r commented Dec 6, 2021

@rissois are you trying to connect via Wi-Fi or LAN? Can you confirm that ip
Address of the printer is in a range of router ip?

@rissois
Copy link
Author

rissois commented Dec 6, 2021

@tr3v3r
I am attempting to use my laptop to communicate with them via Wi-Fi, but the printers themselves are connected to the router via LAN (ethernet).

For the second question, are you referring to physical proximity or the subnet? I have printed the status sheet for each printer, and the TCP/IP status lists the same network address for both (they share the same first 9 digits).

Hopefully that is helpful, please let me know if I misinterpreted any your questions. I appreciate the response.

EDIT: Subnet mask is 255.255.255.0, so pretty standard there.

@rissois
Copy link
Author

rissois commented Dec 17, 2021

@tr3v3r

Another observation I forgot to mention: the Discovery returns the single printer before the full 10 seconds completes, so this may be a premature response.

@tr3v3r
Copy link
Owner

tr3v3r commented Dec 17, 2021

@rissois Actually 10 sec it's just a timeout to stop discovery if nothing is found. Since I have only one printer currently it would be nice if you could figure out the problem.

Here is how the discovery of the printer works:

JS side:

...
discoveryEventEmmiter.addListener(
          'onDiscoveryDone',
          (printers: IPrinter[]) => {
            res(printers);
            removeListener();
          }
        );
        
...

iOS native side - node_modules/react-native-esc-pos-printer/ios/EscPosPrinterDiscovery.m

- (void) onDiscovery:(Epos2DeviceInfo *)deviceInfo
{
    [_printerList addObject:deviceInfo];

    NSMutableArray *stringArray = [[NSMutableArray alloc] init];
    
    // you can log what actually is returned by SDK

    for (int i = 0; i < [_printerList count]; i++)
    {
        Epos2DeviceInfo *info = _printerList[i];
        NSString *name = [info getDeviceName];
        NSString *ip = [info getIpAddress];
        NSString *mac = [info getMacAddress];
        NSString *target = [info getTarget];
        NSString *bt = [info getBdAddress];
        NSString *usb = [self getUSBAddress: target];

        [stringArray addObject:@{
            @"name": name,
            @"ip": ip,
            @"mac": mac,
            @"target": target,
            @"bt": bt,
            @"usb": usb
        }];
    }


    [self sendEventWithName:@"onDiscoveryDone" body:stringArray];

    NSLog(@"Discovery done!");
}



I left a comment on the iOS native side. Could you please try to LOG what is returned by native SDK?

@fragilehm
Copy link
Contributor

fragilehm commented Dec 28, 2021

@tr3v3r I am still having the issue mentioned on #37, which I am now thinking that passing longer timeout isn't a real solution but just a coincidence that it found the printer (but still probably not a bad thing to allow passing the timeout from JS side).

So I have TM-m30 Bluetooth, which works perfectly on ios, immediately discovered every time, but on Android, it is still not consistent, it doesn't return the printer sometimes. I have tried adding some logs in onDiscovery which is called when the printer is being discovered and added to the list, but sometimes that method is not called meaning the printer wasn't discovered, and even with 10 seconds of timeout it also fails sometimes. So there is something fundamentally not working as expected.

@fragilehm
Copy link
Contributor

@tr3v3r I am still having the issue mentioned on #37, which I am now thinking that passing longer timeout isn't a real solution but just a coincidence that it found the printer (but still probably not a bad thing to allow passing the timeout from JS side).

So I have TM-m30 Bluetooth, which works perfectly on ios, immediately discovered every time, but on Android, it is still not consistent, it doesn't return the printer sometimes. I have tried adding some logs in onDiscovery which is called when the printer is being discovered and added to the list, but sometimes that method is not called meaning the printer wasn't discovered, and even with 10 seconds of timeout it also fails sometimes. So there is something fundamentally not working as expected.

After more debugging, I noticed that the printer discovery may take considerably longer, so I just did 50 seconds as a timeout and sometimes the onDiscovery is being called after 11-15 seconds, which is way higher than the default 5 seconds and could potentially be the reason of missing printers, I am not entirely sure what is the logic of the discovery but 15 seconds seems to be quite long especially for checking the Bluetooth printers.

@tr3v3r
Copy link
Owner

tr3v3r commented Dec 28, 2021

@fragilehm Hi! I suppose the reason could not be with discovery but with establishing the connection between device and printer.
Have you tried to connect using BT/IP address without searching (discover) in advance?

Also, have you tried to test on different devices with different OS versions? The problem may lie with Android/Arc. version.

Then we need to research this problem in the context of native Android apps since this library is just a simple wrapper above native SDK, moreover, we can try to test it using the latest SDK ( possibly the problem has been already fixed by Epson).

Current SDK ver. used in this lib is 2.17.1.
Here the link to the latest one https://download.epson-biz.com/modules/pos/index.php?page=soft&scat=61

P.S. Unfortunately I have only one LAN printer all hopes for contributors )

image

@fragilehm
Copy link
Contributor

fragilehm commented Dec 29, 2021

@tr3v3r Yes, I have tried updating to the latest SDK just replacing the necessary files in node_modules directly and rebuilding the app, but nothing changed. Maybe I was updating the wrong way.
So I have replaced:

  1. android/libs/ePOS2.jar
  2. android/src/main/jniLibs all files in this directory

This should work right or any other files I have missed maybe?

@tr3v3r
Copy link
Owner

tr3v3r commented Dec 29, 2021

@fragilehm should work. Ok what about other points I’ve mentioned?

@tr3v3r tr3v3r added the help wanted Extra attention is needed label Dec 29, 2021
@hetoms
Copy link

hetoms commented Jan 19, 2022

Had the same issue so decided to debug it to best of my knowledge.
Setup:

  • iPad mini using wifi
  • TM-20II using wired network
  • TM-m30 over BT - iPad and printer are already paired

I added a breakpoint in xCode to EscPosPrinterDiscovery.m to see whats happening in onDiscovery.
When calling EscPosPrinter.discover once the onDiscovery method gets invoked twice for me.
First time there is only one device in the list (absolutely lottery what it finds first).
After I continue the execution JS already get's the response with discovered printers (only 1) and then onDiscovery breakpoint is hit the second time but now there are two devices in the list but altho "onDiscoveryDone" event is dispatched there is no-one listening for the response anymore as discover in index.tsx on line 66 has already resolved the promise. Also in debug console I can see the following warning about it:
LogBox.js:173 Sending `onDiscoveryDone` with no listeners registered.

I'll try to dig into it a bit more tomorrow and I can also test out other scenarios if you want.

@tr3v3r
Copy link
Owner

tr3v3r commented Jan 20, 2022

Wow! Thanks a lot
I realized one thing after your investigation.
Possibly discover process is not “one time action” and we should discovery and listen for all updates during the search.

so instead

startDiscovery().then( // one time result )

We need

onDiscover(printers => // update every time native side updates) 

startDiscovery() // now it’ll search forever until  we stop it manually 

Right now I can’t prove it because of huge workload (

@fragilehm
Copy link
Contributor

@tr3v3r that is indeed the case, so what happens is the discovery gets resolved as soon as the first printer is found as the onDiscoveryDone event is fired when the first printer gets discovered on the native side. And in fact, the timeout doesn't do anything in this case if the first found printer was discovered before the timeout. So I can make a PR that actually fires onDiscoveryDone event only on timeout, which will return all discovered printers within that time frame (have already tested on ios and it works as expected) But I can imagine this behavior will affect the existing package integrators as the first discovery (promise resolve when onDiscoveryDone is called) would be before the timeout (might even be just one second) and now, the promise will be resolved only after the delay (default 5 seconds). But the current implementation is for sure not the right one. So, how do you think we should solve this backward compatibility issue? Maybe we can leave the existing discovery function that resolves on the first found printer and create a new one that will behave as expected (returning all discovered printers after the timeout, and we might also include another callback param that will be called after each printer discovery) or we can also make a BREAKING CHANGE update with the new way of handling the discovery?

@tr3v3r
Copy link
Owner

tr3v3r commented Feb 14, 2023

As a workaround please try using this.

@tr3v3r
Copy link
Owner

tr3v3r commented Nov 12, 2023

@tr3v3r tr3v3r closed this as completed Nov 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

5 participants