node-red-contrib-modbus-modpackqt 1.1.85 → 2.0.0
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/CHANGELOG.md +58 -0
- package/CONTRIBUTING.md +70 -0
- package/DISCLAIMER.md +92 -0
- package/LICENSE +21 -0
- package/README.md +155 -166
- package/SECURITY.md +50 -0
- package/examples/basic-flow.json +130 -185
- package/nodes/modpackqt-config.html +106 -89
- package/nodes/modpackqt-config.js +345 -18
- package/nodes/modpackqt-master-read.html +16 -19
- package/nodes/modpackqt-master-read.js +27 -18
- package/nodes/modpackqt-master-write.html +12 -16
- package/nodes/modpackqt-master-write.js +49 -26
- package/nodes/modpackqt-slave-read.html +12 -85
- package/nodes/modpackqt-slave-read.js +27 -40
- package/nodes/modpackqt-slave-write.html +13 -94
- package/nodes/modpackqt-slave-write.js +24 -32
- package/nodes/modpackqt-traffic.html +118 -0
- package/nodes/modpackqt-traffic.js +68 -0
- package/package.json +24 -6
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('modpackqt-traffic', {
|
|
3
|
+
category: 'ModPackQT',
|
|
4
|
+
color: '#22c55e',
|
|
5
|
+
defaults: {
|
|
6
|
+
name: { value: '' },
|
|
7
|
+
server: { value: '', type: 'modpackqt-config', required: true },
|
|
8
|
+
filterDirection: { value: 'any' },
|
|
9
|
+
filterKind: { value: 'any' },
|
|
10
|
+
filterFc: { value: 'any' },
|
|
11
|
+
filterTarget: { value: '' },
|
|
12
|
+
format: { value: 'object' },
|
|
13
|
+
alsoLog: { value: false }
|
|
14
|
+
},
|
|
15
|
+
inputs: 0,
|
|
16
|
+
outputs: 1,
|
|
17
|
+
icon: 'font-awesome/fa-eye',
|
|
18
|
+
label: function () {
|
|
19
|
+
const parts = [];
|
|
20
|
+
if (this.filterKind !== 'any') parts.push(this.filterKind);
|
|
21
|
+
if (this.filterDirection !== 'any') parts.push(this.filterDirection);
|
|
22
|
+
if (this.filterFc !== 'any') parts.push('FC' + this.filterFc);
|
|
23
|
+
if (this.filterTarget) parts.push(this.filterTarget);
|
|
24
|
+
return this.name || ('traffic' + (parts.length ? ' · ' + parts.join(' ') : ''));
|
|
25
|
+
},
|
|
26
|
+
paletteLabel: 'modbus traffic'
|
|
27
|
+
});
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<script type="text/html" data-template-name="modpackqt-traffic">
|
|
31
|
+
<div class="form-row"><label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
32
|
+
<input type="text" id="node-input-name" placeholder="Name"></div>
|
|
33
|
+
<div class="form-row"><label for="node-input-server"><i class="fa fa-cog"></i> Runtime</label>
|
|
34
|
+
<input type="text" id="node-input-server"></div>
|
|
35
|
+
|
|
36
|
+
<h4 style="margin-top:14px">Filters (optional)</h4>
|
|
37
|
+
<div class="form-row"><label for="node-input-filterKind"><i class="fa fa-server"></i> Kind</label>
|
|
38
|
+
<select id="node-input-filterKind">
|
|
39
|
+
<option value="any">Any</option>
|
|
40
|
+
<option value="master">Master only</option>
|
|
41
|
+
<option value="slave">Slave only</option>
|
|
42
|
+
</select>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="form-row"><label for="node-input-filterDirection"><i class="fa fa-exchange"></i> Direction</label>
|
|
45
|
+
<select id="node-input-filterDirection">
|
|
46
|
+
<option value="any">Any</option>
|
|
47
|
+
<option value="read">Read only</option>
|
|
48
|
+
<option value="write">Write only</option>
|
|
49
|
+
</select>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="form-row"><label for="node-input-filterFc"><i class="fa fa-list"></i> Function Code</label>
|
|
52
|
+
<select id="node-input-filterFc">
|
|
53
|
+
<option value="any">Any</option>
|
|
54
|
+
<option value="1">FC1 — Read Coils</option>
|
|
55
|
+
<option value="2">FC2 — Read Discrete Inputs</option>
|
|
56
|
+
<option value="3">FC3 — Read Holding</option>
|
|
57
|
+
<option value="4">FC4 — Read Input</option>
|
|
58
|
+
<option value="5">FC5 — Write Coil</option>
|
|
59
|
+
<option value="6">FC6 — Write Register</option>
|
|
60
|
+
<option value="15">FC15 — Write Coils</option>
|
|
61
|
+
<option value="16">FC16 — Write Registers</option>
|
|
62
|
+
</select>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="form-row"><label for="node-input-filterTarget"><i class="fa fa-filter"></i> Target contains</label>
|
|
65
|
+
<input type="text" id="node-input-filterTarget" placeholder="e.g. 192.168.1.10 or rtu:/dev/ttyUSB0"></div>
|
|
66
|
+
|
|
67
|
+
<h4 style="margin-top:14px">Output</h4>
|
|
68
|
+
<div class="form-row"><label for="node-input-format"><i class="fa fa-code"></i> Payload</label>
|
|
69
|
+
<select id="node-input-format">
|
|
70
|
+
<option value="object">Full event object</option>
|
|
71
|
+
<option value="summary">One-line summary string</option>
|
|
72
|
+
</select>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="form-row"><label for="node-input-alsoLog" style="width:auto">
|
|
75
|
+
<input type="checkbox" id="node-input-alsoLog" style="width:auto;vertical-align:middle">
|
|
76
|
+
Also write to Node-RED log
|
|
77
|
+
</label></div>
|
|
78
|
+
|
|
79
|
+
<div class="form-tips">
|
|
80
|
+
<b>Passive monitor.</b> No input wire — just listens to all Modbus ops on the runtime
|
|
81
|
+
and emits one message each. Free.
|
|
82
|
+
</div>
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<script type="text/html" data-help-name="modpackqt-traffic">
|
|
86
|
+
<p>
|
|
87
|
+
Passive Modbus traffic monitor. Subscribes to all Modbus operations performed by any
|
|
88
|
+
master or slave node sharing the same runtime config and emits one message per op.
|
|
89
|
+
</p>
|
|
90
|
+
|
|
91
|
+
<h3>Output payload (object format)</h3>
|
|
92
|
+
<pre>{
|
|
93
|
+
ts: "2026-05-09T14:23:01.234Z",
|
|
94
|
+
direction: "read" | "write",
|
|
95
|
+
kind: "master" | "slave",
|
|
96
|
+
target: "192.168.1.10:502" | "local:1502" | "rtu:/dev/ttyUSB0",
|
|
97
|
+
unitId: 1,
|
|
98
|
+
fc: 3, // null for slave events
|
|
99
|
+
registerType: "holding",// only set for slave events
|
|
100
|
+
address: 100,
|
|
101
|
+
quantity: 2,
|
|
102
|
+
values: [16828, 0], // raw register values
|
|
103
|
+
durationMs: 12,
|
|
104
|
+
ok: true,
|
|
105
|
+
error: null // populated on failure
|
|
106
|
+
}</pre>
|
|
107
|
+
|
|
108
|
+
<h3>Use cases</h3>
|
|
109
|
+
<ul>
|
|
110
|
+
<li><b>Debug:</b> wire to a Debug node — see exactly what every Modbus op did.</li>
|
|
111
|
+
<li><b>Alerting:</b> filter <code>ok=false</code> → email/Slack on errors.</li>
|
|
112
|
+
<li><b>Charting:</b> count ops/sec, response-time histograms, per-target latency.</li>
|
|
113
|
+
<li><b>Audit trail:</b> store every op in a database for compliance.</li>
|
|
114
|
+
</ul>
|
|
115
|
+
|
|
116
|
+
<h3>Pricing</h3>
|
|
117
|
+
<p><b>Free</b> — visibility costs nothing. Traffic events themselves don't count toward your daily op limit.</p>
|
|
118
|
+
</script>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModPackQT Traffic — passive Modbus traffic monitor.
|
|
3
|
+
*
|
|
4
|
+
* Subscribes to the config node's traffic event bus and emits one message
|
|
5
|
+
* per Modbus operation (master read/write or slave read/write).
|
|
6
|
+
*
|
|
7
|
+
* Free for everyone — debug visibility costs nothing.
|
|
8
|
+
*/
|
|
9
|
+
module.exports = function (RED) {
|
|
10
|
+
function ModPackQTTrafficNode(config) {
|
|
11
|
+
RED.nodes.createNode(this, config);
|
|
12
|
+
const node = this;
|
|
13
|
+
const server = RED.nodes.getNode(config.server);
|
|
14
|
+
|
|
15
|
+
node.filterDirection = config.filterDirection || 'any'; // any | read | write
|
|
16
|
+
node.filterKind = config.filterKind || 'any'; // any | master | slave
|
|
17
|
+
node.filterFc = config.filterFc || 'any'; // any | 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16
|
|
18
|
+
node.filterTarget = (config.filterTarget || '').trim(); // substring match
|
|
19
|
+
node.format = config.format || 'object'; // object | summary
|
|
20
|
+
node.alsoLog = config.alsoLog === true || config.alsoLog === 'true';
|
|
21
|
+
|
|
22
|
+
let count = 0;
|
|
23
|
+
|
|
24
|
+
if (!server) {
|
|
25
|
+
node.status({ fill: 'red', shape: 'ring', text: 'no config' });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function summarize(evt) {
|
|
30
|
+
const tag = evt.kind === 'slave'
|
|
31
|
+
? `slave ${evt.direction} ${evt.registerType}@${evt.address}×${evt.quantity}`
|
|
32
|
+
: `${evt.direction} FC${evt.fc} ${evt.target} u${evt.unitId} @${evt.address}×${evt.quantity}`;
|
|
33
|
+
const status = evt.ok ? `${evt.durationMs}ms` : `ERR ${evt.error || ''}`;
|
|
34
|
+
return `${tag} · ${status}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function onTraffic(evt) {
|
|
38
|
+
// Filters
|
|
39
|
+
if (node.filterDirection !== 'any' && evt.direction !== node.filterDirection) return;
|
|
40
|
+
if (node.filterKind !== 'any' && evt.kind !== node.filterKind) return;
|
|
41
|
+
if (node.filterFc !== 'any' && String(evt.fc) !== String(node.filterFc)) return;
|
|
42
|
+
if (node.filterTarget && !(evt.target || '').includes(node.filterTarget)) return;
|
|
43
|
+
|
|
44
|
+
count += 1;
|
|
45
|
+
const summary = summarize(evt);
|
|
46
|
+
node.status({
|
|
47
|
+
fill: evt.ok ? 'green' : 'red', shape: 'dot',
|
|
48
|
+
text: `modpackqt · ${count} ops · ${summary.slice(0, 50)}`
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (node.alsoLog) node.log(summary);
|
|
52
|
+
|
|
53
|
+
const msg = (node.format === 'summary')
|
|
54
|
+
? { payload: summary, traffic: evt }
|
|
55
|
+
: { payload: evt };
|
|
56
|
+
msg.topic = `modpackqt/traffic/${evt.kind}/${evt.direction}`;
|
|
57
|
+
node.send(msg);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
server.traffic.on('op', onTraffic);
|
|
61
|
+
node.status({ fill: 'grey', shape: 'ring', text: 'modpackqt · waiting…' });
|
|
62
|
+
|
|
63
|
+
node.on('close', function () {
|
|
64
|
+
try { server.traffic.removeListener('op', onTraffic); } catch (_) {}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
RED.nodes.registerType('modpackqt-traffic', ModPackQTTrafficNode);
|
|
68
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-modbus-modpackqt",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Node-RED nodes
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Node-RED Modbus nodes — embedded Modbus TCP/RTU master + slave server, no extra apps required. By ModPackQT. FC1/FC2/FC3/FC4 reads, FC5/FC6/FC15/FC16 writes, a built-in slave register store, and a free passive traffic monitor for debugging.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node-red",
|
|
7
7
|
"modbus",
|
|
@@ -10,22 +10,39 @@
|
|
|
10
10
|
"modbus-rtu",
|
|
11
11
|
"modbus-master",
|
|
12
12
|
"modbus-slave",
|
|
13
|
+
"modbus-server",
|
|
13
14
|
"industrial",
|
|
14
15
|
"automation",
|
|
15
16
|
"holding-register",
|
|
16
17
|
"coil",
|
|
17
18
|
"iiot",
|
|
19
|
+
"scada",
|
|
18
20
|
"plc"
|
|
19
21
|
],
|
|
20
22
|
"license": "MIT",
|
|
21
23
|
"author": "ModPackQT",
|
|
22
|
-
"homepage": "https://modpackqt.com",
|
|
24
|
+
"homepage": "https://modpackqt.com/nodered",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/modpackqt/node-red-contrib-modbus-modpackqt.git"
|
|
28
|
+
},
|
|
23
29
|
"bugs": {
|
|
24
|
-
"url": "https://
|
|
30
|
+
"url": "https://github.com/modpackqt/node-red-contrib-modbus-modpackqt/issues",
|
|
31
|
+
"email": "support@modpackqt.com"
|
|
25
32
|
},
|
|
26
33
|
"engines": {
|
|
27
34
|
"node": ">=14"
|
|
28
35
|
},
|
|
36
|
+
"files": [
|
|
37
|
+
"nodes/",
|
|
38
|
+
"examples/",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE",
|
|
41
|
+
"CHANGELOG.md",
|
|
42
|
+
"DISCLAIMER.md",
|
|
43
|
+
"SECURITY.md",
|
|
44
|
+
"CONTRIBUTING.md"
|
|
45
|
+
],
|
|
29
46
|
"node-red": {
|
|
30
47
|
"version": ">=2.0.0",
|
|
31
48
|
"nodes": {
|
|
@@ -33,10 +50,11 @@
|
|
|
33
50
|
"modpackqt-master-read": "nodes/modpackqt-master-read.js",
|
|
34
51
|
"modpackqt-master-write": "nodes/modpackqt-master-write.js",
|
|
35
52
|
"modpackqt-slave-read": "nodes/modpackqt-slave-read.js",
|
|
36
|
-
"modpackqt-slave-write": "nodes/modpackqt-slave-write.js"
|
|
53
|
+
"modpackqt-slave-write": "nodes/modpackqt-slave-write.js",
|
|
54
|
+
"modpackqt-traffic": "nodes/modpackqt-traffic.js"
|
|
37
55
|
}
|
|
38
56
|
},
|
|
39
57
|
"dependencies": {
|
|
40
|
-
"
|
|
58
|
+
"modbus-serial": "^8.0.0"
|
|
41
59
|
}
|
|
42
60
|
}
|