Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

jsmodbus

Package Overview
Dependencies
Maintainers
1
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jsmodbus - npm Package Compare versions

Comparing version 0.4.0 to 0.5.0

examples/ReadDiscreteInput.js

2

package.json
{
"name": "jsmodbus",
"version": "0.4.0",
"version": "0.5.0",
"description": "Implementation for the Serial/TCP Modbus protocol.",

@@ -5,0 +5,0 @@ "author": "Stefan Poeter <stefan.poeter@cloud-automation.de>",

@@ -6,3 +6,3 @@ A simple an easy to use Modbus TCP client/server implementation.

Modbus is a simple Modbus TCP Client (Server implementation is coming, but feel free to start on your own) with a simple API.
Modbus is a simple Modbus TCP Client with a simple API.

@@ -12,3 +12,3 @@ Installation

Just type `npm install modbus` and you are ready to go.
Just type `npm install jsmodbus` and you are ready to go.

@@ -26,64 +26,89 @@ Testing

--------------
```javascript
var modbus = require('jsmodbus');
var modbus = require('./modbus');
// create a modbus client
var client = modbus.createTCPClient(502, '127.0.0.1', function (err) {
if (err) {
console.log(err);
exit(0);
}
});
// make some calls
client.readInputRegister(0, 10, function (resp, err) {
// resp will look like { fc: 4, byteCount: 20, register: [ values 0 - 10 ] }
});
client.readCoils(5, 3, function (resp, err) {
// resp will look like { fc: 1, byteCount: 1, register: [ true, false, true ] }
});
client.writeSingleCoil(5, true, function (resp, err) {
// resp will look like { fc: 5, byteCount: 4, outputAddress: 5, outputValue: true }
});
// create a modbus client
var client = modbus.createTCPClient(8888, '127.0.0.1', function (err) {
if (err) {
console.log(err);
process.exit(0);
}
});
client.writeSingleRegister(13, 42, function (resp, err) {
// resp will look like { fc: 6, byteCount: 4, registerAddress: 13, registerValue: 42 }
});
// make some calls
client.readHoldingRegister(0, 10, function (reps, err) {
// resp will look like { fc: 3, byteCount: 20, register: [ values 0 - 10 ] }
console.log(err, resp);
client.readCoils(0, 13, function (resp, err) {
// resp will look like { fc: 1, byteCount: 20, coils: [ values 0 - 13 ] }
console.log(err, resp);
});
client.readDiscreteInput(0, 13, function (resp, err) {
// resp will look like { fc: 2, byteCount: 20, coils: [ values 0 - 13 ] }
console.log(err, resp);
});
client.readInputRegister(0, 10, function (resp, err) {
// resp will look like { fc: 4, byteCount: 20, register: [ values 0 - 10 ] }
console.log(err, resp);
});
client.readCoils(5, 3, function (resp, err) {
// resp will look like { fc: 1, byteCount: 1, register: [ true, false, true ] }
console.log(err, resp);
});
client.writeSingleCoil(5, true, function (resp, err) {
// resp will look like { fc: 5, byteCount: 4, outputAddress: 5, outputValue: true }
console.log(err, resp);
});
client.writeSingleRegister(13, 42, function (resp, err) {
// resp will look like { fc: 6, byteCount: 4, registerAddress: 13, registerValue: 42 }
console.log(err, resp);
});
client.writeMultipleCoils(3, [1, 0, 1, 0, 1, 1], function (resp, err) {
// resp will look like { fc: 15, startAddress: 3, quantity: 6 }
console.log(err, resp);
});
```
Server example
--------------
```javascript
var modbus = require('jsmodbus');
var modbus = require('./modbus');
// create readInputRegister handler
var rirHandler = function (start, quantity) {
var resp = [];
for (var i = start; i < start + quantity; i += 1) {
resp.push(i);
}
// create readInputRegister handler
var rirHandler = function (start, quantity) {
var resp[];
for (var i = start; i < start + quant; i += 1) {
resp.push(i);
}
return [resp];
};
return [resp];
};
var coil = false;
var writeCoilHandler = function (addr, value) {
var coil = false;
var writeCoilHandler = function (addr, value) {
if (addr === 0) {
coil = value;
}
if (addr === 0) {
coil = value;
}
return [addr, value];
return [addr, value];
};
};
// create Modbus TCP Server
modbus.createTCPServer(8888, '127.0.0.1', function (err, modbusServer) {
// addHandler
modbusServer.addHandler(4, rirHandler);
modbusServer.addHandler(5, writeCoilHandler);
});
```
// create Modbus TCP Server
modbus.createTCPServer(8888, '127.0.0.1', function (err, modbusServer) {
// addHandler
server.addHandler(4, rirHandler);
server.addHandler(5, writeCoilHandler);
});
Development

@@ -90,0 +115,0 @@ -----------

@@ -14,3 +14,3 @@

0x02 : 'ILLEGAL DATA ADDRESS',
0x03 : 'ILLEGAL DATA VALE',
0x03 : 'ILLEGAL DATA VALUE',
0x04 : 'SLAVE DEVICE FAILURE',

@@ -151,3 +151,3 @@ 0x05 : 'ACKNOWLEDGE',

// ReadCoils
1 : function (pdu, cb, defer) {
1 : function (pdu, cb) {

@@ -177,7 +177,55 @@ log("handeling read coils response.");

cb(resp);
defer.resolve(resp);
},
// ReadDiscreteInput
2 : function (pdu, cb) {
log("handle read discrete input register response.");
var fc = pdu.readUInt8(0),
byteCount = pdu.readUInt8(1),
cntr = 0,
resp = {
fc : fc,
byteCount : byteCount,
coils : []
};
for (var i = 0; i < byteCount; i+=1) {
var h = 1, cur = pdu.readUInt8(2 + i);
for (var j = 0; j < 8; j+=1) {
resp.coils[cntr] = (cur & h) > 0 ;
h = h << 1;
cntr += 1;
}
}
cb(resp);
},
// ReadHoldingRegister
3: function (pdu, cb) {
log("handling read holding register response.");
var fc = pdu.readUInt8(0),
byteCount = pdu.readUInt8(1);
var resp = {
fc : fc,
byteCount : byteCount,
register : [ ]
};
var registerCount = byteCount / 2;
for (var i = 0; i < registerCount; i += 1) {
resp.register.push(pdu.readUInt16BE(2 + (i * 2)));
}
cb(resp);
},
// ReadInputRegister
4 : function (pdu, cb, defer) {
4 : function (pdu, cb) {

@@ -202,6 +250,5 @@ log("handling read input register response.");

cb(resp);
defer.resolve(resp);
},
5 : function (pdu, cb, defer) {
5 : function (pdu, cb) {

@@ -221,6 +268,5 @@ log("handling write single coil response.");

cb(resp);
defer.resolve(resp);
},
6 : function (pdu, cb, defer) {
6 : function (pdu, cb) {

@@ -240,5 +286,21 @@ log("handling write single register response.");

cb(resp);
defer.resolve(resp);
},
// WriteMultipleCoils
15 : function (pdu, cb) {
log("handling write multiple coils response");
}
var fc = pdu.readUInt8(0),
startAddress = pdu.readUInt16BE(1),
quantity = pdu.readUInt16BE(3);
var resp = {
fc : fc,
startAddress : startAddress,
quantity : quantity
};
cb(resp);
}

@@ -245,0 +307,0 @@ };

@@ -11,3 +11,3 @@ var net = require('net'),

exports.createTCPClient = function (port, host, cb) {
exports.createTCPClient = function (port, host, unit_id, cb) {

@@ -20,6 +20,20 @@ var net = require('net'),

serialClientModule.setLogger(log);
// retrieve arguments as array
var args = [];
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
// first argument is the port, 2nd argument is the host
port = args.shift();
host = args.shift();
// last argument is the callback function.
cb = args.pop();
// if args still holds items, this is the unit_id
if (args.length > 0) unit_id = args.shift(); else unit_id = 1; //default to 1
var socket = net.connect(port, host),
tcpClient = tcpClientModule.create(socket);
tcpClient = tcpClientModule.create(socket, unit_id);
socket.on('error', function (e) {

@@ -26,0 +40,0 @@

@@ -61,5 +61,62 @@ var util = require('util'),

return that.makeRequest(fc, pdu, !cb?dummy:cb, defer);
if (!cb) {
that.makeRequest(fc, pdu, that.promiseCallback(defer));
return defer.promise;
}
return that.makeRequest(fc, pdu, cb);
},
readHoldingRegister: function (start, quantity, cb) {
var fc = 3,
defer = Q.defer(),
pdu = that.pduWithTwoParameter(fc, start, quantity);
if (!cb) {
that.makeRequest(fc, pdu, that.promiseCallback(defer));
return that.promise;
}
return that.makeRequest(fc, pdu, cb);
},
readDiscreteInput: function (start, quantity, cb) {
var fc = 2,
defer = Q.defer(),
pdu = that.pduWithTwoParameter(fc, start, quantity);
if (quantity > 2000) {
if (!cb) {
defer.reject();
return defer.promise;
}
cb(null, {});
return;
}
if (!cb) {
that.makeRequest(fc, pdu, that.promiseCallback(defer));
return defer.promise;
}
return that.makeRequest(fc, pdu, cb);
},
readInputRegister: function (start, quantity, cb) {

@@ -71,4 +128,12 @@

return that.makeRequest(fc, pdu, !cb?dummy:cb, defer);
if (!cb) {
that.makeRequest(fc, pdu, that.promiseCallback(defer));
return defer.promise;
}
return that.makeRequest(fc, pdu, cb);
},

@@ -82,4 +147,11 @@

return that.makeRequest(fc, pdu, !cb?dummy:cb, defer);
if (!cb) {
that.makeRequest(fc, pdu, that.promiseCallback(defer));
return defer.promise;
}
return that.makeRequest(fc, pdu, cb);
},

@@ -92,11 +164,69 @@

return that.makeRequest(fc, pdu, !cb?dummy:cb, defer);
if (!cb) {
that.makeRequest(fc, pdu, that.promiseCallback(defer));
return defer.promise;
}
return that.makeRequest(fc, pdu, cb);
},
writeMultipleCoils: function (startAddress, coils, cb) {
if (coils.length > 1968) {
cb({}, true);
return;
}
var fc = 15,
byteCount = Math.ceil(coils.length / 8),
curByte = 0,
cntr = 0,
defer = Q.defer(),
pdu = Put()
.word8(fc)
.word16be(startAddress)
.word16be(coils.length)
.word8(byteCount);
for (var i = 0; i < coils.length; i += 1) {
curByte += coils[i]?Math.pow(2, cntr):0;
cntr = (cntr + 1) % 8;
if (cntr === 0) {
pdu.word8(curByte);
}
}
pdu = pdu.buffer();
if (!cb) {
that.makeRequest(fc, pdu, that.promiseCallback(defer));
return defer.promise;
}
return that.makeRequest(fc, pdu, cb);
},
isConnected: function () {
return that.isConnected;
},
on: function (name, cb) {
socket.on(name, cb);
},

@@ -109,4 +239,7 @@

close: function () {
that.socket.end();
}
};

@@ -120,2 +253,24 @@

proto.promiseCallback = function (defer) {
var that = this;
return function (resp, err) {
console.log(arguments);
if (err) {
defer.reject(err);
return;
}
defer.resolve(resp);
};
};
/**

@@ -125,5 +280,9 @@ * Pack up the pdu and the handler function

*/
proto.makeRequest = function (fc, pdu, cb, defer) {
proto.makeRequest = function (fc, pdu, cb) {
var req = { fc: fc, cb: cb, pdu: pdu, defer: defer };
var req = {
fc: fc,
cb: cb,
pdu: pdu
};

@@ -133,7 +292,7 @@ this.pipe.push(req);

if (this.state === 'ready') {
this.flush();
}
return defer.promise;
};

@@ -148,3 +307,5 @@

if (!this.isConnected) {
return;
}

@@ -203,3 +364,3 @@

}
handler(pdu, that.current.cb, that.current.defer);
handler(pdu, that.current.cb);

@@ -253,6 +414,6 @@ that.current = null;

return Put()
.word8(fc)
.word16be(start)
.word16be(quantity)
.buffer();
.word8(fc)
.word16be(start)
.word16be(quantity)
.buffer();

@@ -274,3 +435,5 @@ };

return function () {
that.isConnected = false;
};

@@ -277,0 +440,0 @@

@@ -12,5 +12,4 @@

var PROTOCOL_VERSION = 0,
UNIT_ID = 1;
var PROTOCOL_VERSION = 0;
/**

@@ -22,6 +21,6 @@ * ModbusTCPClient handles the MBAP that is the

*/
var ModbusTCPClient = function (socket) {
var ModbusTCPClient = function (socket, unit_id) {
if (!(this instanceof ModbusTCPClient)) {
return new ModbusTCPClient(socket);
return new ModbusTCPClient(socket, unit_id);
}

@@ -52,3 +51,3 @@

.word16be(pdu.length + 1) // pdu length
.word8(UNIT_ID) // unit id
.word8(typeof unit_id === 'number' ? unit_id:true) // unit id
.put(pdu) // the actual pdu

@@ -55,0 +54,0 @@ .buffer();

@@ -338,6 +338,133 @@

});
/**
* Simply read holding registers with success
*/
it("should read holding register just fine", function () {
var cb = sinon.spy();
client.readHoldingRegister(0, 1, cb);
var res = Put()
.word8(3) // function code
.word8(2) // byte count
.word16be(42) // register 0 value
.buffer();
socket.emit('data', res);
assert.ok(cb.called);
assert.deepEqual(cb.args[0][0], { fc: 3, byteCount: 2, register: [42]});
});
/**
* Write Multiple Coils with success
*/
it("should write multiple coils just fine", function () {
var cb = sinon.spy();
client.writeMultipleCoils(123, [1, 0, 1, 0, 1, 0, 1, 1], cb);
var res = Put()
.word8(15) // function code
.word16be(123) // start address
.word16be(8) // quantity of outputs
.buffer();
socket.emit('data', res);
assert.ok(cb.called);
assert.deepEqual(cb.args[0][0], { fc: 15, startAddress: 123, quantity: 8 });
});
/**
* Write Multiple Coils with too many coils
*/
it("should not write multiple coils due to too much coils", function () {
var cb = sinon.spy(),
coils = [];
for (var i = 0; i < 1969; i += 1) {
coils.push(1);
}
client.writeMultipleCoils(123, coils, cb);
assert.ok(cb.called);
assert.ok(cb.args[0][1]);
});
// Read Discrete Input
it('should handle a read discrete input request', function () {
var cb = sinon.spy();
client.readDiscreteInput(0, 13, cb);
var res = Put()
.word8(2) // function code
.word8(2) // register address
.word8(3) // coils 1 - 8
.word8(1) // coils 9 - 13
.buffer();
socket.emit('data', res);
assert.ok(cb.calledOnce);
assert.deepEqual(cb.args[0][0], {
fc: 2,
byteCount: 2,
coils: [
true, // 1
true, // 2
false, // 3
false, // 4
false, // 5
false, // 6
false, // 7
false, // 8
true, // 9
false, // 10
false, // 11
false, // 12
false, // 13
false, // filled in 14
false, // filled in 15
false, // filled in 16
]
});
});
it('should handle a wrong read discrete input request', function () {
var cb = sinon.spy();
// quantitiy is to big
client.readDiscreteInput(0, 2001, cb);
assert.ok(cb.calledOnce);
assert.deepEqual(cb.args[0][1], { });
});
});
});

