基于纯JavaScript实现的MODBUS-RTU(串口和TCP) modbus-serial

modbus-serial

如果你需要使用JavaScript来操作一台RS458的设备,那么你一定不能错过这个库 modbus-serial

安装和使用

bash 复制代码
npm install modbus-serial

支持的功能码

功能码 函数
FC1 读取读线圈寄存器 readCoils(coil, len)
FC2 读离散输入寄存器 readDiscreteInputs(addr, arg)
FC3 读保持寄存器 readHoldingRegisters(addr, len)
FC4 读输入寄存器 readInputRegisters(addr, len)
FC5 写单个线圈寄存器 writeCoil(coil, binary)
FC6 写单个保持寄存器 writeRegister(addr, value)
FC15 写多个线圈寄存器 writeCoils(addr, valueAry)
FC16 写多个保持寄存器 writeRegisters(addr, valueAry)
FC43/14 读保持寄存器 readDeviceIdentification(id, obj)

客户端串行:

  • modbus-RTU (SerialPort):通过串行线路,需要node serialport。

  • modbus-RTU (RTUBufferedPort):通过缓冲串行线路,需要node serialport。

  • modbus-ASCII (AsciiPort):通过串行线路,需要node serialport。

客户端TCP:

  • modbus-TCP (TcpPort):通过TCP/IP线路。

  • modbus-RTU (UdpPort):通过C701服务器,商业UDP到串行桥。

  • modbus-RTU (TcpRTUBufferedPort):通过TCP/IP线路,TCP/IP串行RTU缓冲设备。

  • modbus-RTU (TelnetPort):通过Telnet服务器,TCP/IP串行桥。

服务器

  • modbus-TCP (ServerTCP):通过TCP/IP线路。

示例

读取和写入

js 复制代码
// create an empty modbus client
const ModbusRTU = require("modbus-serial");
const client = new ModbusRTU();

// open connection to a serial port
client.connectRTUBuffered("/dev/ttyUSB0", { baudRate: 9600 }, write);

function write() {
    client.setID(1);

    // write the values 0, 0xffff to registers starting at address 5
    // on device number 1.
    client.writeRegisters(5, [0 , 0xffff])
        .then(read);
}

function read() {
    // read the 2 registers starting at address 5
    // on device number 1.
    client.readHoldingRegisters(5, 2)
        .then(console.log);
}

读取多个从站

js 复制代码
const ModbusRTU = require("modbus-serial");
// create an empty modbus client
const client = new ModbusRTU();
// open connection to a serial port
client.connectRTUBuffered("/dev/ttyS0", { baudRate: 9600 });
// set timeout, if slave did not reply back
client.setTimeout(500);

// list of meter's id
const metersIdList = [10, 11, 12, 13, 14];

const getMetersValue = async (meters) => {
    try{
        // get value of all meters
        for(let meter of meters) {
            // output value to console
            console.log(await getMeterValue(meter));
            // wait 100ms before get another device
            await sleep(100);
	}
    } catch(e){
        // if error, handle them here (it should not)
        console.log(e)
    } finally {
        // after get all data from slave, repeat it again
        setImmediate(() => {
            getMetersValue(metersIdList);
        })
    }
}

const getMeterValue = async (id) => {
    try {
        // set ID of slave
        await client.setID(id);
        // read the 1 registers starting at address 0 (first register)
        let val =  await client.readInputRegisters(0, 1);
        // return the value
        return val.data[0];
    } catch(e){
        // if error return -1
        return -1
    }
}

const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));


// start get value
getMetersValue(metersIdList);

ModbusTCP 服务

js 复制代码
// create an empty modbus client
const ModbusRTU = require("modbus-serial");
const vector = {
    getInputRegister: function(addr, unitID) {
        // Synchronous handling
        return addr;
    },
    getHoldingRegister: function(addr, unitID, callback) {
        // Asynchronous handling (with callback)
        setTimeout(function() {
            // callback = function(err, value)
            callback(null, addr + 8000);
        }, 10);
    },
    getCoil: function(addr, unitID) {
        // Asynchronous handling (with Promises, async/await supported)
        return new Promise(function(resolve) {
            setTimeout(function() {
                resolve((addr % 2) === 0);
            }, 10);
        });
    },
    setRegister: function(addr, value, unitID) {
        // Asynchronous handling supported also here
        console.log("set register", addr, value, unitID);
        return;
    },
    setCoil: function(addr, value, unitID) {
        // Asynchronous handling supported also here
        console.log("set coil", addr, value, unitID);
        return;
    },
    readDeviceIdentification: function(addr) {
        return {
            0x00: "MyVendorName",
            0x01: "MyProductCode",
            0x02: "MyMajorMinorRevision",
            0x05: "MyModelName",
            0x97: "MyExtendedObject1",
            0xAB: "MyExtendedObject2"
        };
    }
};

// set the server to answer for modbus requests
console.log("ModbusTCP listening on modbus://0.0.0.0:8502");
const serverTCP = new ModbusRTU.ServerTCP(vector, { host: "0.0.0.0", port: 8502, debug: true, unitID: 1 });

serverTCP.on("socketError", function(err){
    // Handle socket error if needed, can be ignored
    console.error(err);
});

市面上有非常多的设备时 RS485,如果你之前是前端,并且想接触硬件,就学习一下它吧。

相关推荐
To_OC5 小时前
LC 51 N 皇后:我以为难的是回溯,结果栽在了对角线下标
javascript·算法·leetcode
Scott9999HH5 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
AimerMilet5 小时前
物联网卡流量池是什么意思?企业用划算吗?
物联网
码智社6 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海6 小时前
python 列表、元组、集合和字典
开发语言·python
小林ixn6 小时前
从零到一理解 React 父子组件通信:手写一个 Todo 应用带你彻底搞懂单向数据流
前端·javascript·react.js
萧瑟余晖7 小时前
JDK 26 新特性详解
java·开发语言
Xxtaoaooo7 小时前
DolphinDB 物联网数据平台全景:一份从架构到落地的实践地图
物联网·系统架构·时序数据库·数据库架构·dolphindb
马优晨7 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
窝子面9 小时前
手搓最简前后端协作-node
javascript·数据库