Cordova Bluetooth printer plugin demo

This is a small demo app for testing the functions from the Cordova-Plugin-BTPrinter plugin, which allows to use any bluetooth printer from your Cordova / Ionic app.

Install Plugin

To add the bluetooth printer plugin to your existing Cordova app, run this command:

cordova plugin add https://github.com/CesarBalzer/Cordova-Plugin-BTPrinter.git

In order to test the plugin’s functions, either download the demo app’s compiled APK or the source code below.

Using the bluetooth printer demo app

To use the demo app:

  1. Pair your android device with the desired bluetooth printer and turn bluetooth on
  2. Start the demo app and click status to check if bluetooth is active (optional)
  3. Click list to view all paired bluetooth devices (required)
  4. Click connect and wait a few seconds (required)
  5. Click connected to check if the connection is active (optional)
  6.  Start testing the provided methods as desired.
Cordova-plugin-btprinter demo app screenshot 1

Cordova-plugin-btprinter demo app screenshot 1

Cordova-plugin-btprinter demo app screenshot 2

Cordova-plugin-btprinter demo app screenshot 2

Methods from the demo app

Besides the status, list, connect, connected and disconnect methods, the following functions are provided by the demo app:

Reset

Send ESC @ (hex 1B40) to initialize the bluetooth printer. This command has the same effect as restarting the printer, so your encoding set with setEncoding will be cleared as well.

Line feed

Send LF command (hex A0) to insert a line feed and advance the paper in the printer.

Font demo

Prints a sample of different font types: underline 1-dot, underline 2-dot, bold, font type A, font type B.

Size demo

Prints a sample of different font sizes: 00 normal, 01 reduced, 10 double-height, 20 double-width, 30 double width and height.

Beep x1/x3

Sends a 1B420109 or 1B420309 POS command to beep the buzzer 1 or 3 times respectively. These codes do not match the EPSON buzzer codes, but they worked on the generic printer I’ve tested. This method is useful to beep the device after the printing process is complete.

Set encoding

Sets the encoding method used by the printer plugin, applied with mmOutputStream.write(msg.getBytes(encoding)); whenever a string is sent to the printer.

Set inverted mode

Sends POS command 1D4201 to enable inverted mode text and 1D4200 to disable it.

Send POS command

Sends an arbitrary ESC/POS command to the bluetooth printer. Refer to your particular printer model for supported commands, most printers should support the official EPSON commands by default.

Print base 64 image

Tests the printBase64 method to print the provided base-64 encoded image. There is another method to print images by path, but it’s not implemented in this demo app to avoid dealing with the endless caveats of file system plugin.

Print QR Code (demo app version 1.1.0)

Prints a Quick Response code with these options: model, size, error correction level. With my generic printer, all models show the same QR code, but size and alignment can be properly set.

BTPrinter plugin QR code sample

BTPrinter plugin QR code sample

Print Barcode (demo app version 1.1.0)

Prints a barcode with these options: system (format), characters position, font, height. With my cheap portable bluetooth printer, all fonts are the same, and only 2 height settings are applicable. Formats supported:

  • UPC-A (numbers 0-9)
  • UPC-E (numbers 0-9)
  • EAN13 / JAN13 (numbers 0-9)
  • EAN8 / JAN8 (numbers 0-9)
  • CODE39 (supports numbers+text)
  • ITF (does not work in my brandless printer)
  • CODABAR (supports numbers+text)
BTPrinter plugin barcode sample

BTPrinter plugin barcode sample

Ελληνικά Test

Greek language test, works as follows:

  • Calls the BTPrinter.setEncoding function with ISO-8859-7 character set.
  • Sends an ESC + t command (1B74 in hex) followed by the character tables: 11, 14, 15, 38, 47 in hex format, to set the character code table, and prints a sample text with each table. These tables correspond to all Greek code page variations CP851, CP737, ISO-8859-7, CP869 and CP1253 for EPSON printers.
  • By calling the demo app function testCP(cp_table_number) you can test any character table easily, however, remember to set the encoding properly before printing.

