node-modbus / stream Goto Github PK
View Code? Open in Web Editor NEWNodeJS Modbus Stream
License: MIT License
NodeJS Modbus Stream
License: MIT License
var modbus = require("modbus-stream");
modbus.tcp.server({ debug: "server" }, (connection) => {
connection.readCoils({from: 1, to: 40}, (err, info) => {
console.log(info.response.data);
});
}).listen(502, () => {
// ready
});
info.response.data is incoming-data ?
Just trying to get a serial connection on a Raspberry Pi going to a modbus slave with address 10. I know the address is correct and 9600 baud etc because I can connect using another program on the Pi to the device.
I have the following code for modbus-stream
modbus.serial.connect("/dev/ttyUSB0",{slaveId:10},(err,connection)=> etc
The connection appears to be set up as I can look at the connection parameter and it looks OK, the transport variable always contains slaveId:1 regardless of what I put in the setup object. Am I doing something wrong here or does the slaveId setting not work?
Just a PS here. I managed to find out how to change the slave device address to 1 and the code works, however I do need to address other devices besides address 1. So the question still stands
Thanks
Robyn
hello my project of modbus-steam it's reading some registers of my modbus tcp devices .
i use a Setinterval JS function to read every minute my devices , but after some times ( may be 1 or 2 hours or less ) my script stops with ECONNRESET ERROR
Question : Ho can i handlle this error to disable script stopp and continue reading or waiting until connection is OK
error is
Error: read ECONNRESET at TCP.onStreamRead (internal/stream_base_commons.js:111:27) Emitted 'error' event at: at Transport.<anonymous> (D:\serveur\readmodbus\node_modules\modbus-stream\l ib\stream.js:36:10) at Transport.emit (events.js:182:13) at Transport.<anonymous> (D:\serveur\readmodbus\node_modules\modbus-stream\l ib\transport\transport.js:21:8) at Socket.emit (events.js:182:13) at emitErrorNT (internal/streams/destroy.js:82:8) at emitErrorAndCloseNT (internal/streams/destroy.js:50:3) at process._tickCallback (internal/process/next_tick.js:63:19)
Hi!
While debugging a project, I stumbled upon the following lines of code:
Is there any good reason for not making a "not equal" comparison here?
Although it may seem exaggerated that may guard us a little bit better from malicious crafted responses.
Thanks.
I have a USB RS485 adapter connected to a MODBUS temperature sensor. I have a C program using libmodbus successfully reading the device. I want to use Node.js, of course.
I'm getting this error:
$ sudo node mstemp.js
<< automaton-123 0x[ 01, 04, 00, 01, 00, 01, 60, 0A ]
>> automaton-123 0x[ 01, 04, 02, 0C ]
events.js:160
throw er; // Unhandled 'error' event
^
TypeError: Cannot set property 'code' of null
at Object.exports.Response (/home/david/modbus-server/node_modules/modbus-pdu/lib/Modbus.js:84:16)
at SerialPort.<anonymous> (/home/david/modbus-server/node_modules/modbus-stream/lib/transport/transport.js:82:24)
at emitOne (events.js:96:13)
at SerialPort.emit (events.js:188:7)
at SerialPort.raw (/home/david/modbus-server/node_modules/serialport/lib/parsers.js:7:13)
at SerialPort._emitData (/home/david/modbus-server/node_modules/serialport/lib/serialport.js:313:18)
at SerialPort.<anonymous> (/home/david/modbus-server/node_modules/serialport/lib/serialport.js:293:14)
at SerialPort.<anonymous> (/home/david/modbus-server/node_modules/serialport/lib/serialport.js:306:7)
at FSReqWrap.wrapper [as oncomplete] (fs.js:681:17)
The line of code is here in modbus-pdu:
if (typeof exports[k] == "object" && exports[k].Code == code) {
var data = exports[k].Response.parse(buffer);
if (typeof data == "object" && !util.isArray(data)) {
data.code = k; // CRASH HERE
} else {
data = { code: k, data: data };
}
return data;
}
So.. going by the crash, somehow data
is null
but by the test it has typeof == object
and it is not an array.
My code is adapted from your examples:
const modbus = require('modbus-stream');
const util = require('util');
modbus.serial.connect("/dev/ttyUSB0", {
// except "debug", everything else is the default for serial
baudRate : 9600,
dataBits : 8,
stopBits : 1,
parity : "none",
debug : "automaton-123"
}, (err, connection) => {
if (err) throw err;
connection.readInputRegisters({ address: 1, quantity: 1 }, (err, res) => {
if (err) throw err;
console.log(res); // response
})
});
Something I see missing -- not setting the device ID to connect to. The device is at ID=1 and I see in the protocol dump that is the address which was requested.
i have a modbus client with ( modbus unit id = 245 for example) how can i add this in node-modbus stream methods to read values ( coils and inputs )
I am trying to run a tcp master app in a docker container. First time I run "docker-compose up" everything went well but after that all I am getting is this:
Can you please help dresende?
Error: This socket has been ended by the other party
at Socket.writeAfterFIN [as write] (net.js:290:12)
at Transport.BaseTransport.write (/C:\Users\Ilhan\Desktop\IcaxMaster/node_modules/modbus-stream/lib/transport/transport.js:46:15)
at /C:\Users\Ilhan\Desktop\IcaxMaster/node_modules/modbus-stream/lib/transport/transport.js:80:13
at call_queue (/C:\Users\Ilhan\Desktop\IcaxMaster/node_modules/modbus-stream/lib/transport/transport.js:190:38)
at Transport.BaseTransport.retrySend (/C:\Users\Ilhan\Desktop\IcaxMaster/node_modules/modbus-stream/lib/transport/transport.js:79:2)
at Transport.BaseTransport.send (/C:\Users\Ilhan\Desktop\IcaxMaster/node_modules/modbus-stream/lib/transport/transport.js:72:8)
at Stream.writeMultipleRegisters (/C:\Users\Ilhan\Desktop\IcaxMaster/node_modules/modbus-stream/lib/stream.js:174:17)
at Timeout._onTimeout (/C:\Users\Ilhan\Desktop\IcaxMaster/app.js:38:20)
at ontimeout (timers.js:386:11)
at tryOnTimeout (timers.js:250:5)
In Modbus(TCP), the terms "server" & "slave" refer to devices that do not initiate contact with other devices but rather only respond to request they receive. The terms "client" & "master" refer to devices that initiate requests. So why does the first example have the server (slave) send a request (read-coils
address 3-7) to a client (master)? This seems backwards.
This is my current test.js file. It creates a client and a server network socket and the server requests coils as soon as the client connects.
Hello,
I am using the function 'writeSingleCoil' to write value 1 on address 5.
The example is given below:
var modbus = require("modbus-stream");
modbus.tcp.server({ debug: "server" }, (connection) => {
connection.writeSingleCoil({ address: 5, value: 1 }, (err, info) => {
console.log("Write Request: Server");
console.log("response", info.response);
});
}).listen(12345, () => {
modbus.tcp.connect(12345, { debug: "client" }, (err, connection) => {
connection.on("write-single-coil", (request, reply) => {
console.log("Write Request: Client");
console.log(request.request.value);
reply(null, 2,1);
});
});
});
My Questions are:
Hi Diego,
Thanks again for your work. Is below a drop of established connection? Is there something that can be enabled to automatically establish the connection again? If not, what is the best way to reestablish the connection.
Thank you for your help.
Ilhan
events.js:167
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at TCP.onread (net.js:659:25)
Emitted 'error' event at:
at Transport.<anonymous> (/home/ilhans/tools/grid-tester/node_modules/modbus-stream/lib/stream.js:36:10)
at Transport.emit (events.js:182:13)
at Transport.<anonymous> (/home/ilhans/tools/grid-tester/node_modules/modbus-stream/lib/transport/transport.js:21:8)
at Socket.emit (events.js:182:13)
at emitErrorNT (internal/streams/destroy.js:82:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
at process._tickCallback (internal/process/next_tick.js:63:19)
Hi!
I'm able to establish a connection to a Siemens S7 via Modbus TCP.
I'm trying to read the holding registers. If I run the application I get the "Connected." info and the debug information that shows the data sent to the device. But I don't get the res object of the function call. I get a timeout instead:
Error while reading holding registers: { Error: GatewayTargetDeviceFailedToRespond
at Object.exports.error (/Users/uNki/Documents/Development/modbus_test/node_modules/modbus-pdu/lib/Exception.js:24:13)
at Timeout._onTimeout (/Users/uNki/Documents/Development/modbus_test/node_modules/modbus-stream/lib/transport/transport.js:93:33)
at ontimeout (timers.js:475:11)
at tryOnTimeout (timers.js:310:5)
at Timer.listOnTimeout (timers.js:270:5) code: 11 }
here is my code:
const modbus = require("modbus-stream");
modbus.tcp.connect(502, "192.168.0.1", { debug: "server" }, (err, connection) => {
if (err)
console.error('Connection error: ', err)
console.log('Connected.\n')
connection.readHoldingRegisters({ address: 0, quantity: 20, extra: { unitId: 1 } }, (err, res) => {
if (err)
return console.error('Error while reading holding registers: ', err)
console.log('Response: ', res); //
})
connection.on('error', err => {
if (err.message != 'write EPIPE')
console.log('Unknown error:', err.message)
})
});
How can i setup a modbus ascii slave?
I found no option to use the ascii transport.
const modbus = require(".")
modbus.tcp.connect(10000, "127.0.0.1", { unitId: 3, debug: "automaton-2454" }, (err, connection) => {
// do something with connection
connection.readCoils( {address: 0, quantity:4}, (err, res) => {
console.log(err)
console.log(res)
})
});
debug log:
2017-09-12T10:23:56.833Z << automaton-2454 0x[ 00, 01, 00, 00, 00, 06, 01, 01, 00, 00, 00, 04 ]
unitId still 01, ([ 00, 01, 00, 00, 00, 06, 01(should be 03), 01, 00, 00, 00, 04 ])
I would like a way to have the socket close automatically.
socket provides two methods already; we just need to pass them into your tcp.js driver.
../drivers/tcp.js file modifications here:
// if the timeout option is present; make sure it is an integer
// and limit it between 1 and 60 seconds
if (options.timeout) {
let timeOut = Math.min(60000, Math.max(1000, parseInt(options.timeout)));
socket.setTimeout(timeOut);
socket.on('timeout', () => {
socket.end();
});
}
// --- End of timeout option
// if the closeOnData is set to 'true' then
// end() the socket connection when data is returned from
// the tcp connection.
if (options.closeOnData === true) {
socket.on('data', () => {
socket.end();
})
}
// --- End of closeOnData option
return socket;
use like this:
modbus.tcp.connect(12345, { timeout: 3000, closeOnData: true, debug: "client" }, (err, connection) => {
connection.readCoils({ address: 1, quantity: 1 }, (err, res) => {
if (err) throw err;
console.log(res.response); // response here
})
});
Thanks!
My PLC has 4 threads that I can connect to. Once I connect the 4 times, it will crash on the 5th attempt. Is there any documentation on disconnecting from an existing connection?
I've tried connection.close(), connection.off() without any luck.
I'm able to read all my coils fine, preform hex conversions, etc just fine. I'm having issues setting some binary coils (or any coils) and can narrow it down to my weak understanding of JS in this instance. Could someone point me in the write direction of a writeSingleCoil use example? Sorry to be a bother.
Hi,
I'm probably missing something simple, but how would one detect/cleanup after a connection loss and then reconnect when connectivity is restored?
Currently I connect and save the connection in a variable. I use that connection periodically. If it gets an error (cable unplugged in this case), I call close on the connection. When the link is restored, I make a new connection and things continue. However, at some point soon after the reconnect a ECONNRESET
is thrown.
What is the proper way to handle connection loss?
Thanks,
Kevin
Hello, I've succesfully connected a to a real device and I'm able to read a value as soon as the device connects, the problem is that if a surround the readHoldingRegister in a loop, it only reads the value the first time and catches an exception of IllegalDataValue the next one.
Here' the code of my client
`modbus.tcp.connect(port, address, { debug: 'device-1' }, (err, connection) => {
if (err){
console.log(err);
}
else{
console.log('Device connected');
var buffer;
var hex = ''
for (let i=0; i<5; i++){
connection.readHoldingRegisters({ address: 50526, quantity: 2, extra: { unitId: 1, retry: 1000, retries: 3 }}, (err, res) =>{
if (err != null){
throw err;
}
else{
buffer = res.response.data;
hex = buffer[1].toString('hex');
console.log(hex);
}
});
}`
I don't know if it's because my response is wrong, here's the code for the server:
`modbus.tcp.server({ debug: 'server' }, (connection) => {
connection.on("read-holding-registers", function (req, reply) {
console.log(req);
console.log('OK');
return reply(null, [ Buffer.from([ 0x00, req.request.address ]) ]);
});
}).listen(502, () => {
console.log('Listening');
}); `
Dear @jhillacre , @dresende , @jacobq , @buffcode , @insideGen
I am working on a proprietary protocol translator from /to modbus.
I need to discover all the modbus device master/slave and get the list of parameters they are able to support (finally the data model) for each devic discovered.
It's our data model for one parameter it could be string, boolean, real, integer, ....
{
"number": 0,
"identifier": "ParameTypeInteger",
"description": "",
"value": 0,
"minimum": -4096,
"maximum": 0,
"access": "readWrite",
"format": "%8.2f°",
"enumeration": "",
"factor": 32,
"isOnline": true,
"formula": "1*\n1/",
"default": -1024,
"type": "integer"
} {
"number": 1,
"identifier": "ParameTypeReal",
"description": "",
"value": 0,
"minimum": 0,
"maximum": 4096,
"access": "readWrite",
"format": "%8.2f°",
"enumeration": "",
"factor": 1,
"isOnline": true,
"formula": "10*\n10/",
"default": 100,
"type": "real"
},
{
"number": 2,
"identifier": "ParameTypeString",
"description": "",
"value": "text",
"access": "readWrite",
"enumeration": "Yes\nNo\nOk",
"isOnline": true,
"default": "default",
"type": "string"
},
{
"number": 3,
"identifier": "ParameTypeEnumeration",
"description": "",
"value": 0,
"access": "readWrite",
"enumeration": "Line\nMic+48V\nMic",
"isOnline": true,
"default": 0,
"type": "enum"
},
{
"number": 4,
"identifier": "ParameTypeBoolean",
"description": "",
"value": true,
"access": "readWrite",
"isOnline": true,
"default": false,
"type": "boolean"
}
How we could do with you code to generate a json file with all the devices ?
Best regards
Youssef
Similar to #34 I'm confused about the different signatures that need to be used for reply
. It seems to depend on the function code, that is, reply
seems to assume the data it receives is byte-for-byte identical to the data section of the response frame, even if that includes additional fields like start address, number of elements to read/write, etc. Is that right?
For example, in my application I define a "modbus map" to associate handler functions with ROB & ROR read operations (function code 2 & 4) as well as RWB & RWR read/write operations (codes 1, 3, 5, 6, 15, and 16). However, I am not certain how I should call reply
with the resulting data.
modbus.tcp.server(serverOptions, (connection: any) => {
// ...
connection.transport.on('request', (eventName, transaction, reply) => {
const request = transaction.request;
const size = request.quantity;
const firstAddr = request.address;
const lastAddr = firstAddr + size - 1;
// (call appropriate handlers)
// ...
// This is the part that seems weird / opaque to me.
// Why isn't there a function that will just accept `result` and format it appropriately
// (since the transaction contains the information needed)?
switch(eventName) {
case 'read-coils': // fcode 1: response format = [ID][FC][BC][DATA, 1 byte per 8 coils]
case 'read-discrete-inputs': // fcode 2: response format = [ID][FC][BC][DATA, 1 byte per 8 coils]
reply(null, result);
break;
case 'read-holding-registers': // fcode 3: response format = [ID][FC][BC][DATA, 2 bytes per register]
case 'read-input-registers': // fcode 4: response format = [ID][FC][BC][DATA, 2 bytes per register]
result = result.map(x => (x instanceof Buffer) ? x : createUInt16BufferFromNumber(x));
reply(null, result);
break;
case 'write-single-coil': // fcode 5: response format = [ID][FC][ADDR][DATA] (mirrors request exactly)
case 'write-single-register': // fcode 6: response format = [ID][FC][ADDR][DATA] (mirrors request exactly)
reply(null, firstAddr, request.value);
break;
case 'write-multiple-coils': // fcode 15: response format = [ID][FC][ADDR][NUM]
case 'write-multiple-registers': // fcode 16: response format = [ID][FC][ADDR][NUM]
reply(null, firstAddr, size);
break;
default:
warn(`Replying with default format -- probably wrong!`, result);
reply(null, result);
}
})
// ...
}
Hi,
Is there a way to disable logging. Log files go crazy.
Thanks.
This isn't a huge deal, but I noticed that you used package
as an identifier in several places--most significantly in example code. This causes problems for people using strict
mode (common when using babel). It would be nice if you could use some other name that is not a future reserved word in JavaScript.
Hi,
as the title says, trying to install modbus-stream on Windows causes this:
prebuild-install WARN install No prebuilt binaries found (target=12.14.1 runtime=node arch=x64 platform=win32)
Then follow a number of errors as the automatic compilation fails. As a result I cannot install modbus-stream on Windows.
Package [email protected] can be installed on Windows. Can you up the dependency on your project or otherwise fix installation on Windows?
Thanks,
Regards
Alessandro
I have a lock system hooked up to the tcp controller i'm using with node-modbus. I can successfully send the unlock to modbus but I'm trying to figure out a way to listen to the device. After unlocking, when the device LOCKS how do I listen on port 502 so that I can trigger an event?
My current code is:
modbus.tcp.connect(502, "10.100.55.17", { debug: "automaton-2454" }, (err, connection) => {
//do something with connection
connection.writeSingleCoil({ address: 0, value: 0 }, (err, info) => {
console.log("response", info.response);
});
connection.writeSingleCoil({ address: 0, value: 1 }, (err, info) => {
console.log("response", info.response);
});
connection.on("read-coils", (request, reply) => {
console.log("**READ-COILS**")
reply(null, [ 0, 0, 0, 0, 0, 0, 0, 0 ]);
});
connection.on("write-single-coil", (request, reply) => {
console.log("**WRITE-SINGLE-COIL**")
reply(null, 0, 1);
});
});
modbus.tcp.server({ debug: "server" }, (connection) => {
// do something with connection
connection.on("read-coils", (request, reply) => {
console.log("**READ-COILS**")
//reply(null, [ 0, 0, 0, 0, 0, 0, 0, 0 ]);
});
connection.on("write-single-coil", (request, reply) => {
console.log("**WRITE-SINGLE-COIL**")
//reply(null, 0, 1);
});
connection.on("read-single-coil", (request, reply) => {
console.log("**READ-SINGLE-COIL**")
reply(null, 0, 1);
});
connection.readCoils({ address: 0, quantity: 16 }, (err, info) => {
console.log("response", info.response);
});
connection.readCoils({ from: 0, to: 7 }, (err, info) => {
console.log("PDU", info.pdu);
console.log("response", info.response.data);
});
}).listen(502, () => {
// ready
console.log("** GOT RESPONSE FROM DEVICE **")
});
Hi,
first of all thanks to you for your solid work!
We are planning to use your library within one of our TypeScript-based projects and noticed that there aren't any type declarations yet.
I'm willing to provide those declarations and it would be nice when some one could test / extend the types to include serial and UDP, as we probably only use either TCP or UDP in our project.
I will publish the types in my own repository first of all and if everything looks okay a PR to the official @types namespace managed by https://github.com/DefinitelyTyped/DefinitelyTyped will be created.
There are no changes to the actual codebase necessary, though this project would really benefit from a migration to typescript (codecompletion for driver / stream options etc.)
Hi dresende
Thank you for your great library.
This is my scenario:
The issue is: the modbus-stream library doesn't discard the heartbeat from the internal buffer and through exception because of wrong modbus responses.
...
<modbus-response><noise-byte><noise-byte><noise-byte><modbus-response><modbus-response><noise-byte><modbus-response>
...
Can you add some check code to discard those "heartbeat/noise bytes"?
I've been looking at your code and i think the best place to add this check code is:
lib/transport/tcp.js (line 73) (inside Transport.prototype.unwrap function):
and a simple check code, based on "Protocol Identifier" is always 0x0000, min length and Unit-ID matching, would be:
for(; (this.buffer.length >= 7);) {
if ((this.buffer.readUInt16BE(2) !== 0) || (this.buffer.readUInt16BE(4) < 3) || (this.buffer.readUInt8(6) !== this.unitId)) {
this.buffer = this.buffer.slice(1, this.buffer.length);
} else {
break;
}
}
What do you think?
Thank you
it's not compatible with the lastest version of nodejs 12.14.0 (npm V6.13.4 )
Managed to overflow the transaction id counter in lib/transport/tcp.js. I'm not 100% familiar with the raw protocol, but would it be safe for node-modbus-stream to be resetting the transaction ID instead of overflowing? If not, I guess I could catch this and rebuild the connection.
My exception:
TypeError: "value" argument is out of bounds
at checkInt (buffer.js:1041:11)
at Buffer.writeUInt16BE (buffer.js:1110:5)
at Transport.wrap (/home/logger/server/node_modules/modbus-stream/lib/transport/tcp.js:38:8)
at Transport.BaseTransport.send (/home/logger/server/node_modules/modbus-stream/lib/transport/transport.js:72:23)
at Stream.readInputRegisters (/home/logger/server/node_modules/modbus-stream/lib/stream.js:103:17)
at voltageAndRanges (/home/logger/server/lib/plc.js:104:49)
at /home/logger/server/node_modules/async/dist/async.js:3853:24
at replenish (/home/logger/server/node_modules/async/dist/async.js:946:17)
at /home/logger/server/node_modules/async/dist/async.js:950:9
at eachOfLimit (/home/logger/server/node_modules/async/dist/async.js:975:24)
at /home/logger/server/node_modules/async/dist/async.js:980:16
at eachOf (/home/logger/server/node_modules/async/dist/async.js:1051:5)
The code I can understand it is simple. But my problem is the connection. Fo instance I have something like
setInterval(() => {
// get device info here
}, 2000);
1, In the section where I collect data from the device, do I call connect every time or I should connect before the interval and then only read registers? Something like this
let run = async () => {
let conn = await modbus.tcp.connect(502, "134.2.56.231", { debug: "automaton-2454" });
setInterval(() => {
conn.readCoil();
}, 2000);
}
run();
Or like this
setInterval(() => {
modbus.tcp.connect(502, "134.2.56.231", { debug: "automaton-2454" }, (err, connection) => {
connection.readCoil();
});
}, 2000);
I have tried setting the debug field to null and false in the extra option when reading from holding registers with no luck.
connection.readHoldingRegisters ({address : address, quantity : 1, extra: { unitId: slave, debug: false} }, (err, res) => {
console.log(res);
})
However, I keep getting the following:
2019-09-06T16:13:38.543Z << undefined 0x[ 00, 1B, 00, 00, 00, 06, 02, 03, 00, 5E, 00, 01 ]
Is it expected behaviour?
For example, I've got this code:
let modbus = require('modbus-stream')
modbus.tcp.server({ debug: "server" }, (connection) => {
connection.on("write-single-register", (request, reply) => {
console.log('Remote address') // somehow print remote address here
});
}).listen(12345, 'localhost', () => {
modbus.tcp.connect(12345, 'localhost', { debug: "client" }, (err, connection) => {
let msg = Buffer.alloc(2);
msg.writeUInt16BE(0x01, 0);
connection.writeSingleRegister({address: 05, value: msg, extra: {unitId: 12}}, (err, info) => {
console.log(info)
});
});
});
I'm looking for something like socket.remoteAddress
I know that there is something like that _connectionKey: '4:127.0.0.1:12345'
in request
object.
But I'd like to find "easy and correct" approach. If it is exists, of course.
Running into an issue migrating over from node-modbus-tcp
. I seem to have a readInputRegisters
callback being called a second time. The first time has my results, the second time has a GatewayTargetDeviceFailedToRespond
error object.
I'm using the async library to handle callbacks to run multiple readInputRegisters
in parallel. Async throws an exception when its callback is called a second time. I added a call counter to my function and it seems like the first readInputRegisters
that returned successfully was then called again.
Is this caused by transport.retryTimer
being overwritten in lib/transport/transport.js
by the second call to readInputRegisters
?
Here is my code:
const modbus = require('modbus-stream');
let modbusConn;
...
modbus.tcp.connect(
sql.currentSettings.modbusPort,
sql.currentSettings.ipAddress,
(err, connection) => {
if (err) {
return die(err, 'modbus');
}
modbusConn = connection;
}
);
let callCount = 0;
...
function getPlcDMAndHSCPV(cb) {
let myCallCount = callCount++;
console.log('myCallCount', myCallCount);
async.parallel(
{
counter: innercb => modbusConn.readInputRegisters(
{address: 520, quantity: 2},
(err, result) => {
console.log('counterCb', {myCallCount: myCallCount, err: err, result: result}); innercb(err, result);
}
),
voltageAndRanges: innercb => modbusConn.readInputRegisters(
{address: 1000, quantity: 6},
(err, result) => {
console.log('voltageAndRangesCb', {myCallCount: myCallCount, err: err, result: result}); innercb(err, result);
}
),
},
(err, results) => {
if (err) {
return cb(err);
}
let mapped = [];
mapped[0] = results.voltageAndRanges.response.data[0].readInt16BE(0);
mapped[1] = results.voltageAndRanges.response.data[1].readInt16BE(0);
mapped[3] = Buffer.concat(results.counter.response.data).readInt32BE(0);
mapped[2] = (mapped[3] / pulseToDistanceRatio).toFixed(2);
mapped[4] = results.voltageAndRanges.response.data[4].readInt16BE(0);
mapped[5] = results.voltageAndRanges.response.data[5].readInt16BE(0);
cb(null, mapped);
}
);
}
myCallCount 0
counterCb { myCallCount: 0,
err: null,
result:
{ transactionId: 1,
protocol: 0,
length: 7,
unitId: 1,
pdu: <Buffer 04 04 02 7d d0 27>,
callback: [Function],
response: { code: 'ReadInputRegisters', data: [Object] } } }
voltageAndRangesCb { myCallCount: 0,
err: null,
result:
{ transactionId: 2,
protocol: 0,
length: 15,
unitId: 1,
pdu: <Buffer 04 0c 00 34 00 37 ff ff ff ff 00 01 00 01>,
callback: [Function],
response: { code: 'ReadInputRegisters', data: [Object] } } }
... 30 seconds of similar calls ...
myCallCount 599
counterCb { myCallCount: 599,
err: null,
result:
{ transactionId: 1199,
protocol: 0,
length: 7,
unitId: 1,
pdu: <Buffer 04 04 02 7d b7 aa>,
callback: [Function],
response: { code: 'ReadInputRegisters', data: [Object] } } }
voltageAndRangesCb { myCallCount: 599,
err: null,
result:
{ transactionId: 1200,
protocol: 0,
length: 15,
unitId: 1,
pdu: <Buffer 04 0c 00 3a 00 33 ff ff ff ff 00 01 00 01>,
callback: [Function],
response: { code: 'ReadInputRegisters', data: [Object] } } }
counterCb { myCallCount: 0,
err:
{ Error: GatewayTargetDeviceFailedToRespond
at Object.exports.error (/home/joel/WebstormProjects/well-logger/server/node_modules/modbus-pdu/lib/Exception.js:24:13)
at Timeout._onTimeout (/home/joel/WebstormProjects/well-logger/server/node_modules/modbus-stream/lib/transport/transport.js:89:33)
at ontimeout (timers.js:386:14)
at tryOnTimeout (timers.js:250:5)
at Timer.listOnTimeout (timers.js:214:5) code: 11 },
result: undefined }
error: uncaughtException: Callback was already called.
{ date: 'Wed Jul 19 2017 16:29:20 GMT-0600 (MDT)',
process:
{ pid: 15041,
uid: 1002,
gid: 1002,
cwd: '/home/joel/WebstormProjects/well-logger/server',
execPath: '/home/joel/.nvm/versions/node/v6.11.1/bin/node',
version: 'v6.11.1',
argv:
[ '/home/joel/.nvm/versions/node/v6.11.1/bin/node',
'/home/joel/WebstormProjects/well-logger/server/app.js' ],
memoryUsage:
{ rss: 57839616,
heapTotal: 36737024,
heapUsed: 32882016,
external: 396488 } },
os:
{ loadavg: [ 0.8125, 0.5537109375, 0.38232421875 ],
uptime: 194414 },
trace:
[ { column: 32,
file: '/home/joel/WebstormProjects/well-logger/server/node_modules/async/dist/async.js',
function: null,
line: 903,
method: null,
native: false },
{ column: 13,
file: '/home/joel/WebstormProjects/well-logger/server/node_modules/async/dist/async.js',
function: null,
line: 3835,
method: null,
native: false },
{ column: 93,
file: '/home/joel/WebstormProjects/well-logger/server/lib/plc.js',
function: 'modbusConn.readInputRegisters',
line: 108,
method: 'readInputRegisters',
native: false },
{ column: 14,
file: '/home/joel/WebstormProjects/well-logger/server/node_modules/modbus-stream/lib/transport/transport.js',
function: 'Timeout._onTimeout',
line: 89,
method: '_onTimeout',
native: false },
{ column: 14,
file: 'timers.js',
function: 'ontimeout',
line: 386,
method: null,
native: false },
{ column: 5,
file: 'timers.js',
function: 'tryOnTimeout',
line: 250,
method: null,
native: false },
{ column: 5,
file: 'timers.js',
function: 'Timer.listOnTimeout',
line: 214,
method: 'listOnTimeout',
native: false } ],
stack:
[ 'Error: Callback was already called.',
' at /home/joel/WebstormProjects/well-logger/server/node_modules/async/dist/async.js:903:32',
' at /home/joel/WebstormProjects/well-logger/server/node_modules/async/dist/async.js:3835:13',
' at modbusConn.readInputRegisters (/home/joel/WebstormProjects/well-logger/server/lib/plc.js:108:93)',
' at Timeout._onTimeout (/home/joel/WebstormProjects/well-logger/server/node_modules/modbus-stream/lib/transport/transport.js:89:14)',
' at ontimeout (timers.js:386:14)',
' at tryOnTimeout (timers.js:250:5)',
' at Timer.listOnTimeout (timers.js:214:5)' ] }
Hi ,
I am new to modbus & node.js . Nevertheless I was able to read and write holding registers of a my-PV Boiler Heater ( Model: ELWA-E ) . This heater screw in heater has a LAN and modbus-tcp connection.
I am not sure why the node execution continues (does not end) , and why a third communication fails.
The code below opens a connection, then reads all the holding registers, sets the target boiler temperature , and finally re-reads the set register to validate the change.
I need to somehow close the connection ( timeout , timer ? .... ) , and be able to do the last "readHoldingRegisters". Any help would be appreciated.
Here is the code -
In the modbus.js file the {retry:options.retry} seems to be clearing out all the options.
Changing it to {options} seems to resolve.:
if (typeof options.retry == "undefined") {
options.retry = 30000;
}
var socket = exports.drivers.tcp.connect(port, host, options);
socket.attach(exports.transports.tcp.prepare({ retry: options.retry }), next);
It is present twice in the file (line 45 and 66).
Thanks!
I'm trying to write multiple coils at once but I'm getting IllegalData error. I can write single coils without any problem, maybe that's not the format that I should use? If not, what should I use instead? Also, how should I format the buffers for writing registers?
modbus.tcp.connect(device.port, device.ip, { debug: null }, (err, connection) => {
connection.writeMultipleCoils({address: address, value: [1,0,0,0,1,1,1,0], extra: {unitId: device.id_slave}}, (err, data) => {
});
});
I have a serial connection to a Modbus Server and everything seems to work okay, but I seem to get a "GatewayTargetDeviceFailedToRespond". If I retry the operation, it seems to continue, but this causes the overall communication rate to be much slower than desired.
I tried using retries, retry, but the results seems to be the same.
I also tried modifying maxDataInterval, but again the results seemed to be similar.
What variable is used to decide how long to wait, before deciding the device failed to respond?
Is it one of the variables mentioned above?
Eric
For example,
modbus.serial.connect('/dev/ttyS1', {slaveId: 10}, (err, conn){
conn.on('read-coils', (req, reply) => {
console.log(req)
})
})
The events is always received for event if the slaveId is not 10, and it responds with exception when reply is not called (we should ignore when slaveId doesn't match).
Node can receive requests which is not intended for it in RS-485 network.
ERROR in ./node_modules/modbus-stream/lib/driver/serial.js
Module not found: Error: Can't resolve 'serialport/package'
I am trying to create a server and I need to send the reply after the client calls writeMultipleRegisters.
What are the correct parameters to send back and is there a helper function that will create the response?
Dear @jhillacre , @dresende , @jacobq , @buffcode , @insideGen
I am working on a proprietary protocol translator from /to modbus.
I need to discover all the modbus device master/slave and get the list of parameters they are able to support (finally the data model) for each devic discovered.
It's our data model for one parameter it could be string, boolean, real, integer, ....
{
"number": 0,
"identifier": "ParameTypeInteger",
"description": "",
"value": 0,
"minimum": -4096,
"maximum": 0,
"access": "readWrite",
"format": "%8.2f°",
"enumeration": "",
"factor": 32,
"isOnline": true,
"formula": "1*\n1/",
"default": -1024,
"type": "integer"
} {
"number": 1,
"identifier": "ParameTypeReal",
"description": "",
"value": 0,
"minimum": 0,
"maximum": 4096,
"access": "readWrite",
"format": "%8.2f°",
"enumeration": "",
"factor": 1,
"isOnline": true,
"formula": "10*\n10/",
"default": 100,
"type": "real"
},
{
"number": 2,
"identifier": "ParameTypeString",
"description": "",
"value": "text",
"access": "readWrite",
"enumeration": "Yes\nNo\nOk",
"isOnline": true,
"default": "default",
"type": "string"
},
{
"number": 3,
"identifier": "ParameTypeEnumeration",
"description": "",
"value": 0,
"access": "readWrite",
"enumeration": "Line\nMic+48V\nMic",
"isOnline": true,
"default": 0,
"type": "enum"
},
{
"number": 4,
"identifier": "ParameTypeBoolean",
"description": "",
"value": true,
"access": "readWrite",
"isOnline": true,
"default": false,
"type": "boolean"
}
How we could do with you code to generate a json file with all the devices ?
Best regards
Youssef
I am not able to find any information regarding the support of SSL / TLS. I am not able to see any specific security options on the tcp transport / connect options
Is it as simple as specifying the SSL port number instead?
The version of serialport included in package.json (<7) is not compatible with node 12 and generates a lot of errors during installation. Have you already planned the update of that package?
var modbus = require("modbus-stream");
module.exports = {
initModbus: function() {
modbus.tcp.server({ debug: "server" }, (connection) => {
connection.readHoldingRegisters( {address: 0, quantity: 1}, (err, info) => {
console.log("response", info.response.data);
});
}).listen(12345, () => {
modbus.tcp.connect(12345, { debug: "client" }, (err, connection) => {
connection.on("read-holding-registers", (request, reply) => {
reply(null, [234]);
});
});
});
}
}
Hi, thanks for your effort. Could not achieve just a simple thing. What can be wrong here?
Error output:
events.js:141
throw er; // Unhandled 'error' event
^
TypeError: blocks[i].copy is not a function
at Object.blocksToBuffer [as buildResponse] (/home/ubuntu/workspace/EasygenSlave/node_modules/modbus-stream/node_modules/modbus-pdu/lib/Helpers.js:111:13)
at Object.build (/home/ubuntu/workspace/EasygenSlave/node_modules/modbus-stream/node_modules/modbus-pdu/lib/Modbus.js:113:30)
at /home/ubuntu/workspace/EasygenSlave/node_modules/modbus-stream/lib/transport/transport.js:165:75
at Stream.<anonymous> (/home/ubuntu/workspace/EasygenSlave/modbus-tcp-server.js:12:13)
at emitTwo (events.js:87:13)
at Stream.emit (events.js:172:7)
at Transport.<anonymous> (/home/ubuntu/workspace/EasygenSlave/node_modules/modbus-stream/lib/stream.js:44:10)
at emitThree (events.js:97:13)
at Transport.emit (events.js:175:7)
at handle (/home/ubuntu/workspace/EasygenSlave/node_modules/modbus-stream/lib/transport/transport.js:156:16)
Can you give me guidance when you are available? Cheers.
Hi
I'm getting an array of buffers of registers with every connection.readHoldingRegisters call.
It looks like:
2019-11-04T22:11:33.896Z >> server-node 0x[ 00, 01, 00, 00, 00, DD, 01, 03, DA........
How can I turn off please? Thank you
It seems that this implementation assumes a "Unit identifer" (see 3.1.2 MODBUS On TCP/IP Application Data Unit ) value of 1
by default. How can this by changed by the caller / consuming application? Is there some property of the extra
options that can do this?
Hi!
I get this error GatewayTargetDeviceFailedToRespond
when I execute several times the readHoldingRegisters
function. I use the readHoldingRegisters
function inside a loop.
Any idea?
Thanks.
var modbus = require("modbus-stream"); // v0.38.0
var startDate = Date.now();
modbus.tcp.connect(502, "localhost", { "debug": null }, function (err, connection) {
if (err == null && connection != null) {
for (var i = 0 ; i < 10 ; i++) {
(function (address) {
connection.readHoldingRegisters({ "address": address, "quantity": 1 }, function (err, res) {
if (err != null) {
console.log((Date.now() - startDate) + "ms - Register[" + address + "]: " + err.message);
}
else if (res != null) {
console.log((Date.now() - startDate) + "ms - Register[" + address + "]: " + res.response.data[0].readInt16BE(0));
}
});
})(i);
}
}
});
3 executions with this test in the same context:
13ms - Register[0]: 10
14ms - Register[1]: 11
15ms - Register[2]: 12
15ms - Register[3]: 13
15ms - Register[4]: 14
15ms - Register[5]: 15
15ms - Register[6]: 16
15ms - Register[7]: 17
15ms - Register[9]: 19
30009ms - Register[8]: GatewayTargetDeviceFailedToRespond
13ms - Register[0]: 10
14ms - Register[1]: 11
14ms - Register[2]: 12
15ms - Register[5]: 15
15ms - Register[6]: 16
15ms - Register[7]: 17
15ms - Register[9]: 19
30009ms - Register[3]: GatewayTargetDeviceFailedToRespond
30009ms - Register[4]: GatewayTargetDeviceFailedToRespond
30009ms - Register[8]: GatewayTargetDeviceFailedToRespond
13ms - Register[0]: 10
14ms - Register[1]: 11
15ms - Register[2]: 12
15ms - Register[3]: 13
15ms - Register[4]: 14
15ms - Register[5]: 15
15ms - Register[6]: 16
15ms - Register[7]: 17
30010ms - Register[8]: GatewayTargetDeviceFailedToRespond
30010ms - Register[9]: GatewayTargetDeviceFailedToRespond
receive data from TCP client :
{ Error: GatewayTargetDeviceFailedToRespond
at Object.exports.error (/Users/mac/Desktop/RLLP-PCL5new/node_modules/modbus-pdu/lib/Exception.js:24:13)
at Timeout._onTimeout (/Users/mac/Desktop/RLLP-PCL5new/node_modules/modbus-stream/lib/transport/transport.js:92:33)
at ontimeout (timers.js:498:11)
at tryOnTimeout (timers.js:323:5)
at Timer.listOnTimeout (timers.js:290:5) code: 11 }
I cant find cause?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.