How to Integrate an MEI BNR Bill Recycler into Your Website with JavaScript

Dispense cash from your kiosk with an MEI BNR Bill Recycler
MEI BNR Bill Recycler

It’s easy to dispense bills from your kiosk like a cashier when you integrate an MEI BNR bill recycler into your website using JavaScript and KioskSimple.  This article will include a detailed JavaScript website code example so you can try it out for free.

You’re probably reading this article because you’ve decided to create a website which needs to accept cash payments, but also needs to dispense change in whole bills.  Maybe your website is running on a self-service kiosk or unattended payment solution.

Integrating a bill recycler can be extremely time-consuming and dispensing cash from your kiosk is fraught with risk.  Fortunately we’ve done all the heavy lifting in KioskSimple to provide you with a high-level, simple and straightforward JavaScript API for the MEI BNR so you can get started dispensing cash quickly.

The example website we’ve create to get you started quickly is pictured below and has the following features:

  • Enables and disable the MEI BNR bill recycler
  • Displays the user’s credit (see Session Funds)
  • Dispenses cash
  • Rolls back a transaction
  • Empties the bill recycler
  • Generates an audit report
  • Includes a Result Output window which displays diagnostics from the MEI BNR bill recycler when you insert bills
MEI BNR JavaScript Example
MEI BNR Bill Recycler JavaScript Example

You can see from the following JavaScript code example the basic flow for interacting with the MEI BNR bill recycler is as follows…

  1. Initialize the KioskSimple API “window.external.KioskSimpleAPIInit();”
  2. Wire-up the bank events for tracking the user’s credit (OnCreditChanged)
  3. Wire-up the MEI BNR bill recycler events (BNROnCashIn, BNROnDispense, etc…)
  4. Enable the MEI BNR bill recycler and wait for the user to insert cash “BNR.Enable(0);”
var BNR = null;
//Assuming using jQuery, lets wait until the document has finished loading. 
$(document).ready(function () {
    //This reaches out to KioskSimple and requests API initialization
    try{
        window.external.KioskSimpleAPIInit();
    }
    catch (err) {

        //If we got here then we are not running within KioskSimple, lets disable all buttons and output to user
        $("#btnCashInStart").prop('disabled', true);
        $("#btnCashInEnd").prop('disabled', true);
        $("#btnDispense").prop('disabled', true);
        $("#btnRollback").prop('disabled', true);
        $("#btnEmpty").prop('disabled', true);
        $("#btnGenerateAuditReport").prop('disabled', true);
        outputActionResult("Initialization", "Something went wrong intitializing KioskSimple. Error:" + err)
        return;
    }
    //If we got this far, we are successfully running within KioskSimple's local code domain
    if (K()) {
        //If the credit in KioskSImple changes, lets update our own UI
        KioskSimple.Plugins.GetPlugin("Bank").OnCreditChanged = KSCreditChanged;
        //Get instance of BNR plugin, (if available)
        BNR = KioskSimple.Plugins.GetPlugin("MeiBNR");
        if (BNR != null) {
            //BNR is installed, lets setup UI and Handlers to interact with it
            setupUIButtons();
            setupBNRHandlers();
            

            //After setup , enable the BNR for communication
            BNR.Enable(0);
        }
    }

});

//Not 100% needed but a nice shortcut to determine if KS is preset.
function K() {
    return !(typeof KioskSimple === 'undefined')
}

//Handers to receive from the BNR plugin, gives us ability for cash workflow. More details at handler definition
function setupBNRHandlers() {

    BNR.OnBNRErrorJs = BNROnError;
    BNR.OnBNROpenedJs = BNROnOpened;
    BNR.OnBNRResetJs = BNROnReset;
    BNR.OnBNRClosedJs = BNROnClosed;
    BNR.OnBNRCashInStartJs = BNROnCashInStart;
    BNR.OnBNRCashInJs = BNROnCashIn;
    BNR.OnBNRCashEndJs = BNROnCashEnd;
    BNR.OnBNREmptyJs = BNROnEmpty;
    BNR.OnBNRDispenseJs = BNROnDispense;
    BNR.OnBNRRollBackJs = BNROnRollback;
    BNR.OnBNRCashAvailableJs = BNROnCashAvailable;
    BNR.OnBNRCashTakenJs = BNROnCashTaken;  
}
//KS Credit Changed Handler. Whenever credit changes in the KioskSImple instance. This handler will fire off. 
function KSCreditChanged(amount) {
    $("#currentCredit").html(amount);
}

