Skip to content

Commit b0b80c3

Browse files
committed
reconnect
1 parent 2103e88 commit b0b80c3

File tree

5 files changed

+69
-88
lines changed

5 files changed

+69
-88
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{
44
"name": "Node.js Launch",
55
"program": "${workspaceFolder}/server.js",
6-
"args": ["-p", "8081", "--modbus-holdingregister", "1:5", "10", "50:20", "--modbus-holdingregister","100:5", "--modbus-host", "localhost"],
6+
"args": ["-p", "8080","--modbus-not-onebased","--modbus-host", "localhost","--modbus-port", "5020", "--modbus-holdingregister", " 0:2","3","5:5","426:6","456:6"],
77
"request": "launch",
88
"skipFiles": [
99
"<node_internals>/**"

modbushandler.js

Lines changed: 47 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
`use strict`;
22

3-
var modbus = require('jsmodbus');
4-
var opcua = require("node-opcua");
5-
const net = require('net')
3+
const opcua = require("node-opcua");
4+
const Reconnect = require('node-net-reconnect')
5+
const net = require('net');
6+
const { errorCodeToMessage } = require('jsmodbus/dist/codes');
67

78
var modbushandler = {
89
modbusclient: {},
@@ -36,7 +37,7 @@ var modbushandler = {
3637
}
3738
}
3839
});
39-
setInterval(polldata.bind(null, this.modbusclient, this.ValueMap, name, type, address, count), pollrate);
40+
setInterval(polldata.bind(null, this.socket, this.modbusclient, this.ValueMap, name, type, address, count), pollrate);
4041
},
4142
ReadValue: function (name) {
4243
//console.log("read ", this.ValueMap);
@@ -78,10 +79,12 @@ var modbushandler = {
7879
'host': host,
7980
'port': port,
8081
'autoReconnect': true,
81-
'reconnectTimeout': 1000,
82+
'retryAlways' : true,
83+
'retryTime': 1000,
8284
'timeout': 5000,
8385
'keepAlive': 5000
8486
};
87+
let recon = new Reconnect( this.socket, options);
8588
this.socket.connect(options);
8689

8790
console.log("Created a Modbus device on " + host + ":" + port + " " + unit);
@@ -100,87 +103,61 @@ function toOPCType(type) {
100103
}
101104
}
102105

