qzind / tray

Browser plugin for sending documents and raw commands to a printer or attached device.
https://qz.io
Other
851 stars 276 forks source link

Deploy Multi-scales and printer within QZ Tray Code #1158

Closed anthonylaney closed 1 year ago

anthonylaney commented 1 year ago

'use strict';

/**
 * util function
 *
 * @param str
 * @returns {boolean}
 */

function emptyOrUndefined(str) {
    return(str === '' || str === undefined || str === 'undefined');
}

const scale = {
    // this must be set
    scaleType: undefined,
    scalePort: undefined,
    errorHandler: undefined,
    scaleTypes: [
        ['adams', 'Adams'],
        ['adamsNTEP', 'Adams NTEP'],
        ['cardinal', 'Cardinal 190'],
        ['cas', 'CAS'],
        ['optima', 'Legend/Optima'],
        ['optima-2', 'Legend/Optima version 2'],
        ['mettler', 'Mettler'],
        ['ohaus', 'Ohaus'],
        ['torrey', 'Torrey']
    ],

    modalChg: function(state) {
        if (state === 'show') {
            // start the scale sending
            if (scale.scaleType === 'cas') {
                // send the W with even parity to start the scale
                let that = this
                qz.serial.sendData(scale.scalePort, 'W', '').catch(that.errorHandler);
            }
            if (scale.scaleType === 'torrey') {
                // send the W with even parity to start the scale
                let that = this
                qz.serial.sendData(scale.scalePort, 'P', '').catch(that.errorHandler);
            }
        } else if (state === 'hide') {
            // stop the scale from sending
            if (scale.scaleType === 'cas') {
                // send the 0x0d with even parity to stop the scale
                let that = this
                qz.serial.sendData(scale.scalePort, '\r', '').catch(that.errorHandler);
            }
        }
    },

    /**
     * deal with errors by logging to the console or calling the errorHandler
     *
     * @param msg
     */
    handleError: function( msg ) {
        if (this.errorHandler === undefined) {
            console.log(msg);
        } else {
            this.errorHandler(msg);
        }
    },

    /**
     *
     * @param obj
     */
    fillInList: function (obj) {
        for (let i = 0; i < this.scaleTypes.length; i++) {
            let opt = new Option(this.scaleTypes[i][1], this.scaleTypes[i][0]);
            obj.add(opt);
            if (!emptyOrUndefined(this.scaleType)) {
                // if scaleType is set, then we want to select the scaleType that matches
                if (this.scaleTypes[i][0] === this.scaleType) {
                    obj.selectedIndex = i;
                }
            }
        }
    },

    /**
     *
     * @param scaleType
     * @param scalePort
     */
    openPort: function(scaleType=this.scaleType, scalePort=this.scalePort) {
        let properties;

        if (!emptyOrUndefined(scaleType) && this.scaleType !== scaleType) {
            this.scaleType = scaleType;
        }

        if (!emptyOrUndefined(scalePort) && this.scalePort !== scalePort) {
            this.scalePort = scalePort;
        }

        if (this.scaleType === 'adams') {
            properties = {
                baudRate: 9600,
                dataBits: 8,
                stopBits: 1,
                parity: 'NONE',
                flowControl: 'NONE',
                encoding: 'UTF-8',
                rx: {
                    start: 'G',
                    end: '\x0a',
                    width: null,
                    lengthBytes: null,
                    crcBytes: null,
                    includeHeader: true,
                    encoding: '',
                    scaleType: this.scaleType
                }
            };
        } else if (this.scaleType === 'adamsNTEP') {
            properties = {
                baudRate: 19200,
                dataBits: 8,
                stopBits: 1,
                parity: 'NONE',
                flowControl: 'NONE',
                encoding: 'UTF-8',
                rx: {
                    start: null,
                    end: null,
                    width: null,
                    lengthBytes: null,
                    crcBytes: null,
                    includeHeader: true,
                    encoding: '',
                    parseLines: true
                }
            };
        } else if (scaleType === 'cardinal') {
            properties = {
                baudRate: 9600,
                dataBits: 8,
                stopBits: 1,
                parity: 'NONE',
                flowControl: 'NONE',
                encoding: 'UTF-8',
                rx: {
                    start: '\u000a',
                    end:   '\u000d',
                    width: null,
                    lengthBytes: null,
                    crcBytes: null,
                    includeHeader: false,
                    encoding: '',
                    parseLines: false,
                    debug: 1,
                    scaleType: 'cardinal'
                }
            };
        } else if (this.scaleType === 'cas') {
            properties = {
                baudRate: 9600,
                dataBits: 8,
                stopBits: 1,
                parity: 'NONE',
                flowControl: 'NONE',
                encoding: 'UTF-8',
                rx: {
                    start: '\u0002',
                    end: '\u000d',
                    width: null,
                    lengthBytes: null,
                    crcBytes: null,
                    includeHeader: false,
                    encoding: '',
                    parseLines: false,
                    scaleType: this.scaleType
                }
            };
        } else if (this.scaleType === 'torrey') {
            properties = {
                baudRate: 9600,
                dataBits: 8,
                stopBits: 1,
                parity: 'NONE',
                flowControl: 'NONE',
                encoding: 'UTF-8',
                rx: {
                    start: null,
                    end: '\u000d',
                    width: null,
                    lengthBytes: null,
                    includeHeader: true,
                    encoding: '',
                    crcBytes: null,
                    parseLines: true,
                    scaleType: this.scaleType
                }
            };
        } else if (this.scaleType === 'mettler' || this.scaleType === 'ohaus') {
            // for a real mettler it should be 7 databits 1 stop and 1 parity EVEN
            properties = {
                baudRate: 9600,
                dataBits: 8,
                stopBits: 1,
                parity: 'NONE',
                flowControl: 'NONE',
                encoding: 'UTF-8',
                rx: {
                    start: null,
                    end: null,
                    width: null,
                    lengthBytes: null,
                    crcBytes: null,
                    includeHeader: true,
                    encoding: '',
                    parseLines: true,
                    scaleType: this.scaleType
                }
            };
        } else if (this.scaleType === 'optima') {
            properties = {
                baudRate: 9600,
                dataBits: 8,
                stopBits: 1,
                parity: 'NONE',
                flowControl: 'NONE',
                encoding: 'UTF-8',
                rx: {
                    start: '\u0002',
                    end: '\u000a',
                    width: null,
                    lengthBytes: null,
                    crcBytes: null,
                    includeHeader: false,
                    encoding: '',
                    parseLines: false,
                    scaleType: this.scaleType
                }
            };
        } else if (this.scaleType === 'optima-2') {
            properties = {
                baudRate: 9600,
                dataBits: 8,
                stopBits: 1,
                parity: 'NONE',
                flowControl: 'NONE',
                encoding: 'UTF-8',
                rx: {
                    start: '\u0002',
                    end: '\u000d',
                    width: null,
                    lengthBytes: null,
                    crcBytes: null,
                    includeHeader: false,
                    encoding: '',
                    parseLines: false,
                    scaleType: this.scaleType
                }
            };
        } else if (emptyOrUndefined(this.scaleType) || emptyOrUndefined(this.scalePort)) {
            // looks like things were not setup correctly so error out
            // show something to the user and bale
            this.handleError('Either scale port or scale type is not set correctly');
            return;
        }

        if (this.scalePort === 'COMSIM') {
            this.handleError('Simulating COM port');
        } else {
            if (!emptyOrUndefined(cookies.getCookie('serialDebug'))) {
                // set the baud to 115200
                properties['baudRate'] = 115200;
            }
            // need to create variable for this
            let that = this;
            qz.serial.openPort(this.scalePort, properties).then(function () {
                // we opened port display something, somewhere to let the user know
                // or maybe only display when it fails
                that.handleError(`${that.scaleType} port ${that.scalePort} opened`);
                if (!emptyOrUndefined(cookies.getCookie('serialDebugSend'))) {
                    // if we want to debug the serial then send some data
                    console.log('We sent it');
                    qz.serial.sendData(that.scalePort, 'H\r\n', '').catch(displayError);
                }
            }).catch(displayError);
        }
    },

    /**
     *
     */
    closePort: function() {
        if (emptyOrUndefined(this. scalePort)) {
            // looks like things were not setup correctly so error out
            // show something to the user and bale
            this.handleError('Scale port is not set');
            return;
        }
        let that = this;

        qz.serial.closePort(this.scalePort).then(function () {

            that.handleError('${this.scaleType} port ${this.scalePort} closed');
        }).catch(displayError);
    },

    /**
     * This is the serial callback handler
     *
     * @param evt
     * @param shouldI
     * @param inputHandler
     */
    handleInput : function(evt, shouldI, inputHandler) {
        if (evt.type !== 'ERROR') {
            if (shouldI()) {
                // we received a message from the scale.
                //displayMessage('Serial', evt.portName, 'received output', evt.output);
                // parse the input
                let curWeight;

                if (this.scaleType === 'adams') {
                    // parse info from adams
                    // get the state
                    if (evt.output.length === 2) {
                        // this is just a CR/LF coming back. We may need to keep track of these
                    } else {
                         //let parsedOutput = evt.output.split(' ');
                        let parsedOutput = evt.output.replace(/\s\s+/g, ' ');
                        //let parsedOutput = evt.output.replace(/  +/g, ' ');
                        parsedOutput = parsedOutput.split(' ');
                        if ((parsedOutput.length >= 3) && (parsedOutput[0] === 'G/W:+')) {
                            curWeight = parsedOutput[1];
                        }
                    }
                } else if (this.scaleType === 'adamsNTEP') {
                    // adams NTEP outputs a few lines, remove all multiple spaces
                    let parsedOutput = evt.output.replace(/  +/g, ' ');
                    // now remove all CR
                    parsedOutput = parsedOutput.replace(/\r/g, '');
                    parsedOutput = parsedOutput.split('\n');
                    let lastEntry = parsedOutput.length - 1;

                    if ((lastEntry === 6) && parsedOutput[lastEntry].startsWith('Gross')) {
                        let grossWeight = parsedOutput[lastEntry].split(' ');
                        if (grossWeight.length === 4) {
                            curWeight = grossWeight[2];
                        }
                    }
                } else if (this.scaleType === 'mettler') {
                    // parse info from mettler, it seems it is one line 'Net x.yy lb \r\n'
                    let parsedOutput = evt.output.split(' ');
                    if ((parsedOutput.length === 4) && (parsedOutput[0] === 'Net') && (parsedOutput[2] === 'lb')) {
                        // parsedOutput[1] should be our weight

                        curWeight = parsedOutput[1];
                    }
                } else if (this.scaleType === 'ohaus') {
                    // parse info from ohaus, it seems it is one line '+/- x.yy(7) units(5) ?(1) legend(3)\r\n'
                    let parsedOutput = evt.output.split(/\s+/);
                    // if the weight is positive and it is stable, Then there are 3 fields
                    if ((parsedOutput.length === 4) && (parsedOutput[2] === 'lb') && (parsedOutput[3] === 'NET')) {
                        // parsedOutput[0] should be our weight

                        curWeight = parsedOutput[1];
                    }
                } else if (this.scaleType === 'cas') {
                    // parse info from cas, it is 5 bytes with a leading 0
                    // it is 0xxxx and we have to change it into xx.xx
                    let parsedOutput = evt.output;
                    if ((parsedOutput.length === 5) && (parsedOutput.charAt(0) === '0')) {
                        curWeight = parseInt(parsedOutput) / 100.0;
                    }
                } else if (this.scaleType === 'torrey') {
                    // parse info from torrey, it is 5 bytes with a leading 0
                    // it is 0xxxx and we have to change it into xx.xx
                    let parsedOutput = evt.output.replace(/\s\s+/g, ' ');
                    if (parsedOutput.length >= 5) {
                        parsedOutput = parsedOutput.split(' ');
                        curWeight = parsedOutput[1];
                    }
                } else if (this.scaleType === 'optima') {
                    // parse info from optima
                    let parsedOutput = evt.output;  
              //alert(parsedOutput);
                    if (((parsedOutput.length === 13) || (parsedOutput.length === 12)) &&
                        (parsedOutput.charAt(parsedOutput.length - 1) === '\r')) {
                        parsedOutput = parsedOutput.substr(1, 8);
                        curWeight = parseFloat(parsedOutput);
                    }
                } else if (this.scaleType === 'optima-2') {
                    // parse info from optima
                    let parsedOutput = evt.output;
                    if (((parsedOutput.length === 14) || (parsedOutput.length === 13))) {
                        parsedOutput = parsedOutput.substr(1, 8);
                        curWeight = parseFloat(parsedOutput);
                    }
                } else if (this.scaleType === 'cardinal') {
                    // parse info from consolidated
                    let parsedOutput = evt.output;
                    if (parsedOutput.length === 18) {
                        parsedOutput = parsedOutput.substr(5, 10);
                        curWeight = parseFloat(parsedOutput);
                    }
                }
                if (curWeight !== undefined) {
                    inputHandler(curWeight);
                }
            }
        } else {
            this.handleError(evt.exception);
        }
    }
};
tresf commented 1 year ago

This could probably be added to our serial documentation. I'll cross-link for now: https://github.com/qzind/tray/wiki/Serial#mettler-toledo