//BNR Handlers
//This will fire when any error in the BNR plugin is thrown. 
function BNROnError(result, data) {
    var output = new Object();
    output.result = result;
    output.data = data;
    outputActionResult("BNROnError", "result:" + JSON.stringify(output))
}

//After the device is opened successfully, result will return "Success", or it will be populated with the reason of error. 
function BNROnOpened(result) {
    outputActionResult("BNROnOpened", "result:" + JSON.stringify(result))
    outputActionResult("Plugin", "name:" + BNR.GetName())

    BNR.Reset();  
}

//After power cycle of the BNR, empty cashbox of BNR or if the BNR is stuck in a certain state, send the reset command to the BNR. This also called when the BNR is opened.
function BNROnReset(result) {
    $("#btnCashInStart").prop('disabled', false);
    outputActionResult("BNROnReset", "result:" + JSON.stringify(result))
}

//Closing results
function BNROnClosed(result) {
    outputActionResult("BNROnClosed", "result:" + JSON.stringify(result))
}

//When starting to accept cash, there are TWO commands that need to be called. Call CashInStart to initiate the Accept Cash Mode. 
//After the mode has been initiated, a call to CashIn is needed in order to accept cash. 
function BNROnCashInStart(result) {
    outputActionResult("BNROnCashInStart", "result:" + JSON.stringify(result))
    BNR.CashIn();
}

//When the CashIn() method has been called and bills are inserted, this handler will fire with the amount and operational data. 
//If the program needs more cash (accept cash again) then another call to CashIn() is required. Repeat this cycle until the 
//desired amount of currency has been inserted. In this example handler, we credit KS bank with the cash amount. This is because 
//the BNR plugin does not automatically credit the local KS bank like other cash plugins do. The reason for this is because the ability to 
//rollback a cash transaction and these funds are considered escrow funds until the transaction is completed. (Complete a transaction by calling
//CashEnd().) Until CashEnd is called, the code can do a call Rollback() and all cash inserted will be returned. Since this escrow
//state esists within the BNR, KioskSimple will not reflect this as available funds and will hand off the management of funds to the 
//calling application. 
//
function BNROnCashIn(result, amount, data) {
  
    outputActionResult("BNROnCashIn", "result:" + JSON.stringify(formatCashOutput(result, amount, data)))
    creditKS(amount);
    BNR.CashIn();
}

//To end the cash accept state and commit the cash transaction, a call to CashEnd() is needed. This handler supplies the result.
function BNROnCashEnd(result) {
    outputActionResult("BNROnCashEnd", "result:" + JSON.stringify(result))
}

//To empty all recyclers to the cashbox, Empty() is called. This handler provides the amount collected into the cashbox plus operational data
function BNROnEmpty(result, amount, data) {
    outputActionResult("BNROnEmpty", "result:" + JSON.stringify(formatCashOutput(result, amount, data)))
}

//When dispensing currently, this handler will be fired when the cash is removed from the dispensing slot at the front of the BNR
function BNROnDispense(result, amount, data) {
    debitKSBank(amount);
    outputActionResult("BNROnDispense", "result:" + JSON.stringify(formatCashOutput(result, amount, data)))
}

//When a transaction is desired to be rolled back, Rollback() is called and this handler will provide data for amount dispensed and operational data
function BNROnRollback(result, amount, data) {
    debitKSBank(amount);
    outputActionResult("BNROnRollback", "result:" + JSON.stringify(formatCashOutput(result, amount, data)))
}

//when dispensing or rollback, this handler is an indicator that cash has been presented to the user
function BNROnCashAvailable(result, amount, data) {
    outputActionResult("BNROnCashAvailable", "result:" + JSON.stringify(formatCashOutput(result, amount, data)))
}

//and this handler will fire when the cash is removed (in conjunction with the dispense handler)
function BNROnCashTaken(result, amount, data) {
    outputActionResult("BNROnCashTaken", "result:" + JSON.stringify(formatCashOutput(result, amount, data)))
}

