osiota-app-modbus 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/busscan.js +7 -1
- package/busscan_tcp.js +52 -0
- package/helper_modbus.js +44 -22
- package/index.js +63 -17
- package/package.json +3 -3
- package/schema.json +3 -2
package/busscan.js
CHANGED
|
@@ -15,13 +15,19 @@ var app_config = {
|
|
|
15
15
|
var m = new modbus.modbus(app_config);
|
|
16
16
|
m.onerror = function(err) {
|
|
17
17
|
if (err.name === "TransactionTimedOutError") {
|
|
18
|
+
m.client._port.openFlag = true;
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
20
21
|
console.log("modbus, error:", err.stack || err);
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
m.connect(app_config.connect_type, app_config.connect_path, app_config.connect_options, function() {
|
|
25
|
+
m.connect(app_config.connect_type, app_config.connect_path, app_config.connect_options, function(err) {
|
|
26
|
+
if (err) {
|
|
27
|
+
console.error("Error:", err);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log("Connected");
|
|
25
31
|
scan();
|
|
26
32
|
});
|
|
27
33
|
|
package/busscan_tcp.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
var modbus = require("./helper_modbus.js");
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
var app_config = {
|
|
7
|
+
"connect_type": "Telnet",
|
|
8
|
+
"connect_path": "192.168.2.111",
|
|
9
|
+
"connect_options": {
|
|
10
|
+
"port": 12345
|
|
11
|
+
},
|
|
12
|
+
"packet_timeout": 200
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
var m = new modbus.modbus(app_config);
|
|
16
|
+
m.onerror = function(err) {
|
|
17
|
+
if (err.name === "TransactionTimedOutError") {
|
|
18
|
+
m.client._port.openFlag = true;
|
|
19
|
+
//m.client.openFlag = true;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
console.log("modbus, error:", err.stack || err);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
m.connect(app_config.connect_type, app_config.connect_path, app_config.connect_options, function(err) {
|
|
27
|
+
if (err) {
|
|
28
|
+
console.error("Error:", err);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
console.log("Connected");
|
|
32
|
+
scan();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
var cid = 1;
|
|
36
|
+
var scan = function() {
|
|
37
|
+
if (cid > 255) {
|
|
38
|
+
m.close();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
m.send_set("writeFC1", cid, 0, 1, function(err) {
|
|
43
|
+
if (err) {
|
|
44
|
+
console.log(cid, "No Client");
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log(cid, "Found");
|
|
48
|
+
}
|
|
49
|
+
cid++;
|
|
50
|
+
scan();
|
|
51
|
+
});
|
|
52
|
+
};
|
package/helper_modbus.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
|
|
2
2
|
var ModbusRTU = require("modbus-serial");
|
|
3
3
|
|
|
4
|
-
var read_data = function(client_items, address_min, data) {
|
|
4
|
+
var read_data = function(client_items, address_min, data, buffer) {
|
|
5
5
|
client_items.forEach(function(c) {
|
|
6
6
|
c.callback(data.slice(c.address-address_min,
|
|
7
|
-
c.address-address_min+c.length)
|
|
7
|
+
c.address-address_min+c.length),
|
|
8
|
+
buffer.slice(2*(c.address-address_min),
|
|
9
|
+
2*(c.address-address_min+c.length)));
|
|
8
10
|
});
|
|
9
11
|
};
|
|
10
12
|
|
|
@@ -28,6 +30,10 @@ exports.modbus = function(config) {
|
|
|
28
30
|
this.packet_delay = config.packet_delay;
|
|
29
31
|
this.circle_delay = config.circle_delay;
|
|
30
32
|
this.client.setTimeout(config.packet_timeout);
|
|
33
|
+
this.max_payload = 60;
|
|
34
|
+
if (typeof config.max_payload === "number") {
|
|
35
|
+
this.max_payload = config.max_payload;
|
|
36
|
+
}
|
|
31
37
|
|
|
32
38
|
this.commands = {
|
|
33
39
|
"output boolean": {
|
|
@@ -54,7 +60,7 @@ exports.modbus = function(config) {
|
|
|
54
60
|
this.set_commands = [];
|
|
55
61
|
|
|
56
62
|
this.onerror = function(err) {
|
|
57
|
-
console.
|
|
63
|
+
console.error("modbus, run:", err.stack || err);
|
|
58
64
|
return false;
|
|
59
65
|
};
|
|
60
66
|
|
|
@@ -95,12 +101,16 @@ exports.modbus.prototype.client_add = function(type, cid, config) {
|
|
|
95
101
|
throw new Error("type undefined: " + type);
|
|
96
102
|
return;
|
|
97
103
|
}
|
|
104
|
+
var gid = config.address - (config.address % this.max_payload);
|
|
98
105
|
if (typeof this.commands[type].clients[cid] !== "object" ||
|
|
99
|
-
|
|
100
|
-
this.commands[type].clients[cid] = [];
|
|
106
|
+
this.commands[type].clients[cid] === null) {
|
|
107
|
+
this.commands[type].clients[cid] = {"groups": []};
|
|
108
|
+
}
|
|
109
|
+
if (!Array.isArray(this.commands[type].clients[cid].groups[gid])) {
|
|
110
|
+
this.commands[type].clients[cid].groups[gid] = [];
|
|
101
111
|
}
|
|
102
112
|
|
|
103
|
-
this.commands[type].clients[cid].push(config);
|
|
113
|
+
this.commands[type].clients[cid].groups[gid].push(config);
|
|
104
114
|
};
|
|
105
115
|
|
|
106
116
|
exports.modbus.prototype.client_can_set = function(type) {
|
|
@@ -146,7 +156,7 @@ exports.modbus.prototype.send_poll = function(command, cid, address, length, cli
|
|
|
146
156
|
length,
|
|
147
157
|
function(err, data) {
|
|
148
158
|
if (already_called) {
|
|
149
|
-
console.
|
|
159
|
+
console.warn("Warn: Called callback twice. Command: POLL", command, cid, address, data, "\nThis happens after a timeout. Please increase the packet timeout.");
|
|
150
160
|
return;
|
|
151
161
|
}
|
|
152
162
|
already_called = true;
|
|
@@ -161,11 +171,11 @@ exports.modbus.prototype.send_poll = function(command, cid, address, length, cli
|
|
|
161
171
|
if (_this.onerror(err))
|
|
162
172
|
return;
|
|
163
173
|
} else {
|
|
164
|
-
read_data(client_items, address, data.data);
|
|
174
|
+
read_data(client_items, address, data.data, data.buffer);
|
|
165
175
|
}
|
|
166
176
|
callback();
|
|
167
177
|
}
|
|
168
|
-
|
|
178
|
+
);
|
|
169
179
|
};
|
|
170
180
|
exports.modbus.prototype.send_set = function(command, cid, address, data, callback) {
|
|
171
181
|
var _this = this;
|
|
@@ -179,7 +189,7 @@ exports.modbus.prototype.send_set = function(command, cid, address, data, callba
|
|
|
179
189
|
data,
|
|
180
190
|
function(err, new_data) {
|
|
181
191
|
if (already_called) {
|
|
182
|
-
console.
|
|
192
|
+
console.warn("Warn: Called callback twice. Command: SET", command, cid, address, data, "\nThis happens after a timeout. Please increase the packet timeout.");
|
|
183
193
|
return;
|
|
184
194
|
}
|
|
185
195
|
already_called = true;
|
|
@@ -222,11 +232,14 @@ exports.modbus.prototype.connect = function(connect_type, path, options,
|
|
|
222
232
|
}
|
|
223
233
|
});
|
|
224
234
|
|
|
225
|
-
|
|
226
|
-
for (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
235
|
+
this.poll_commands = [];
|
|
236
|
+
for (let type in this.commands) {
|
|
237
|
+
for (let cid in this.commands[type].clients) {
|
|
238
|
+
for (let gid in this.commands[type].clients[cid].groups) {
|
|
239
|
+
let address_min = null;
|
|
240
|
+
let address_max = null;
|
|
241
|
+
this.commands[type].clients[cid].groups[gid].
|
|
242
|
+
forEach(function(c) {
|
|
230
243
|
if (address_min === null || c.address < address_min) {
|
|
231
244
|
address_min = c.address;
|
|
232
245
|
}
|
|
@@ -238,13 +251,22 @@ exports.modbus.prototype.connect = function(connect_type, path, options,
|
|
|
238
251
|
//commands[type].clients[cid].address = address_min;
|
|
239
252
|
//commands[type].clients[cid].length = address_max-address_min;
|
|
240
253
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
254
|
+
let command = this.commands[type].command_poll;
|
|
255
|
+
let address = address_min;
|
|
256
|
+
let length = address_max-address_min;
|
|
257
|
+
let client_items = this.commands[type].clients[cid].groups[gid];
|
|
258
|
+
|
|
259
|
+
this.poll_commands.push(function(next) {
|
|
260
|
+
_this.send_poll(
|
|
261
|
+
command,
|
|
262
|
+
+cid,
|
|
263
|
+
address_min,
|
|
264
|
+
length,
|
|
265
|
+
client_items,
|
|
266
|
+
next
|
|
267
|
+
);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
248
270
|
}
|
|
249
271
|
}
|
|
250
272
|
|
package/index.js
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
|
|
2
2
|
var modbus = require("./helper_modbus.js");
|
|
3
3
|
|
|
4
|
-
var map_value = function(datatype, data) {
|
|
4
|
+
var map_value = function(datatype, data, buffer) {
|
|
5
5
|
if (datatype == "uint16") {
|
|
6
|
+
//return buffer.readUInt16BE(0);
|
|
6
7
|
return data[0];
|
|
7
8
|
}
|
|
9
|
+
else if (datatype == "floatBE") {
|
|
10
|
+
return buffer.readFloatBE(0);
|
|
11
|
+
}
|
|
12
|
+
else if (datatype == "floatLE") {
|
|
13
|
+
return buffer.readFloatLE(0);
|
|
14
|
+
}
|
|
15
|
+
else if (datatype == "floatBE-swap") {
|
|
16
|
+
buffer.swap16();
|
|
17
|
+
return buffer.readFloatBE(0);
|
|
18
|
+
}
|
|
19
|
+
else if (datatype == "floatLE-swap") {
|
|
20
|
+
buffer.swap16();
|
|
21
|
+
return buffer.readFloatLE(0);
|
|
22
|
+
}
|
|
8
23
|
else if (datatype == "boolean") {
|
|
9
24
|
return data[0] != 0;
|
|
10
25
|
}
|
|
@@ -15,6 +30,30 @@ var remap_value = function(datatype, value) {
|
|
|
15
30
|
if (datatype == "uint16") {
|
|
16
31
|
return [ value*1 ];
|
|
17
32
|
}
|
|
33
|
+
if (datatype == "floatBE") {
|
|
34
|
+
let buffer = Buffer.alloc(4);
|
|
35
|
+
buffer.writeFloatBE(value);
|
|
36
|
+
return buffer;
|
|
37
|
+
//return new Uint16Array(buffer.buffer,buffer.byteOffset,buffer.length/2);
|
|
38
|
+
//return [ buffer.readUInt16BE(0), buffer.readUInt16BE(2) ];
|
|
39
|
+
}
|
|
40
|
+
else if (datatype == "floatLE") {
|
|
41
|
+
let buffer = Buffer.alloc(4);
|
|
42
|
+
buffer.writeFloatLE(value);
|
|
43
|
+
return buffer;
|
|
44
|
+
}
|
|
45
|
+
else if (datatype == "floatBE-swap") {
|
|
46
|
+
let buffer = Buffer.alloc(4);
|
|
47
|
+
buffer.writeFloatBE(value);
|
|
48
|
+
buffer.swap16();
|
|
49
|
+
return buffer;
|
|
50
|
+
}
|
|
51
|
+
else if (datatype == "floatLE-swap") {
|
|
52
|
+
let buffer = Buffer.alloc(4);
|
|
53
|
+
buffer.writeFloatLE(value);
|
|
54
|
+
buffer.swap16();
|
|
55
|
+
return buffer;
|
|
56
|
+
}
|
|
18
57
|
else if (datatype == "boolean") {
|
|
19
58
|
return [ value*1 ];
|
|
20
59
|
}
|
|
@@ -22,11 +61,6 @@ var remap_value = function(datatype, value) {
|
|
|
22
61
|
};
|
|
23
62
|
|
|
24
63
|
exports.init = function(node, app_config, main, host_info) {
|
|
25
|
-
|
|
26
|
-
var baudrate = 38400;
|
|
27
|
-
|
|
28
|
-
var models = {};
|
|
29
|
-
|
|
30
64
|
if (typeof app_config !== "object") {
|
|
31
65
|
app_config = {};
|
|
32
66
|
}
|
|
@@ -41,7 +75,7 @@ exports.init = function(node, app_config, main, host_info) {
|
|
|
41
75
|
|
|
42
76
|
var m = new modbus.modbus(app_config);
|
|
43
77
|
m.onerror = function(err) {
|
|
44
|
-
console.
|
|
78
|
+
console.error("modbus, error:", err.stack || err);
|
|
45
79
|
|
|
46
80
|
if (typeof err.message === "string" &&
|
|
47
81
|
err.message.match(/^Timed out/))
|
|
@@ -52,7 +86,7 @@ exports.init = function(node, app_config, main, host_info) {
|
|
|
52
86
|
if (this.close)
|
|
53
87
|
this.close();
|
|
54
88
|
|
|
55
|
-
console.
|
|
89
|
+
console.info("modbus, restarting ...");
|
|
56
90
|
_this._reinit_delay(5000);
|
|
57
91
|
return true;
|
|
58
92
|
};
|
|
@@ -60,13 +94,13 @@ exports.init = function(node, app_config, main, host_info) {
|
|
|
60
94
|
var map_itemtype = function(type) {
|
|
61
95
|
if (typeof type !== "string")
|
|
62
96
|
return "output boolean";
|
|
63
|
-
if (type.match(
|
|
97
|
+
if (type.match(/^FC(1|5|15)$/i))
|
|
64
98
|
return "output boolean";
|
|
65
|
-
if (type.match(
|
|
99
|
+
if (type.match(/^FC2$/i))
|
|
66
100
|
return "input boolean";
|
|
67
|
-
if (type.match(
|
|
101
|
+
if (type.match(/^FC(3|6|16)$/i))
|
|
68
102
|
return "output register";
|
|
69
|
-
if (type.match(
|
|
103
|
+
if (type.match(/^FC4$/i))
|
|
70
104
|
return "input register";
|
|
71
105
|
|
|
72
106
|
if (type.match(/coil/))
|
|
@@ -84,6 +118,10 @@ exports.init = function(node, app_config, main, host_info) {
|
|
|
84
118
|
return "output boolean";
|
|
85
119
|
};
|
|
86
120
|
|
|
121
|
+
node.announce({
|
|
122
|
+
"type": "modbus.app"
|
|
123
|
+
});
|
|
124
|
+
|
|
87
125
|
var map = node.map(app_config.map, null, true, null,
|
|
88
126
|
function(n,metadata,config) {
|
|
89
127
|
var command = map_itemtype(config.type);
|
|
@@ -92,7 +130,11 @@ exports.init = function(node, app_config, main, host_info) {
|
|
|
92
130
|
var length = config.length;
|
|
93
131
|
if (typeof length !== "number") {
|
|
94
132
|
var tmp = remap_value(config.datatype, 0);
|
|
95
|
-
|
|
133
|
+
if (Buffer.isBuffer(tmp)) {
|
|
134
|
+
length = tmp.length / 2;
|
|
135
|
+
} else {
|
|
136
|
+
length = tmp.length;
|
|
137
|
+
}
|
|
96
138
|
}
|
|
97
139
|
|
|
98
140
|
var type = "number";
|
|
@@ -104,8 +146,8 @@ exports.init = function(node, app_config, main, host_info) {
|
|
|
104
146
|
m.client_add(command, cid, {
|
|
105
147
|
"address": config.address || 0,
|
|
106
148
|
"length": length || 1,
|
|
107
|
-
"callback": function(data) {
|
|
108
|
-
var value = map_value(config.datatype, data);
|
|
149
|
+
"callback": function(data, buffer) {
|
|
150
|
+
var value = map_value(config.datatype, data, buffer);
|
|
109
151
|
// better name: reset
|
|
110
152
|
if (config.erase && value) {
|
|
111
153
|
// uninitialized?
|
|
@@ -141,6 +183,9 @@ exports.init = function(node, app_config, main, host_info) {
|
|
|
141
183
|
}
|
|
142
184
|
});
|
|
143
185
|
};
|
|
186
|
+
n.rpc_toggle = function(reply, time) {
|
|
187
|
+
return n.rpc_set(reply, !n.value, time);
|
|
188
|
+
};
|
|
144
189
|
n.rpc_publish = function(reply, time, value) {
|
|
145
190
|
return n.rpc_set(reply, value, time);
|
|
146
191
|
};
|
|
@@ -163,7 +208,8 @@ exports.init = function(node, app_config, main, host_info) {
|
|
|
163
208
|
});
|
|
164
209
|
|
|
165
210
|
// open connection to a port
|
|
166
|
-
m.connect(app_config.connect_type, app_config.connect_path,
|
|
211
|
+
m.connect(app_config.connect_type, app_config.connect_path,
|
|
212
|
+
JSON.parse(JSON.stringify(app_config.connect_options || {})));
|
|
167
213
|
|
|
168
|
-
return [map, m];
|
|
214
|
+
return [node, map, m];
|
|
169
215
|
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "osiota-app-modbus",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "This application connects devices via Modbus",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"modbus-serial": "^
|
|
8
|
-
"serialport": "^
|
|
7
|
+
"modbus-serial": "^8.0.23",
|
|
8
|
+
"serialport": "^13.0.0"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
11
|
"osiota-dev": "^1.x"
|
package/schema.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "object",
|
|
3
|
-
"title": "osiota
|
|
3
|
+
"title": "osiota Application Modbus",
|
|
4
4
|
"description": "This application connects devices via Modbus.",
|
|
5
5
|
"oneOf": [{
|
|
6
6
|
"description": "Modbus Serial Interface",
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"type": {
|
|
113
113
|
"title": "Modbus Field Type",
|
|
114
114
|
"type": "string",
|
|
115
|
-
"enum": [ "input boolean", "input register", "output
|
|
115
|
+
"enum": [ "input boolean", "input register", "output boolean", "output register" ]
|
|
116
116
|
},
|
|
117
117
|
"datatype": {
|
|
118
118
|
"title": "Field Data Type",
|
|
@@ -136,6 +136,7 @@
|
|
|
136
136
|
"power": 60
|
|
137
137
|
}
|
|
138
138
|
}],
|
|
139
|
+
"additionalProperties": false,
|
|
139
140
|
"required": [ "id", "address", "datatype" ]
|
|
140
141
|
}
|
|
141
142
|
}
|