st-one-io / node-open-protocol

This node is an implementation of the Atlas Copco's Open Protocol. This node was created by Smart-Tech as part of the ST-One project.
GNU General Public License v3.0
31 stars 31 forks source link

Node Open Protocol

A library to interface with Power Tools using the Atlas Copco Open Protocol

This node was created by Smart-Tech as part of the ST-One project.

Documentation: Open Protocol R 2.8.0

What is Open Protocol?

Open Protocol is an interface for building applications for remote control or data subscription of industrial tightening controllers. It's an open specification led by Atlas Copco Industrial Technique AB, though it is implemented by most of the other tightening controller manufacturers.

What is this node?

This node is a Node.js library that implements the Atlas Copco's Open Protocol, being possible establish communication with tightening controllers. This library has several and the most common MIDs implemented.

Features

How use this node?

Install

npm install node-open-protocol

Instance and connection

The variable options is optional, in the example below it will be created with default values.

const openProtocol = require('node-open-protocol');

let options = {

    // Weather to use LinkLayer Acknowledgement
    //true: enforce activation
    //false: enforce deactivation
    //undefined: auto negotiate
    linkLayerActivate: undefined,

    // Weather to user Generic MID request/subscription
    //true: use generics
    //false or undefined: don't use generics
    genericMode: undefined,

    // How oft we send keep-alive messages (MID 9999), in milliseconds
    keepAlive: 10000,

    // Weather the library will append a parameter "_raw" with the Buffer as received from the controller
    rawData: false,

    // How long we'll wait for an acknowledge of the controller to a message that we send, in milliseconds
    timeOut: 3000,

    // How many times we'll retry to send a message if we don't receive an answer
    retryTimes: 3,

    // A list of MIDs for which we'll not parse the payload
    disableMidParsing: {}
}

let controllerIp = "127.0.0.1";
let controllerPort = 4545;

let op = openProtocol.createClient(controllerPort, controllerIp , options, (data) => {
    console.log("Connected");
    console.log("MID 0002", data);
});

or then simply:

const openProtocol = require('node-open-protocol');

let controllerIp = "127.0.0.1";
let controllerPort = "4545";

let op = openProtocol.createClient(controllerPort, controllerIp, (data) => {
    // data is the content of MID 0002
    console.log("Connected");
    console.log("MID 0002", data);
});

Methods

All calls follow a standard structure:

op.__OPERATION__(midGroup, opts, callback);

where:

//To MIDs not implemented
let opts = {
    revision: 1,
    payload: "mid body" //String or buffer
}

//To MIDs implemented with additional parameters
//Example MID 0018 - selectPset
let opts = {
    payload: {
        parameterSetID: 2
    }
}

Subscribe

The subscribe method is used to subscribe to controller events. The incoming data from these events will be then emitted as events, that can be listened to by using the on method.

List of subscribe midGroups

op.subscribe(midGroup, opts, callback);
op.on("lastTightening", (midData) => {  // will get the events
    console.log("Received data on subscribe", midData);
});

op.subscribe("lastTightening", (err, data) => {
    if (err) {
        console.log("Error on subscribing to 'lastTightening'", err);
        return;
    }

    console.log("Subscribed to 'lastTightening'");
});

Unsubscribe

The unsubscribe method is used to unsubscribe to controller events. The same events from subscribe are supported

List of unsubscribe midGroups

op.unsubscribe(midGroup, opts, callback);
op.unsubscribe("lastTightening", (err, data) => {
    if (err) {
        console.log("Error on unsubscribing to 'lastTightening'", err);
        return;
    }

    console.log("Unsubscribed to 'lastTightening'");
});

Request

The request method is used to request informations from the controller. request MIDs normally have a conterpart MID for the reply containing the requested data, that can here be received in the callback or the Promise.