@@ -64,3 +64,3 @@

describe('Requests/Responses', function () {
describe('Requests/Responses Without Unit Identifier', function () {

@@ -80,5 +80,5 @@ var client;

beforeEach(function (done) {
socket = new SocketApi();
socket = new SocketApi();
client = modbusClient.create(socket);
client = modbusClient.create(socket);

@@ -147,2 +147,84 @@ done();

describe('Requests/Responses With Unit Identifier', function () {
var client;
var SocketApi = function () {
eventEmitter.call(this);
this.write = function () { };
};
util.inherits(SocketApi, eventEmitter);
var socket;
beforeEach(function (done) {
socket = new SocketApi();
unit_id = 100;
client = modbusClient.create(socket, unit_id);
done();
});
it('should read a simple request', function () {
var onDataSpy = sinon.spy();
client.on('data', onDataSpy);
var res = Put()
.word16be(0)
.word16be(0)
.word16be(5)
.word8(unit_id)
.word8(4)
.word8(2)
.word16be(42)
.buffer();
var exRes = Put()
.word8(4)
.word8(2)
.word16be(42)
.buffer();
socket.emit('data', res);
assert.ok(onDataSpy.called);
assert.deepEqual(onDataSpy.args[0][0], exRes);
});
it('should respond', function () {
var writeSpy = sinon.spy(socket, 'write');
var req = Put()
.word8(4)
.word16be(2)
.word16be(12)
.buffer();
var exReq = Put()
.word16be(0)
.word16be(0)
.word16be(6)
.word8(unit_id)
.word8(4)
.word16be(2)
.word16be(12)
.buffer();
socket.emit('connect');
client.write(req);
assert.ok(writeSpy.calledOnce);
assert.deepEqual(writeSpy.args[0][0], exReq);
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc