node-red-contrib-modbus-rtu 1.1.31 → 1.1.32
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/README.md +59 -19
- package/modbus_rtu/modbus_rtu.html +203 -0
- package/modbus_rtu/modbus_rtu.js +169 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,34 +1,74 @@
|
|
|
1
1
|
# node-red-contrib-modbus-rtu
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Một node mạnh mẽ và linh hoạt để xây dựng gói tin Modbus RTU, tự động tính toán CRC16, và giải mã dữ liệu số thực (Float) trực tiếp trong Node-RED.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A robust Node-RED node for building Modbus RTU frames, automatic CRC16 calculation, and decoding Floating-point data.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
---
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## 🌟 Tính năng nổi bật / Key Features
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **Tự động tính CRC16**: Không cần viết code để tính checksum, node sẽ tự động chèn 2 byte CRC vào cuối Buffer.
|
|
12
|
+
- **Xử lý số thực (Float)**: Hỗ trợ chuyển đổi mảng byte nhận về thành số thực với định dạng **ABCD** hoặc **CDAB** (đặc biệt hữu ích cho các dòng đồng hồ năng lượng như Selec, Elmeasure...).
|
|
13
|
+
- **Cấu hình động (Dynamic)**: Cho phép thay đổi Slave ID, mã hàm, địa chỉ thanh ghi ngay trong quá trình chạy thông qua `msg.payload`.
|
|
14
|
+
- **Kiểm tra gói tin (Check CRC)**: Hỗ trợ xác thực gói tin nhận về từ thiết bị ngoại vi có toàn vẹn hay không.
|
|
15
|
+
- **Hỗ trợ đa dạng mã hàm**: 01, 02, 03, 04, 05, 06, 15, 16.
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
---
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
## 🛠 Cấu hình / Configuration
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
Trong cửa sổ cài đặt node, bạn có các tùy chọn tại mục **Function**:
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
| Function | Mô tả (Description) | Cách dùng (Usage) |
|
|
24
|
+
| :--- | :--- | :--- |
|
|
25
|
+
| **ADD CRC (0)** | Chỉ thêm CRC | Thêm 2 byte CRC16 vào cuối `msg.payload` (Buffer). |
|
|
26
|
+
| **DYNAMIC (-1)** | Cấu hình động | Lấy thông số từ `msg.payload = {id, fn, addr, count}`. |
|
|
27
|
+
| **CHECK CRC (-2)** | Kiểm tra lỗi | Kiểm tra và bóc tách dữ liệu nếu CRC của gói tin nhận về là đúng. |
|
|
28
|
+
| **FLOATs ABCD (-3)** | Chuyển đổi số thực | Chuyển mảng byte nhận về thành mảng số thực định dạng ABCD. |
|
|
29
|
+
| **FLOATs CDAB (-4)** | Chuyển đổi số thực | Chuyển mảng byte nhận về thành mảng số thực định dạng CDAB (Selec Meter). |
|
|
30
|
+
| **Mã hàm (1-16)** | Mã hàm cố định | Xây dựng gói tin dựa trên Slave ID, Address, Count trên giao diện. |
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
---
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
- 1.0.1 .. 1.0.11: fix bug
|
|
34
|
+
## 📖 Ví dụ / Examples
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
### 1. Tạo gói tin Modbus từ giao diện (GUI)
|
|
37
|
+
Cấu hình: `Slave ID: 1`, `Function: 3`, `Address: 0`, `Count: 2`.
|
|
38
|
+
- **Input**: Bất kỳ gói tin nào kích hoạt node.
|
|
39
|
+
- **Output (Buffer)**: `01 03 00 00 00 02 C4 0B`
|
|
33
40
|
|
|
41
|
+
### 2. Cấu hình động (Dynamic Mode)
|
|
42
|
+
Sử dụng một node `function` trước node này:
|
|
43
|
+
```javascript
|
|
44
|
+
msg.payload = {
|
|
45
|
+
id: 2,
|
|
46
|
+
fn: 4,
|
|
47
|
+
addr: 10,
|
|
48
|
+
count: 1
|
|
49
|
+
};
|
|
50
|
+
return msg;
|
|
51
|
+
```
|
|
34
52
|
|
|
53
|
+
### 3. Giải mã dữ liệu đồng hồ Selec (NA111)
|
|
54
|
+
Nối đầu ra của node TCP/Serial vào node này, chọn Function: FLOATs CDAB (-4) và cài đặt Làm tròn (Decimal).
|
|
55
|
+
|
|
56
|
+
Kết quả: msg.payload trả về mảng số thực đã giải mã (Ví dụ: [220.5, 49.9, 0.98]).
|
|
57
|
+
|
|
58
|
+
## 🚀 Cài đặt / Installation
|
|
59
|
+
Chạy lệnh sau trong thư mục dữ liệu Node-RED (thường là ~/.node-red):
|
|
60
|
+
|
|
61
|
+
Bash
|
|
62
|
+
npm install node-red-contrib-modbus-rtu
|
|
63
|
+
|
|
64
|
+
## 👤 Thông tin tác giả / Author
|
|
65
|
+
Tác giả: Do Duy Cop
|
|
66
|
+
|
|
67
|
+
Dự án: S-Connect IoT System
|
|
68
|
+
|
|
69
|
+
GitHub: node-red-contrib-modbus-rtu
|
|
70
|
+
|
|
71
|
+
Email: duycop@gmail.com
|
|
72
|
+
|
|
73
|
+
## 📄 Bản quyền / License
|
|
74
|
+
Dự án được phát hành dưới giấy phép MIT. 2026 © Do Duy Cop.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('modbus_rtu', {
|
|
3
|
+
category: 'function',
|
|
4
|
+
color: '#fff000',
|
|
5
|
+
defaults: {
|
|
6
|
+
ten : { value: ""},
|
|
7
|
+
slave_id: { value: ""},
|
|
8
|
+
fn : { value: "0" },
|
|
9
|
+
addr : { value: "" },
|
|
10
|
+
count : { value: "" },
|
|
11
|
+
lamtron : { value: "3" },
|
|
12
|
+
},
|
|
13
|
+
inputs: 1,
|
|
14
|
+
outputs: 2,
|
|
15
|
+
icon: 'bridge.png',
|
|
16
|
+
label: function() {
|
|
17
|
+
if(this.ten != ""){
|
|
18
|
+
return this.ten;
|
|
19
|
+
}
|
|
20
|
+
if (this.fn == "-1") {
|
|
21
|
+
return "DYNAMIC";
|
|
22
|
+
} else if (this.fn == "-2") {
|
|
23
|
+
return "CHECK CRC";
|
|
24
|
+
}else if (this.fn == "-3") {
|
|
25
|
+
return "FLOATs ABCD";
|
|
26
|
+
}else if (this.fn == "-4") {
|
|
27
|
+
return "FLOATs CDAB";
|
|
28
|
+
}else if (this.fn == "0") {
|
|
29
|
+
return "ADD CRC";
|
|
30
|
+
} else {
|
|
31
|
+
return `ModbusRTU fn=${this.fn}`;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
oneditprepare: function() {
|
|
35
|
+
// Hàm kiểm tra và ẩn hiện
|
|
36
|
+
function updateVisibility() {
|
|
37
|
+
var fnValue = $("#node-input-fn").val();
|
|
38
|
+
if (fnValue === "0") {//CRC
|
|
39
|
+
$(".modbus-fields").hide();
|
|
40
|
+
$(".modbus-dynamic").hide();
|
|
41
|
+
$(".modbus-crc").show(); //show crc only
|
|
42
|
+
$(".modbus-check-crc").hide();
|
|
43
|
+
$(".modbus-float").hide();
|
|
44
|
+
} else if (fnValue == "-1") {
|
|
45
|
+
$(".modbus-fields").hide();
|
|
46
|
+
$(".modbus-dynamic").show(); //show dynamic only
|
|
47
|
+
$(".modbus-crc").hide();
|
|
48
|
+
$(".modbus-check-crc").hide();
|
|
49
|
+
$(".modbus-float").hide();
|
|
50
|
+
} else if (fnValue == "-2") {
|
|
51
|
+
$(".modbus-fields").hide();
|
|
52
|
+
$(".modbus-dynamic").hide();
|
|
53
|
+
$(".modbus-crc").hide();
|
|
54
|
+
$(".modbus-check-crc").show(); //show check crc
|
|
55
|
+
$(".modbus-float").hide();
|
|
56
|
+
} else if (fnValue == "-3" || fnValue == "-4") {
|
|
57
|
+
$(".modbus-fields").hide();
|
|
58
|
+
$(".modbus-dynamic").hide();
|
|
59
|
+
$(".modbus-crc").hide();
|
|
60
|
+
$(".modbus-check-crc").hide();
|
|
61
|
+
$(".modbus-float").show();
|
|
62
|
+
}else {
|
|
63
|
+
$(".modbus-fields").show(); //show gui input fields
|
|
64
|
+
$(".modbus-dynamic").hide();
|
|
65
|
+
$(".modbus-crc").hide();
|
|
66
|
+
$(".modbus-check-crc").hide();
|
|
67
|
+
$(".modbus-float").hide();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Gọi ngay khi mở cửa sổ cấu hình
|
|
72
|
+
updateVisibility();
|
|
73
|
+
|
|
74
|
+
// Lắng nghe sự kiện thay đổi của select
|
|
75
|
+
$("#node-input-fn").on("change", function() {
|
|
76
|
+
updateVisibility();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
</script>
|
|
81
|
+
<script type="text/html" data-template-name="modbus_rtu">
|
|
82
|
+
<div class="form-row">
|
|
83
|
+
<h3>modbus_rtu Build payload msg</h3><hr>
|
|
84
|
+
<div/>
|
|
85
|
+
<div class="form-row">
|
|
86
|
+
<label for="node-input-ten"><i class="fa fa-tag"></i> Name</label>
|
|
87
|
+
<input type="text" id="node-input-ten" value="" placeholder="Custom name">
|
|
88
|
+
</div>
|
|
89
|
+
<hr>
|
|
90
|
+
<div class="form-row">
|
|
91
|
+
<label for="node-input-fn"><i class="fa fa-tag"></i> Function</label>
|
|
92
|
+
<select id="node-input-fn" style="width:70%">
|
|
93
|
+
<option value=0>ADD 2 byte CRC ONLY</option>
|
|
94
|
+
<option value=-2>CHECK CRC == 0</option>
|
|
95
|
+
<option value=-1>DYNAMIC by msg.payload.fn</option>
|
|
96
|
+
<option value=-3>FLOATs ABCD</option>
|
|
97
|
+
<option value=-4>FLOATs CDAB</option>
|
|
98
|
+
<option value=1>01 Read Coils (0x)</option>
|
|
99
|
+
<option value=2>02 Read Discrete Inputs [1x]</option>
|
|
100
|
+
<option value=3 selected>03 Read Holding Registers (4x)</option>
|
|
101
|
+
<option value=4>04 Read Input Registers (3x)</option>
|
|
102
|
+
<option value=5>05 Write Single Coil</option>
|
|
103
|
+
<option value=6>06 Write Single Register</option>
|
|
104
|
+
<option value=15>15 Write Multiple Coils</option>
|
|
105
|
+
<option value=16>16 Write Multiple Registers</option>
|
|
106
|
+
</select>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="modbus-fields">
|
|
109
|
+
<div class="form-row">
|
|
110
|
+
<label for="node-input-slave_id"><i class="fa fa-tag"></i> Slave id</label>
|
|
111
|
+
<input type="text" id="node-input-slave_id" value="1" placeholder="id">
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div class="form-row">
|
|
115
|
+
<label for="node-input-addr"><i class="fa fa-tag"></i> Address</label>
|
|
116
|
+
<input type="text" value="0" id="node-input-addr" placeholder="Address begin">
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<div class="form-row">
|
|
120
|
+
<label for="node-input-count"><i class="fa fa-tag"></i> Count</label>
|
|
121
|
+
<input type="text" value="1" id="node-input-count" placeholder="Quantity">
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="modbus-float">
|
|
125
|
+
<label for="node-input-lamtron"><i class="fa fa-tag"></i> Decimal</label>
|
|
126
|
+
<input type="text" value="3" id="node-input-lamtron" placeholder="Number decimal make round after dot">
|
|
127
|
+
</div>
|
|
128
|
+
<hr>
|
|
129
|
+
<i class="fa fa-bomb"></i> Algorithm
|
|
130
|
+
<pre class="modbus-fields">//Modbus RTU: không phụ thuộc payload đầu vào
|
|
131
|
+
const data = ModbusMsg(id, fn, addr, count);
|
|
132
|
+
msg.payload = add_crc16(data, out_crc);
|
|
133
|
+
msg.crc = out_crc</pre>
|
|
134
|
+
<pre class="modbus-crc">//CRC ONLY:
|
|
135
|
+
//input (pre node): phụ thuộc vào payload của node trước ở dạng Buffer
|
|
136
|
+
//output:
|
|
137
|
+
const data = msg.payload;
|
|
138
|
+
msg.payload = add_crc16(data);</pre>
|
|
139
|
+
<pre class="modbus-check-crc">//CHECK CRC:
|
|
140
|
+
//input: phụ thuộc vào payload của node trước ở dạng Buffer
|
|
141
|
+
//output: msg if CRC==0 else msg.crc=crc
|
|
142
|
+
const data = msg.payload;
|
|
143
|
+
const _payload = add_crc16(data, out_crc);
|
|
144
|
+
msg.crc = out_crc
|
|
145
|
+
if(out_crc==0)
|
|
146
|
+
return [msg, null]; /*output 1 when crc ok*/
|
|
147
|
+
else
|
|
148
|
+
return [null, msg]; /*output 2 when crc error*/</pre>
|
|
149
|
+
<pre class="modbus-dynamic">//DYNAMIC:
|
|
150
|
+
//input (pre node): phụ thuộc vào payload của node trước ở dạng json
|
|
151
|
+
msg.payload = {id:2,fn:3,addr:4,count:5}
|
|
152
|
+
//output:
|
|
153
|
+
const id=msg.payload.id;
|
|
154
|
+
const fn=msg.payload.fn;
|
|
155
|
+
const addr=msg.payload.addr;
|
|
156
|
+
const count=msg.payload.count;
|
|
157
|
+
const data = ModbusMsg(id, fn, addr, count);
|
|
158
|
+
msg.payload = add_crc16(data);</pre>
|
|
159
|
+
<pre class="modbus-float">//FLOAT:
|
|
160
|
+
//input (pre node): msg.payload is data with CRC OK
|
|
161
|
+
//id fn data0 data1... dataN crc1 crc2
|
|
162
|
+
//output: array floats value from byte data0,data1,...,dataN
|
|
163
|
+
//1 float == 4 byte data = Math.round (float, number_decimal)
|
|
164
|
+
</pre>
|
|
165
|
+
<hr>
|
|
166
|
+
Code by Do Duy Cop
|
|
167
|
+
</script>
|
|
168
|
+
|
|
169
|
+
<script type="text/html" data-help-name="modbus_rtu">
|
|
170
|
+
<p>modbus_rtu. Code by Do Duy Cop</p>
|
|
171
|
+
|
|
172
|
+
<h3>Inputs</h3>
|
|
173
|
+
<dl class="message-properties">
|
|
174
|
+
<dt>id<span class="property-type">int</span></dt>
|
|
175
|
+
<dd>required</dd>
|
|
176
|
+
|
|
177
|
+
<dt>fn<span class="property-type">int</span></dt>
|
|
178
|
+
<dd>required</dd>
|
|
179
|
+
|
|
180
|
+
<dt>addr<span class="property-type">int</span></dt>
|
|
181
|
+
<dd>required</dd>
|
|
182
|
+
|
|
183
|
+
<dt>count<span class="property-type">int</span></dt>
|
|
184
|
+
<dd>required</dd>
|
|
185
|
+
</dl>
|
|
186
|
+
|
|
187
|
+
<h3>Outputs</h3>
|
|
188
|
+
<dl class="message-properties">
|
|
189
|
+
<dt>payload <span class="property-type">Buffer</span></dt>
|
|
190
|
+
<dd>Output</dd>
|
|
191
|
+
</dl>
|
|
192
|
+
|
|
193
|
+
<h3>Details</h3>
|
|
194
|
+
<dl class="message-properties">
|
|
195
|
+
<p>fn = 0 : <br>
|
|
196
|
+
msg.payload = msg.payload + 2 byte crc16<hr>
|
|
197
|
+
fn > 0:<br>
|
|
198
|
+
id = 0 then get msg.payload.id<br>
|
|
199
|
+
addr = 0 then get msg.payload.addr<br>
|
|
200
|
+
count = 0 then get msg.payload.count
|
|
201
|
+
</p>
|
|
202
|
+
</dl>
|
|
203
|
+
</script>
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
module.exports = function (RED) {
|
|
2
|
+
function MODBUS_Node(config) {
|
|
3
|
+
RED.nodes.createNode(this, config);
|
|
4
|
+
const node = this;
|
|
5
|
+
|
|
6
|
+
function ModbusMsg(slaveAddress, functionCode, addressRegister, numberRegisters) {
|
|
7
|
+
var payloadBuffer = Buffer.allocUnsafe(6); // Tăng kích thước payloadBuffer lên 6 byte để chứa cả slaveAddress
|
|
8
|
+
payloadBuffer.writeUInt8(slaveAddress, 0); // Ghi slaveAddress vào vị trí đầu tiên của payloadBuffer
|
|
9
|
+
payloadBuffer.writeUInt8(functionCode, 1); // Ghi functionCode vào vị trí thứ hai của payloadBuffer
|
|
10
|
+
payloadBuffer.writeUInt16BE(addressRegister, 2); // Ghi addressRegister vào vị trí thứ ba của payloadBuffer
|
|
11
|
+
payloadBuffer.writeUInt16BE(numberRegisters, 4); // Ghi numberRegisters vào vị trí thứ năm của payloadBuffer
|
|
12
|
+
return payloadBuffer;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function add_crc(payload, out_crc) {
|
|
16
|
+
const talbeAbs = [
|
|
17
|
+
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
|
|
18
|
+
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
|
|
19
|
+
];
|
|
20
|
+
function crc16(buf) {
|
|
21
|
+
let crc = 0xFFFF;
|
|
22
|
+
for (let i = 0; i < buf.length; i++) {
|
|
23
|
+
let ch = buf[i];
|
|
24
|
+
crc = talbeAbs[(ch ^ crc) & 15] ^ (crc >> 4);
|
|
25
|
+
crc = talbeAbs[((ch >> 4) ^ crc) & 15] ^ (crc >> 4);
|
|
26
|
+
}
|
|
27
|
+
return crc;
|
|
28
|
+
}
|
|
29
|
+
var crc = crc16(payload);
|
|
30
|
+
var crcBuffer = Buffer.alloc(2); // Allocate a buffer to hold CRC (2 bytes)
|
|
31
|
+
crcBuffer.writeUInt16LE(crc, 0); // Write CRC value into the buffer (little-endian)
|
|
32
|
+
out_crc.crc = crc;
|
|
33
|
+
// Concatenate payload buffer and CRC buffer
|
|
34
|
+
var newPayload = Buffer.concat([payload, crcBuffer]);
|
|
35
|
+
return newPayload;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function get_float_abcd(array, indexfrom) {
|
|
39
|
+
var A = array[indexfrom + 0];
|
|
40
|
+
var B = array[indexfrom + 1];
|
|
41
|
+
var C = array[indexfrom + 2];
|
|
42
|
+
var D = array[indexfrom + 3];
|
|
43
|
+
var data = [A, B, C, D];
|
|
44
|
+
var buf = new ArrayBuffer(4);
|
|
45
|
+
var view = new DataView(buf);
|
|
46
|
+
data.forEach(function (b, i) {
|
|
47
|
+
view.setUint8(i, b);
|
|
48
|
+
});
|
|
49
|
+
return view.getFloat32(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function get_float_cdab(array, indexfrom) {
|
|
53
|
+
var A = array[indexfrom + 0];
|
|
54
|
+
var B = array[indexfrom + 1];
|
|
55
|
+
var C = array[indexfrom + 2];
|
|
56
|
+
var D = array[indexfrom + 3];
|
|
57
|
+
var data = [C, D, A, B];
|
|
58
|
+
var buf = new ArrayBuffer(4);
|
|
59
|
+
var view = new DataView(buf);
|
|
60
|
+
data.forEach(function (b, i) {
|
|
61
|
+
view.setUint8(i, b);
|
|
62
|
+
});
|
|
63
|
+
return view.getFloat32(0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function get_float(payload, fn, k){
|
|
67
|
+
const n = payload.length - 2;
|
|
68
|
+
var data = [];
|
|
69
|
+
for (var i = 3; i < n; i += 4) {
|
|
70
|
+
var value = 0;
|
|
71
|
+
if(fn==-3)
|
|
72
|
+
value = get_float_abcd(payload, i);
|
|
73
|
+
else if(fn==-4)
|
|
74
|
+
value = get_float_cdab(payload, i);
|
|
75
|
+
value = Math.round(value * k) / k;
|
|
76
|
+
data.push(value);
|
|
77
|
+
}
|
|
78
|
+
return data;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
node.on('input', function (msg) {
|
|
82
|
+
var id, fn, addr, count, data = [], out_crc = { crc: " " };
|
|
83
|
+
try {
|
|
84
|
+
fn = parseInt(config.fn);
|
|
85
|
+
if (fn == 0) { //CRC only
|
|
86
|
+
data = msg.payload;
|
|
87
|
+
msg.payload = add_crc(data, out_crc);
|
|
88
|
+
node.status({ fill: "green", shape: "dot", text: "Add CRC16: 0x" + out_crc.crc.toString(16)});
|
|
89
|
+
node.send(msg);
|
|
90
|
+
return;
|
|
91
|
+
} else if (fn == -2) { //CHECK CRC
|
|
92
|
+
data = msg.payload;
|
|
93
|
+
var _payload = add_crc(data, out_crc);
|
|
94
|
+
msg.crc = out_crc.crc;
|
|
95
|
+
if(out_crc.crc == 0){
|
|
96
|
+
node.status({ fill: "green", shape: "dot", text: `${data.length} bytes: CRC == 0`});
|
|
97
|
+
node.send([msg, null]);
|
|
98
|
+
}else{
|
|
99
|
+
var id=msg.payload[0];
|
|
100
|
+
var fn=msg.payload[1];
|
|
101
|
+
var txt = `id:${id} fn:${fn} CRC:0x${out_crc.crc.toString(16)}`;
|
|
102
|
+
node.status({ fill: "red", shape: "ring", text: txt});
|
|
103
|
+
node.send([null, msg]);
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
} else if (fn == -1) { //dynamic
|
|
107
|
+
fn = parseInt(msg.payload.fn);
|
|
108
|
+
id = parseInt(msg.payload.id);
|
|
109
|
+
addr = parseInt(msg.payload.addr);
|
|
110
|
+
count = parseInt(msg.payload.count);
|
|
111
|
+
} else if (fn == -3 || fn == -4 ) { //float
|
|
112
|
+
const lamtron = parseInt(config.lamtron);
|
|
113
|
+
if(lamtron<0)lamtron=0;
|
|
114
|
+
if(lamtron>9)lamtron=9;
|
|
115
|
+
const Ke=[1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9];
|
|
116
|
+
const k=Ke[lamtron];
|
|
117
|
+
const data = get_float(msg.payload, fn, k);
|
|
118
|
+
msg.payload = data;
|
|
119
|
+
node.send(msg);
|
|
120
|
+
var dem = data.length;
|
|
121
|
+
node.status({ fill: "green", shape: "dot", text: `${dem} floats` });
|
|
122
|
+
return;
|
|
123
|
+
} else if (fn > 0) { // GUI
|
|
124
|
+
id = parseInt(config.slave_id);
|
|
125
|
+
addr = parseInt(config.addr);
|
|
126
|
+
count = parseInt(config.count);
|
|
127
|
+
}
|
|
128
|
+
if (isNaN(fn) || fn<0 || fn>255){
|
|
129
|
+
node.status({ fill: "red", shape: "ring", text: 'Error: fn error' });
|
|
130
|
+
node.warn('Error: fn error or NaN');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (isNaN(id) || id < 1 || id > 255) {
|
|
134
|
+
node.status({ fill: "red", shape: "ring", text: 'Error: id not in 1..255' });
|
|
135
|
+
node.warn('Error: id not in 1..255 or NaN');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (isNaN(addr) || addr < 0) {
|
|
140
|
+
node.status({ fill: "red", shape: "ring", text: "Error: addr < 0" });
|
|
141
|
+
node.warn('Error: addr < 0 or NaN');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (isNaN(count) || count < 1) {
|
|
145
|
+
node.status({ fill: "red", shape: "ring", text: "Error: count < 1" });
|
|
146
|
+
node.warn('Error: count < 1 or NaN');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
data = ModbusMsg(id, fn, addr, count);
|
|
150
|
+
var out_crc = { crc: " " };
|
|
151
|
+
msg.payload = add_crc(data, out_crc);
|
|
152
|
+
msg.crc = out_crc.crc;
|
|
153
|
+
node.status({ fill: "green", shape: "dot", text: `ModbusRTU(${id},${fn},${addr},${count})` });
|
|
154
|
+
node.send(msg);
|
|
155
|
+
} catch (e) {
|
|
156
|
+
var err = e.message;
|
|
157
|
+
if (err == 'The "list[0]" argument must be an instance of Buffer or Uint8Array. Received an instance of Object') {
|
|
158
|
+
err = 'pre node must be format: msg.payload = {id: 2, fn:3, addr: 4, count: 5}';
|
|
159
|
+
node.status({ fill: "red", shape: "ring", text: "Error format" });
|
|
160
|
+
} else {
|
|
161
|
+
node.status({ fill: "red", shape: "ring", text: "Error" });
|
|
162
|
+
}
|
|
163
|
+
node.warn(err);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
RED.nodes.registerType("modbus_rtu", MODBUS_Node, {});
|
|
169
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-modbus-rtu",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.32",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Node-RED function build content modbus_rtu - Code by DoDuyCop",
|
|
6
6
|
"author": "duycop",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"modbus_rtu"
|
|
20
20
|
],
|
|
21
21
|
"files": [
|
|
22
|
-
"examples"
|
|
22
|
+
"examples","modbus_rtu"
|
|
23
23
|
],
|
|
24
24
|
"directories": {
|
|
25
25
|
"example": "examples"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"node-red": {
|
|
31
31
|
"version": ">=4.1.0",
|
|
32
32
|
"nodes": {
|
|
33
|
-
"modbus_rtu": "modbus_rtu.js"
|
|
33
|
+
"modbus_rtu": "modbus_rtu/modbus_rtu.js"
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
}
|