A StreamStack implementation of the MODBUS protocol for Node.
This module exposes two concrete StreamStack
implementations:
ModbusRequestStack
can be used as a MODBUS client (i.e. Master), and can write
MODBUS compliant requests and listen for the response.
ModbusResponseStack
can be used to create a MODBUS server (i.e. Slave), by
listening for requests and providing a convenient API to respond with.
MODBUS is an open building automation protocol that is widely used in various monitoring and controlling equipment. It's used with a variety of different transports, including TCP.
Currently only communication through the TCP protocol is supported, however RS-485 serial support should be possible with node-serialport. I haven't had a chance to look into it yet.
You will need to know which Function Code (defined in the MODBUS specification) you are invoking on the remote MODBUS slave. In this example, we'll request to read from the current values of the first 50 Input Registers on the slave:
// 'RIR' contains the "Function Code" that we are going to invoke on the remote device
var RIR = require('modbus-stack').FUNCTION_CODES.READ_INPUT_REGISTERS;
// IP and port of the MODBUS slave, default port is 502
var client = require('modbus-stack/client').createClient(502, '10.0.1.50');
// 'req' is an instance of the low-level `ModbusRequestStack` class
var req = client.request(RIR, // Function Code: 4
0, // Start at address 0
50); // Read 50 contiguous registers from 0
// 'response' is emitted after the entire contents of the response has been received.
req.on('response', function(registers) {
// An Array of length 50 filled with Numbers of the current registers.
console.log(registers);
client.end();
});
node-modbus-stack
makes it dead simple to create a compliant MODBUS Slave (or Server)
written in pure JavaScript. Here's an example of a server that would respond to the
request above:
var FC = require('modbus-stack').FUNCTION_CODES;
// 'handlers' is an Object with keys containing the "Function Codes" that your MODBUS
// server will handle. Anything function code requested without a handler defined here
// will have the Server transparently respond with Exception Code 1 ("Illegal Function")
var handlers = {};
// Define a handler for "Read Input Registers". We'll just respond with the register
// number requested. In a real-world situation, you'd probably look up these values from
// a database, etc.
handlers[FC.READ_INPUT_REGISTERS] = function(request, response) {
var start = request.startAddress;
var length = request.quantity;
var resp = new Array(length);
for (var i=0; i<length; i++) {
resp[i] = start + i;
}
response.writeResponse(resp);
}
require('modbus-stack/server').createServer(handlers).listen(502);
A "catch-all" function can be passed to createServer()
instead of a "handlers" object, if you'd
rather have a single callback invoked for all MODBUS requests. Just be sure to call
writeException()
manually for any "Function Codes" your server isn't going to handle.
require('modbus-stack')
-
FUNCTION_CODES
- Object
Contains the defined "Function Codes" as programmer-friendly names that translate into the defined code number.
Usage:FUNCTION_CODES.READ_COILS → 1
-
EXCEPTION_CODES
- Object
Same asFUNCTION_CODES
, contains the defined "Exception Codes".
Usage:EXCEPTION_CODES.ILLEGAL_FUNCTION → 1
-
ModbusRequestStack
- Function
AStreamStack
subclass that handles the client-side (Master) of the MODBUS protocol.
Usage:var req = new ModbusRequestStack(stream)
-
ModbusRequestStack#request(functionCode[, param1, param2, ...], cb)
- Function
Writes a MODBUS request to the underlyingStream
(usually anet.Stream
).response
will be emitted after the slave responds to the request. The first arg is the "Function Code" to request. Anything after that are parameters specific to each function code.cb
is an optional callback to attach to theresponse
anderror
events. The function should have the signature:function(err, response) {}
.
Usage:req.request(FC.READ_COILS, 0, 50)
-
"response" - function(response)
- Event
The "response" event is fired after the remote MODBUS slave responds to therequest
previously sent. -
"error" - function(error)
- Event
The "error" event is fired if the remote MODBUS slave responds with an Exception Code instead of a successful response code, or if a Function Code is requested in whichnode-modbus-stack
hasn't implemented the proper Function Code parsing logic inclient.js
.
-
-
ModbusResponseStack
- Function
AStreamStack
implementation to handle the server-side (Slave) of the MODBUS protocol.
Usage:var res = new ModbusResponseStack(stream)
-
ModbusResponseStack#writeResponse(param1[, param2, param3, ...])
- Function
Writes out the MODBUS response after receiving arequest
event. The parameters given are dependant on the MODBUS "Function Code" that was requested.
Usage:res.writeResponse(array) // After receiving a "Read Input Registers" request
-
ModbusResponseStack#writeException(exceptionCode)
- Function
Writes out a MODBUS exception response after receiving arequest
event.exceptionCode
should be the desired exception code to respond with. SeeEXCEPTION_CODES
.
Usage:res.writeException(EXCEPTION_CODES.ILLEGAL_FUNCTION)
-
"request" - function(request)
- Event
The "request" event is fired once a remote MODBUS master sends a Function Code request.request
is an Object containing interesting properties about the request, likefunctionCode
and any other parameters that go with the desired Function Code. -
"error" - function(error)
- Event
The "error" event is fired if a Function Code is requested in whichnode-modbus-stack
hasn't implemented the proper Function Code parsing logic inserver.js
.
-
require('modbus-stack/client')
-
createClient(port[, host])
- Client
Creates and return a newClient
instance, which is the preferred method of conventional MODBUS master communication over TCP. The default MODBUS port is 502.
Usage:var client = modbusClient.createClient(502, 'example.com')
-
Client#request(functionCode[, param1, param2, ...], cb)
- ModbusRequestStack
Makes a MODBUS request to the remote MODBUS slave. Same asModusRequestStack#request()
.
Usage:var req = client.request(FC.READ_COILS, 0, 10)
-
Client#end()
- Function
Sends a FIN to the remote slave device, closing the TCP connection.
Usage:client.end()
-
require('modbus-stack/server')
createServer(handlers | callback)
- Server
Creates and returns a newServer
instance, which is used to make MODBUS compliant servers easily.handlers
should be an Object containing keys and callbacks of the Function Codes your server is implementing, or a "catch-all"callback
function can be passed to invoke for every MODBUS request, regardless of the Function Code.
Usage:var server = modbusServer.createServer(handlers)