This function is quite tricky, and it failed to print properly in my generic printer, even after setting the encoding correctly. However, the printer’s demo ticket does not show non-latin-1 characters properly either, my guess is that the printer has left out these languages to save a few KB of memory (or neither me nor the manufacturer knows the table numbers for other languages). This should work just fine with decent printers, or those aimed for specific non-western-european markets.

greek language cordova bluetooth printer plugin btprinter

Greek language test with printer plugin using generic cheap printer for latin american market

Please send your comments and feedback in this page regarding printing in other languages and charsets with your specific printer model.

Sample ticket created by demo app with generic BT printer

Bluetooth thermal printer cordova btplugin sample ticket

Bluetooth thermal printer cordova btplugin sample ticket

The previous ticket shows the thermal printer’s output for different text formats and sizes, a base 64 encoded image sample, and a reversed color text sample.

Download the bluetooth printer demo app

You can test the provided source code by creating a Cordova app, installing the plugin, and replacing the www folder contents with the provided one.

BTPrinter plugin usage considerations

  • The plugin does not discover nor pair with devices, therefore the user must pair with the printer using the Android Bluetooth/Connection settings before using the print functions.
  • The plugin will list all paired Bluetooth devices, not just printers. If a single device is found, we could assume it is a bluetooth printer and go ahead with the connection, but if more than 1 device is found a Select Bluetooth Device dialog should be implemented.
  • Do not reconnect to an already connected printer, this will return an error. Use the connected method to check if a printer is already connected and jump directly to printing if this is the case.

Index.js source code

This file includes all the functions and methods from the demo app.

/* global BTPrinter */
var app = {
  initialize: function() {
    if (typeof(window.cordova) !== 'undefined') {
      document.addEventListener('deviceready', function() {
        onDeviceReady(true);
      }, false);
    } else {
      onDeviceReady(false);
    }
  }
};

