Node js เชื่อมต่อ Modbus TCP และอ่าน Holding Register ด้วย lib jsmodbus #v6w47Sjo46–1

Chaleampolpumpotong
3 min readAug 16, 2023

สร้างโปรเจค node js คำสั่ง npm init

ติดตั้ง package jsmodbus คำสั่ง npm install jsmodbus

สร้างไฟล์ main.js

import module ที่จะใช้

const modbus = require("jsmodbus");
const net = require("net");

สร้าง instance ของ ตัว jsmodbus สำหรับการเชื่อมต่อแบบ TCP

const client = new modbus.client.TCP(new net.Socket());

เขียน event handler สำหรับกรณี ที่มี error

ตัว jsmodbus tcp ใช้ net.Socket() พื้นฐานของ node js ใครเคยใช้มันจะจัดการ event แบบเดียวกัน

client.socket.on("error", (error) => {
console.log("error:" + error);
});

เชื่อมต่อ อุปกรณ์ modbus tcp

ผมใช้ Simulator ชื่อ Modbus Slave ไปหาเอาใน google เด้อ ใครมีอุปกรณ์ ก็ต่อของจริงได้เลย

client.socket.connect(
{
host: /*ไอพีของอุปกรณ์*/,
port: /*พอทของอุปกรณ์*/,
},
() => {
/*callback function เมื่อการเชื่อมต่อสำเร็จ*/
}
);
client.socket.connect(
{
host: "127.0.0.1",
port: "502",
},
() => {
console.log("connected:");
}
);

ทีนี้ถ้าเราทดสอบด้วยการ พิมพ์ node main ใน terminal ถ้าไม่ผิดพลาด ก็จะมี “connected:” แสดง

*อย่าลืมเปิดตัว simulator Modbus Slave แล้ว setup ตัว Connection ตามนี้ ก่อนเด้อ กรณีไม่ได้ต่อ อุปกรณ์จริง

การอ่านค่า Holding register ใช้คำสั่ง

.readHoldingRegisters(ตำแหน่งที่จะอ่าน, จำนวนที่จะอ่าน)

client
.readHoldingRegisters(/*ตำแหน่ง*/, /*จำนวนที่จะอ่าน*/)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});

อ่านค่า ตำแหน่ง 0 จำนวน 1

1 ตำแหน่ง ของ modbus จะเก็บได้ 16 bit หรือจะเรียก 1 word คือถ้าอ่านมันเป็น

unsigned integer 16 bit จะได้ 0 ถึง 65,535

 client
.readHoldingRegisters(0, 1)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});

จะอ่านมันได้ ก็ต่อเมื่อเรา เชื่อมต่อสำเร็จ เราก็เอาคำสั่งอ่านค่าไปใส่ไว้ใน callback function ของคำสั่ง connect

client.socket.connect(
{
host: "127.0.0.1",
port: "502",
},
() => {
console.log("connected:");
client
.readHoldingRegisters(0, 1)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
}
);

โค้ดที่ได้


const modbus = require("jsmodbus");
const net = require("net");
const client = new modbus.client.TCP(new net.Socket());
client.socket.on("error", (error) => {
console.log("error:" + error);
});
client.socket.connect(
{
host: "127.0.0.1",
port: "502",
},
() => {
console.log("connected:");
client
.readHoldingRegisters(0, 1)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
}
);

ถ้าผมไป เซ็ต ตัว Simulator Modbus Slave ที่ตำแหน่ง 0 ให้มีค่า 99 เมื่อเรารันด้วย

node main.js มันจะได้ res เป็น object แบบนี้

*ตัว โปรแกรม Modbus Slave มันเป็น integer 16 bit เด้อ ค่ามันจะเป็น

–32,768 ถึง 32,767 ระวังเรื่องนี้ด้วยเด้อ ถ้าค่าที่เราอ่านมันเกิน 16 bit อย่าง ทศนิยม หรือ พวกข้อความ เวลาแปลงถ้าเราไม่รู้วิธีเก็บค่าต้นทาง เวลาแปลงกลับมันอาจจะเพี้ยน กรณีที่บันทึกค่าเป็นอุปกรณ์อื่น เช่น พวก plc ยังไงลอง debug ผลลัพธ์ด้วย console log ดูก่อน

{
metrics: UserRequestMetrics {
createdAt: 2023-08-16T07:20:03.517Z,
startedAt: 2023-08-16T07:20:03.517Z,
receivedAt: 2023-08-16T07:20:03.542Z
},
request: ModbusTCPRequest {
_id: 1,
_protocol: 0,
_length: 6,
_unitId: 1,
_body: ReadHoldingRegistersRequestBody { _fc: 3, _start: 0, _count: 1 }
},
response: ModbusTCPResponse {
_id: 1,
_protocol: 0,
_bodyLength: 5,
_unitId: 1,
_body: ReadHoldingRegistersResponseBody {
_fc: 3,
_byteCount: 2,
_values: [Array],
_bufferLength: 4,
_valuesAsArray: [Array],
_valuesAsBuffer: <Buffer 00 63>
}
}
}

ทีนี้ เราก็สามารถนำค่าไปทำงานต่อได้ โดยค่าที่เราสนใจ คือ

res.response._body._values และ res.response._body._valuesAsArray

อันนี้จะอ่านมาเป็น อาเรย์ของตำแหน่งที่เราอ่าน

res.response._body._valuesAsBuffer

อันนี้จะออกมาเป็น bytes ใช้อันนี้ จะง่าย ถ้าค่ามันต้องมีการแปลง เป็นข้อความ หรือ เลขทศนิยม

client
.readHoldingRegisters(0, 1)
.then((res) => {
console.log(res.response._body._values);
console.log(res.response._body._valuesAsArray);
console.log(res.response._body._valuesAsBuffer);
})
.catch((err) => {
console.log(err);
});

เราก็จะได้ผลลัพท์ แบบนี้ที่ terminal

[ 99 ]
[ 99 ]
<Buffer 00 63>

แถม วิธีแปลง function connect ที่เป็น callback ลักษณะนี้บางทีเราจัดการยากหน่อย เราสามารถแปลง มันเป็น Promise จาก

client.socket.connect(
{
host: "127.0.0.1",
port: "502",
},
() => {
console.log("connected:");
}
);

เป็น

function ConnectPromise(){
return new Promise((resolve,rejects)=>{
client.socket.connect(
{
host: "127.0.0.1",
port: "502",
},
() => {
resolve();
}
);

client.socket.on("error", (error) => {
rejects(error);
});
});
}

ทีนี้ ก็จะสามารถใช้ ท่า Asynchronous จัดการได้

async function ConnectAsync() {
try {
await ConnectPromise();
let res = await client.readHoldingRegisters(0, 1);
console.log(res);
} catch (err) {
console.log(err);
}
}

--

--