op.request(midGroup, opts, callback);
op.request("readTimeUpload", (err, data) => {
    if (err) {
        console.log("Error getting current time of the controller", err);
        return;
    }

    console.log("Controller clock is", data.payload);
});

Command

The command method is used to perform various actions on the controller.

op.command(midGroup, opts, callback);
op.command("disableTool", (err, data) => {
    if (err) {
        console.log("Error disabling the tool", err);
        return;
    }

    console.log("Tool disabled successfully");
});

SendMid

Method responsible for making a generic call, here it is possible to send a not implemented MID. If only midNumber is passed, the sent message will only contain default values and revision = 1, if you need to pass revision or others parameters use the opts parameter. The callback function is the function called in cases of error, passing the error as a parameter. The incoming data from these calls will be then emitted as events, that can be listened to by using the on method.

op.sendMid(midNumber, opts, callback);
op.on("data", (data) => {
    console.log("Data received", data);        
});

op.sendMid(1, (err) => {

    if (err) {
        console.log("Error", err);
        return;
    }

});

Example

This example shows how to perform a subscribe in lastTightening and make a tightening call.

const openProtocol = require('node-open-protocol');

let op = openProtocol.createClient(4545, "127.0.0.1", () => {
    console.log("Connected!");

    op.subscribe("lastTightening", (err, data) => {
        if (err) {
            return console.log("Error on Subscribe", err);
        }

        startTightening(1, "ASDEDCUHBG34563EDFRCVGFR6");
    });
});

op.on("error", (error) => {
    console.log("Error on OpenProtocol", error);
});

op.on("lastTightening", (midData) => {
    console.log("Tightening received!", JSON.stringify(midData));
});

function startTightening(parameterSetID, numberVIN) {
    // --> Abort Job --> Select Pset --> Set VehicleId --> Disable Tool --> Enable Tool

    op.command("abortJob", (err) => {
        if (err) {
            return console.log("Fail on abortJob", err);
        }

        op.command("selectPset", { payload: { parameterSetID } }, (err) => {

            if (err) {
                return console.log("Fail on selectPset", err);
            }

            op.command("vinDownload", { payload: { numberVIN } }, (err) => {

                if (err) {
                    return console.log("Fail on vinDownload", err);
                }

                op.command("disableTool", (err, data) => {

                    if (err) {
                        return console.log("Fail on disableTool", err);
                    }

                    op.command("enableTool", (err, data) => {

                        if (err) {
                            return console.log("Fail on enableTool", err);
                        }

                        console.log("waiting for the operator to tighten");
                    });
                });
            });
        });
    });
}

Or then with async/await functions:

const openProtocol = require('node-open-protocol');

async function onClientConnected() {
    console.log("Connected!");

    // subscribe to tightening results
    await op.subscribe("lastTightening");
    op.on("lastTightening", result => {
        console.log("Hooray! Result received!", result);
    });

    // start tigtening process
    // --> Abort Job --> Select Pset --> Set VehicleId --> Disable Tool --> Enable Tool
    let pset = 1;
    let vin = "ASDEDCUHBG34563EDFRCVGFR6";
    await op.command("abortJob");
    await op.command("selectPset", { payload: { parameterSetID: pset } });
    await op.command("vinDownload", { payload: { numberVIN: vin } });
    await op.command("disableTool");
    await op.command("enableTool");

    console.log(`Tightening started on VIN [${vin}] with pset [${pset}]`);
}

let op = openProtocol.createClient(4545, "127.0.0.1", data => {
    onClientConnected().catch(err => {
        console.log("¡Ay caramba!", err.toString());
    });
});

Controllers supported

The marked controllers have been tested to some degree, so we can assure basic communication support.

Please contact us by sending an e-mail to netsmarttech@netsmarttech.com if you'd like to have your controller tested and validated by us and to appear on this list.

Disclaimer

Contributing

For contributing see instructions in CONTRIBUTING.md

License

Copyright: (c) 2018-2020, Smart-Tech

GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)