function onDeviceReady() {
  // Cordova has been loaded. Perform any initialization that requires Cordova here.
  console.log('onDeviceReady()');

  // Handle the Cordova pause and resume events
  document.addEventListener('pause', onPause.bind(this), false);
  document.addEventListener('resume', onResume.bind(this), false);

  /* Initialize plugin */
  if (typeof(BTPrinter) === 'undefined') {
    // Error: plugin not installed
    console.error('Error: BTPrinter plugin not detected');
    window.plugins.toast.showLongBottom('BTPrinter plugin not detected');
  } else {
    // Bind action buttons
    $('#list').click(function() {
      BTPrinter.list(function(data) {
        console.log('list: success');
        window.plugins.toast.showLongBottom('list: success');
        $('#btpPrinter').empty().prop('disabled', false);
        $.each(data, function(idx, value) {
          /* Add devices (array contains device name every 3 array elements) */
          if (idx % 3 === 0) {
            $('#btpPrinter').append('' + data[idx] + ' (' + data[idx + 1] + ')');
          }
        });
      }, function(err) {
        console.error('list: ' + err);
        window.plugins.toast.showLongBottom('list: ' + err);
        $('#btpPrinter').empty().prop('disabled', true);
      });
    });
    $('#status').click(function() {
      BTPrinter.status(function(data) {
        console.log('status: ' + data);
        window.plugins.toast.showLongBottom('status: ' + data);
      }, function(err) {
        console.error('status: ' + err);
        window.plugins.toast.showLongBottom('status: ' + err);
      });
    });
    $('#connected').click(function() {
      BTPrinter.connected(function(data) {
        console.log('connected: ' + data);
        window.plugins.toast.showLongBottom('connected: ' + data);
      }, function(err) {
        console.error('connected:' + err);
        window.plugins.toast.showLongBottom('connected: ' + err);
      });
    });
    $('#connect').click(function() {
      $('#connect').prop('disabled', true);
      window.setTimeout(function() {
        /* Use timeout to properly update GUI first */
        var strPrinter = $('#btpPrinter option:selected').attr('data-name');
        BTPrinter.connect(function(data) {
          console.log('connect: ' + data);
          window.plugins.toast.showLongBottom('connect: ' + data);
          $('#connect').prop('disabled', false);
        }, function(err) {
          console.error('connect: ' + err);
          window.plugins.toast.showLongBottom('connect: ' + err);
          $('#connect').prop('disabled', false);
        }, strPrinter);
      }, 100);
    });
    $('#disconnect').click(function() {
      BTPrinter.disconnect(function(data) {
        console.log('disconnect: ' + data);
        window.plugins.toast.showLongBottom('disconnect: ' + data);
      }, function(err) {
        console.error('disconnect: ' + err);
        window.plugins.toast.showLongBottom('disconnect: ' + err);
      });
    });
    $('#printQRCode').click(function() {
      var data = $('#txtQRData').val();
      var align = $('#optAlign').val();
      var model = $('#optQRModel').val();
      var size = $('#optQRSize').val();
      var eclevel = $('#optQREclevel').val();
      BTPrinter.printQRCode(function(data) {
        console.log('printQRCode:' + data);
        window.plugins.toast.showLongBottom('printQRCode:' + data);
      }, function(err) {
        console.error('printQRCode:' + err);
        window.plugins.toast.showLongBottom('printQRCode:' + err);
      }, data, align, model, size, eclevel);
      $('#lineFeed').click();
    });
    $('#printBarcode').click(function() {
      var system = $('#optBCSystem').val();
      var data = $('#txtBarcode').val();
      var align = $('#optAlign').val();
      var position = $('#optBCPosition').val();
      var font = $('#optBCFont').val();
      var height = $('#optBCHeight').val();
      BTPrinter.printBarcode(function(data) {
        console.log();
        window.plugins.toast.showLongBottom('printBarcode: ' + data);
      }, function(err) {
        console.error(err);
        window.plugins.toast.showLongBottom('printBarcode: ' + err);
      }, system, data, align, position, font, height);
      $('#lineFeed').click();
    });
    $('#setEncoding').click(function() {
      var strEncoding = $('#txtEncoding').val();
      BTPrinter.setEncoding(function(data) {
        console.log('setEncoding: ' + data);
        window.plugins.toast.showLongBottom('setEncoding: ' + data);
      }, function(err) {
        console.error('setEncoding: ' + err);
        window.plugins.toast.showLongBottom('setEncoding: ' + err);
      }, strEncoding);
    });
    $('#printText').click(function() {
      var strText = $('#txtSample').val() + "\n";
      BTPrinter.printText(function(data) {
        console.log('printText: ' + data);
        window.plugins.toast.showLongBottom('printText: ' + data);
      }, function(err) {
        console.error('printText: ' + err);
        window.plugins.toast.showLongBottom('printText: ' + err);
      }, strText);
    });
    $('#printTextSizeAlign').click(function() {
      var strText = $('#txtSample').val();
      var strSize = $('#optSize option:selected').val();
      var strAlign = $('#optAlign option:selected').val();
      BTPrinter.printTextSizeAlign(function(data) {
        console.log('printTextSizeAlign: ' + data);
        window.plugins.toast.showLongBottom('printTextSizeAlign: ' + data);
      }, function(err) {
        console.error('printTextSizeAlign: ' + err);
        window.plugins.toast.showLongBottom('printTextSizeAlign: ' + err);
      }, strText, strSize, strAlign);
    });
    $('#printTitle').click(function() {
      var strText = $('#txtSample').val();
      var strSize = $('#optSize option:selected').val();
      var strAlign = $('#optAlign option:selected').val();
      BTPrinter.printTitle(function(data) {
        console.log('printTitle: ' + data);
        window.plugins.toast.showLongBottom('printTitle: ' + data);
      }, function(err) {
        console.error('printTitle: ' + err);
        window.plugins.toast.showLongBottom('printTitle: ' + err);
      }, strText, strSize, strAlign);
    });
    $('#printPOSCommand').click(function() {
      var printPOS = $('#txtPOS').val();
      BTPrinter.printPOSCommand(function(data) {
        console.log('printPOSCommand: ' + data);
        window.plugins.toast.showLongBottom('printPOSCommand: ' + data);
      }, function(err) {
        console.error('printPOSCommand: ' + err);
        window.plugins.toast.showLongBottom('printPOSCommand: ' + err);
      }, printPOS);
    });
    $('#printBase64').click(function() {
      var printBase64 = $('#txtBase64').val();
      var strAlign = $('#optAlign option:selected').val();
      BTPrinter.printBase64(function(data) {
        console.log('printBase64: ' + data);
        window.plugins.toast.showLongBottom('printBase64: ' + data);
      }, function(err) {
        console.error('printBase64: ' + err);
        window.plugins.toast.showLongBottom('printBase64: ' + err);
      }, printBase64, strAlign);
      // Print extras
      $('#txtSample').val('>>> Sent POS:FEED+BEEP');
      $('#printText').click();
      $('#lineFeed').click();
      $('#beepX3').click();
    });
    $('#reset').click(function() {
      // Clear data in buffer and reset modes
      var bytes = '1B40'; /* Initialize printer: https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=192 */
      $('#txtPOS').val(bytes);
      $('#printPOSCommand').click();
      // Reset GUI
      $('#txtSample').val("» BTPrinter Plugin Demo\n» ©2020 Andrés Zsögön");
      $('#optAlign').val(0);
      $('#optSize').val('00');
      $('#invertedIcon').hide();
    });
    $('#lineFeed').click(function() {
      // Print line feed
      var bytes = '0A';
      $('#txtPOS').val(bytes);
      $('#printPOSCommand').click();
    });
    $('#fontDemo').click(function() {
      var TXT_UNDERL_OFF = '1b2d00'; // bluetooth printer underline OFF
      var TXT_UNDERL_ON = '1b2d01'; // bluetooth printer underline font 1-dot ON
      var TXT_UNDERL2_ON = '1b2d02'; // bluetooth printer underline font 2-dot ON
      var TXT_BOLD_OFF = '1b4500'; // bluetooth printer bold font OFF
      var TXT_BOLD_ON = '1b4501'; // bluetooth printer bold font ON
      var TXT_FONT_A = '1b4d48'; // bluetooth printer font type A
      var TXT_FONT_B = '1b4d01'; // bluetooth printer font type B

      $('#reset').click();
      $('#txtEncoding').val('ISO-8859-1');

      /* Print font types demo */
      $('#txtSample').val('>>> FONT DEMO');
      $('#printText').click();

      $('#txtPOS').val(TXT_UNDERL_ON);
      $('#printPOSCommand').click();
      $('#txtSample').val('Underline font 1-dot');
      $('#printText').click();
      $('#reset').click();

      $('#txtPOS').val(TXT_UNDERL2_ON);
      $('#printPOSCommand').click();
      $('#printPOSCommand').click();
      $('#txtSample').val('Underline font 2-dot');
      $('#printText').click();
      $('#reset').click();

      $('#txtPOS').val(TXT_BOLD_ON);
      $('#printPOSCommand').click();
      $('#txtSample').val('Bold font ON');
      $('#printText').click();
      $('#reset').click();

      $('#txtPOS').val(TXT_FONT_A);
      $('#printPOSCommand').click();
      $('#txtSample').val('Font type A');
      $('#printText').click();
      $('#reset').click();

      $('#txtPOS').val(TXT_FONT_B);
      $('#printPOSCommand').click();
      $('#txtSample').val('Font type B');
      $('#printText').click();

      $('#reset').click();
      $('#txtSample').val('>>> Sent POS:FEED+BEEP+RESET');
      $('#printText').click();

      $('#lineFeed').click();
      $('#beepX3').click();
      $('#reset').click();
    });
    $('#sizeDemo').click(function() {
      $('#reset').click();
      $('#txtEncoding').val('ISO-8859-1');

      /* Print font sizes demo */
      $('#txtSample').val('>>> SIZE DEMO');
      $('#printText').click();

      $('#optSize').val('00');
      $('#txtSample').val('00 Normal Size');
      $('#printTextSizeAlign').click();

      $('#optSize').val('01');
      $('#txtSample').val('01 Reduced Size');
      $('#printTextSizeAlign').click();

      $('#optSize').val('10');
      $('#txtSample').val('10 Double Height');
      $('#printTextSizeAlign').click();

      $('#optSize').val('20');
      $('#txtSample').val('20 Double Width');
      $('#printTextSizeAlign').click();

      $('#optSize').val('30');
      $('#txtSample').val('30 Quad Area');
      $('#printTextSizeAlign').click();

      $('#reset').click();
      $('#txtSample').val('>>> Sent POS:FEED+BEEP+RESET');
      $('#printText').click();

      $('#lineFeed').click();
      $('#beepX3').click();
      $('#reset').click();
    });
    $('#beepX1').click(function() {
      // Beeps 1 time for 9*50ms
      var bytes = '1B420109';
      $('#txtPOS').val(bytes);
      $('#printPOSCommand').click();
    });
    $('#beepX3').click(function() {
      // Beeps 3 times for 9*50ms each time
      var bytes = '1B420309';
      $('#txtPOS').val(bytes);
      $('#printPOSCommand').click();
    });
    $('#printGreek').click(function() {
      // Greek sample text
      $('#txtEncoding').val('ISO-8859-7');
      $('#txtSample').val('>>> Set Encoding: ISO-8859-7');
      $('#setEncoding').click();
      $('#printText').click(); // print performed action

      //				$('#txtPOS').val('1B740F'); /* (ESC t in HEX => 1B74) + (ISO-8859-7 => EPSON page 15 => 0F in HEX) */
      //				$('#txtSample').val('>>> Set POS: 1B740F');
      //				$('#printText').click(); // print performed action
      //				$('#txtSample').val('    0F=HEX for EPSON page #15');
      //				$('#printText').click(); // print performed action
      //				$('#printPOSCommand').click();

      /* Greek character tables modes test with ISO-8859-7 encoding */
      testCP(11);
      testCP(14);
      testCP(15);
      testCP(38);
      testCP(47);

      $('#lineFeed').click();
      $('#beepX3').click();

    });
    $('#enableInverted').click(function() {
      // Enable inverted color
      var bytes = '1D4201';
      $('#txtPOS').val(bytes);
      $('#printPOSCommand').click();
      $('#invertedIcon').fadeIn();
      $('#txtSample').val('< Inverted Mode ON >');
      $('#optAlign').val(1);
      $('#printTitle').click();
      $('#optAlign').val(0);
      $('#lineFeed').click();
      $('#beepX1').click();
    });
    $('#disableInverted').click(function() {
      // Disable inverted color
      var bytes = '1D4200';
      $('#txtPOS').val(bytes);
      $('#printPOSCommand').click();
      $('#invertedIcon').fadeOut();
      $('#txtSample').val('< Inverted Mode OFF >');
      $('#optAlign').val(1);
      $('#printTitle').click();
      $('#optAlign').val(0);
      $('#lineFeed').click();
      $('#beepX1').click();
    });
    /* Demo app links */
    $('#btnAndreszsogon').click(function() {
      window.open('http://www.andreszsogon.com/cordova-bluetooth-printer-plugin-demo-app/', '_system');
    });
    $('#btnWebsite').click(function() {
      window.open('https://github.com/CesarBalzer/Cordova-Plugin-BTPrinter', '_system');
    });
  }
}

function onPause() {
  // TODO: This application has been suspended. Save application state here.
}

function onResume() {
  // TODO: This application has been reactivated. Restore application state here.
}

function testCP(table) {
  // Convert table from decimal to hex
  var hexa = table.toString(16);
  hexa = hexa.toUpperCase();
  if (hexa.length == 1) {
    hexa = '0' + hexa;
  }
  // Run POS command ESC + t + table_hex
  var pos = '1B74' + hexa;
  $('#txtPOS').val(pos);
  $('#printPOSCommand').click();
  // Create sample text
  $('#txtSample').val('#' + table + ' POS ' + pos + ' ΑαΒβΓγΔδΕε');
  $('#printText').click();
}

/* Initialize app */
app.initialize();

Printer used for this demo

The demo app has been tested with a generic bluetooth portable thermal printer with a meaningless model number, as shown here. Device fails to print non-latin-1 characters even in the demo ticket printed by itself, probably because it was specifically aimed to the latin american market.

Portable bluetooth thermal printer

Portable bluetooth thermal printer for latin american market

All product names, logos, and brands in this website are property of their respective owners. All company, product and service names used in this website are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.