103-
function polldata(client, ValueMap, rootname, type, address, count) {
104-
if (this.socket?.readState != 'open') {
106+
async function read(client, readFunction, rootname, address, count, ValueMap,) {
107+
try {
108+
const resp = await client[readFunction](address, count);
109+
resp.response.body.values.forEach(function (value, i) {
110+
var fulladdress = (address + i).toString();
111+
ValueMap[rootname + fulladdress] = {
112+
v: new opcua.Variant({ dataType: opcua.DataType.Int32, value: value }),
113+
q: "good"
114+
};
115+
});
116+
} catch (err) {
105117
for (var i = 0; i < count; ++i) {
106118
var fulladdress = (address + i).toString();
107119
ValueMap[rootname + fulladdress] = {
108-
v: new opcua.Variant({ dataType: opcua.DataType.Null}),
109-
q: "BadNotConnected"
120+
q: "BadCommunicationError"
110121
};
111122
}
112-
} else {
113-
try {
123+
console.error("Unable to read items address: %d count: %d:", address, count, err);
124+
}
125+
}
126+
127+
async function polldata(socket, client, ValueMap, rootname, type, address, count) {
128+
try {
129+
if (socket.readyState != 'open') {
130+
for (var i = 0; i < count; ++i) {
131+
var fulladdress = (address + i).toString();
132+
ValueMap[rootname + fulladdress] = {
133+
q: "BadNotConnected"
134+
};
135+
}
136+
} else {
137+
114138
switch (type) {
115139
case "holdingregister":
116-
client.readHoldingRegisters(address, count).then(function (resp) {
117-
// resp will look like { fc: 3, byteCount: 20, register: [ values 0 - 10 ], payload: <Buffer> }
118-
// console.log(resp);
119-
resp.register.forEach(function (value, i) {
120-
var fulladdress = (address + i).toString();
121-
ValueMap[rootname + fulladdress] = {
122-
v: new opcua.Variant({ dataType: opcua.DataType.Int32, value: value }),
123-
q: "good"
124-
};
125-
});
126-
});
127-
140+
await read(client, 'readHoldingRegisters', rootname, address, count, ValueMap);
128141
break;
129142
case "inputregisters":
130-
131-
client.readInputRegisters(address, count).then(function (resp) {
132-
// resp will look like { fc: 3, byteCount: 20, register: [ values 0 - 10 ], payload: <Buffer> }
133-
//console.log(resp);
134-
resp.register.forEach(function (value, i) {
135-
var fulladdress = (address + i).toString();
136-
ValueMap[rootname + fulladdress] = {
137-
v: new opcua.Variant({ dataType: opcua.DataType.Int32, value: value }),
138-
q: "good"
139-
};
140-
});
141-
});
142-
143+
await read(client, 'readInputRegisters', rootname, address, count, ValueMap);
143144
break;
144145
case "coils":
145-
client.readCoils(address, count).then(function (resp) {
146-
// resp will look like { fc: 3, byteCount: 20, register: [ values 0 - 10 ], payload: <Buffer> }
147-
//console.log(resp);
148-
149-
resp.coils.forEach(function (value, i) {
150-
var fulladdress = (address + i).toString();
151-
ValueMap[rootname + fulladdress] = {
152-
v: new opcua.Variant({ dataType: opcua.DataType.Boolean, value: value }),
153-
q: "good"
154-
};
155-
});
156-
});//.fail(console.log);
146+
await read(client, 'readCoils', rootname, address, count, ValueMap);
157147
break;
158148
case "discreteinputs":
159-
client.readDiscreteInputs(address, count).then(function (resp) {
160-
// resp will look like { fc: 3, byteCount: 20, register: [ values 0 - 10 ], payload: <Buffer> }
161-
//console.log(resp);
162-
resp.coils.forEach(function (value, i) {
163-
var fulladdress = (address + i).toString();
164-
ValueMap[rootname + fulladdress] = {
165-
v: new opcua.Variant({ dataType: opcua.DataType.Boolean, value: value }),
166-
q: "good"
167-
};
168-
});
169-
});//.fail(console.log);
149+
await read(client, 'readDiscreteInputs', rootname, address, count, ValueMap);
170150
break;
171151
}
172-
173-
} catch (err) {
174-
for (var i = 0; i < count; ++i) {
175-
var fulladdress = (address + i).toString();
176-
ValueMap[rootname + fulladdress] = {
177-
v: new opcua.Variant({ dataType: opcua.DataType.Null }),
178-
q: "BadCommunicationError"
179-
};
180-
}
181-
console.error("Unable to poll items: " + err);
182152
}
183-
153+
} catch (err) {
154+
for (var i = 0; i < count; ++i) {
155+
var fulladdress = (address + i).toString();
156+
ValueMap[rootname + fulladdress] = {
157+
q: "BadCommunicationError"
158+
};
159+
}
160+
console.error("Unable to poll items: ", err);
184161
}
185162
}
186163
module.exports = modbushandler;

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
"config": "^3.3.6",
1414
"jsmodbus": "~4.0",
1515
"lodash": "~4.17",
16-
"node-opcua": "~2.50"
16+
"node-opcua": "~2.50",
17+
"net-keepalive" : "~3.0",
18+
"node-net-reconnect" : "~0.2"
1719
}
1820
}

sample/docker-compose.yaml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
opcua-server:
2-
container_name: opcua-server
3-
image: ghcr.io/bobiene/opcmodbusuaserver
4-
ports:
5-
- 8080
6-
command: >
7-
--modbus-host modbus-server
8-
--modbus.port 5020
9-
--modbus-not-onebased
10-
--modbus-holdingregister 0:100
11-
--modbus-inputregisters 0:2 3 5:5 426:6 456:6
1+
# opcua-server:
2+
# container_name: opcua-server
3+
# image: ghcr.io/bobiene/opcmodbusuaserver
4+
# ports:
5+
# - 8080:8080
6+
# command: >
7+
# --modbus-host modbus-server
8+
# --modbus-port 5020
9+
# --modbus-not-onebased
10+
# --modbus-holdingregister 0:100
11+
# --modbus-inputregisters 0:2 3 5:5 426:6 456:6
1212
modbus-server:
1313
container_name: modbus-server
1414
image: oitc/modbus-server
1515
restart: always
1616
command: -f /server_config.json
17-
expose:
18-
- 5020
17+
ports:
18+
- 5020:5020
1919
volumes:
2020
- ./modbus-server.json:/server_config.json:ro

server.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ processArgs
3333
.addOption(new commander.Option('-p, --port <number>', 'opc ua server port number').default(config.get('port')).env('PORT').argParser(parseMyInt))
3434
.addOption(new commander.Option('-u, --url <path>', 'opc ua server url-path').default(config.get('url')).env('URL_PATH'))
3535
.addOption(new commander.Option('--modbus-host <host>', 'specify the modbus host address').env('MODBUS_HOST'))
36-
.addOption(new commander.Option('--modbus-port <port>', 'specify the modbus tcp port').default('502').env('MODBUS_PORT').argParser(parseMyInt))
37-
.addOption(new commander.Option('--modbus-unit-id <unitId>', 'specify the modbus unit id').default('1').env('MODBUS_UNITID').argParser(parseMyInt))
36+
.addOption(new commander.Option('--modbus-port <port>', 'specify the modbus tcp port').default(502).env('MODBUS_PORT').argParser(parseMyInt))
37+
.addOption(new commander.Option('--modbus-pollrate <pollrate>', 'specify the pollrate in milliseconds').default(1000).env('MODBUS_POLLRATE').argParser(parseMyInt))
38+
.addOption(new commander.Option('--modbus-unit-id <unitId>', 'specify the modbus unit id').default(1).env('MODBUS_UNITID').argParser(parseMyInt))
3839
.addOption(new commander.Option('--modbus-not-onebased', 'disable one based addresses'))
3940
.addOption(new commander.Option('--modbus-holdingregister [ranges...]', 'specify the modbus holdingregister ranges').default([]).argParser(parseMyRange))
4041
.addOption(new commander.Option('--modbus-coils [ranges...]', 'specify the modbus coils ranges').default([]).argParser(parseMyRange))
@@ -129,8 +130,9 @@ function create_modbus_variables(server, modbushandler, rootname, register, type
129130
registerDeviceToUAServer(server, devicesnode, namespace, {
130131
"modbushost": options.modbusHost,
131132
"modbusport": options.modbusPort,
133+
"pollrate" : options.modbusPollrate,
132134
"unit": options.modbusUnitId,
133-
"onebased": !!!options.modbusNotOnebased,
135+
"onebased": !!options.modbusNotOnebased,
134136
"deviceaddressspace": [
135137
{ "type": "holdingregister", "addresses": options.modbusHoldingregister },
136138
{ "type": "coils", "addresses": options.modbusCoils },

0 commit comments

Comments
 (0)