function setupUIButtons() {
    $("#btnCashInStart").click(function () {
        BNR.CashInStart();
    });

    $("#btnCashInEnd").click(function () {
        BNR.CashEnd();
    });

    //The Dispense(int) takes an integer>100 and with the multiple of 100. For instance dispensing $1.00 is 100 and dispensing $32.00 is 3200.
    $("#btnDispense").click(function () {
        BNR.Dispense(100);//dispenses $1.00
    });

    $("#btnRollback").click(function () {
        BNR.RollBack();
    });

    //Will empty all recyclers into the cashbox.
    $("#btnEmpty").click(function () {
        BNR.Empty();
    });

    //For diagnostic purposes (to provide to MEI or self analysis), this command will create an audit report of the current device state and resent transactions of the device
    $("#btnGenerateAuditReport").click(function () {
        BNR.GenerateAuditReport("C:\\temp\\audit.txt"); //folder path needs to exist on host machine.
    });
}

function outputActionResult(actionName, data) {
    var output = "<a href='#' class='list-group-item'><h4 class='list-group-item-heading'>Action Result: " + actionName + "</h4><p class='list-group-item-text'>" + data + "</p></a>";
    $(".list-group").append(output);
}

function formatCashOutput(result, amount, data) {
    var output = new Object();
    output.result = result;
    output.amount = amount;
    output.data = data;
    return output;
}

function creditKS(amount) {
    if (K()) {
        KioskSimple.Plugins.GetPlugin("Bank").CreditKSBank(amount, "Example BNR Web App", 0);
    }
}

function debitKSBank(amount) {
    if (K()) {
        KioskSimple.Plugins.GetPlugin("Bank").DebitKSBank(amount);
    }
}

How to get this example working with a free demo of KioskSimple

KioskSimple configuration settings

  1. Download the example here called “MEI BNR Plugin Example – Web JavaScript” and store the uncompressed folder on your desktop.
  2. Download and install the free demo of KioskSimple.
  3. Connect an MEI BNR bill recycler to your PC.
  4. Run the KioskSimple Configuration Tool and navigate to the PLUGIN STORE.
  5. Install the MEI BNR Bill Recycler Plugin.  The configuration tool will restart and some dependencies will be installed.  You should now see a menu option called BILL ACCEPTORS.  Navigate there and select CONFIGURE.
  6. Under the Device Settings ensure that the device is enabled then click DETECT AND RESET the MEI BNR bill recycler to ensure its installed correctly.
  7. To configure the MEI BNR you need to use the proprietary BNR Configuration Tool provided by MEI.  MEI has requested that KioskSimple customers contact MEI directly to obtain this tool.  Please mention that you’re needing to integrate the MEI BNR with KioskSimple and they’ll get you a copy of their BNR configuration tool.
  8. Navigate to BROWSER->BROWSER SETTINGS and set the Start-up Web Page to the HTML file in this example.  In the case of my PC the path is “file:///C:/Users/Andrew/Desktop/web/Web/BNRTest.html”.  This could also point to your web server if you stored the folder there, but I find it easier to store the files locally for this example.
  9. Save your settings and close the KioskSimple Configuration Tool.

Running the example in KioskSimple

  1. Start KioskSimple.
  2. Select “Try the Demo” and then “Test Mode”.
  3. Now you’ll see the MEI BNR bill recycler website example shown above.  Press “Accept Cash” and the device should be ready to start accepting bills.  Now if you insert a bill you should see the Session Funds update and the Result Output change.
  4. When you’re done press ESC and any password will work while KioskSimple is unregistered.

Got Questions?

Please contact us and we’ll get you in touch with a developer.  We offer free phone and email technical support for all of our code examples.  Try finding that anywhere else in this industry.

We’re dedicated to making your next kiosk project a success and we’re happy to hold your hand through the hardware integration.

Andrew Savala
Follow me

Author: Andrew Savala

Andrew Savala is the CEO of RedSwimmer, with a background in designing and deploying complex payment kiosk systems. Andrew offers high-value, strategic consulting services to companies looking to develop their payment kiosks.