cy-plugin-modbus
v2.0.0
Published
modbus 插件
Readme
cy-plugin-modbus
浏览器端 Modbus RTU 串口通信插件,基于 Web Serial API。
特性
- Modbus RTU:读线圈 / 离散输入 / 保持寄存器 / 输入寄存器,写单/多线圈与寄存器
- Web Serial:浏览器串口连接、收发、超时可配置
- 统一错误:
ModbusError+onFail回调约定清晰
安装
npm install cy-plugin-modbus运行环境需支持 Web Serial API(推荐 Chromium 系浏览器,且需 HTTPS 或 localhost)。
快速开始
import { CySerialPort, EnumModbusOptionType, ModbusError } from 'cy-plugin-modbus';
import type { IModbusErrorInfo } from 'cy-plugin-modbus';
const port = new CySerialPort({
debug: true,
timeout: 1000, // 默认通信超时(ms),默认 800
onConnect: () => console.log('串口已连接'),
// connect / send 失败:先 onFail,再 throw ModbusError
onFail: (err: IModbusErrorInfo) => {
console.error(err.code, err.message);
}
});
try {
await port.connect({
baudRate: 9600,
parity: 'odd' // 'none' | 'even' | 'odd'
});
const result = await port.send({
slave: 1,
function_code: EnumModbusOptionType.READ_HOLDING_REGISTERS,
starting_address: 0,
quantity_of_x: 10,
output_value: []
});
console.log(result); // number[]
} catch (error) {
if (error instanceof ModbusError) {
console.error(error.code, error.message);
}
}CySerialPort
初始化
import { CySerialPort } from 'cy-plugin-modbus';
const port = new CySerialPort({
debug: false,
timeout: 800,
onConnect: (data) => {},
onFail: (err) => {}
});| 选项 | 类型 | 默认 | 说明 |
| ----------- | ----------------------------------- | ------- | -------------------------------------------------------------------- |
| debug | boolean | false | 是否打印调试日志 |
| timeout | number | 800 | 默认通信超时(ms) |
| onConnect | (data: unknown) => void | - | 连接成功回调 |
| onFail | (error: IModbusErrorInfo) => void | - | 失败回调;connect / send 会先回调再抛出;disconnect 清理失败仅回调 |
连接 / 断开
await port.connect({
baudRate: 9600, // 必填
parity: 'odd', // 必填:'none' | 'even' | 'odd'
dataBits: 8, // 可选:7 | 8
stopBits: 1, // 可选:1 | 2
bufferSize: 255, // 可选
flowControl: 'none' // 可选:'none' | 'hardware' | 'software'
});
await port.disconnect();
// 带错误信息断开:会触发 onFail,不抛出
await port.disconnect(new Error('device lost'));发送
import { EnumModbusOptionType, ModbusError } from 'cy-plugin-modbus';
try {
const result = await port.send(
{
slave: 1,
function_code: EnumModbusOptionType.READ_HOLDING_REGISTERS,
starting_address: 0,
quantity_of_x: 10,
output_value: []
},
{ timeout: 1500 } // 可选:覆盖本次超时
);
console.log(result); // number[]
} catch (error) {
if (error instanceof ModbusError) {
// onFail 已触发,这里做流程控制
}
}| API | 说明 |
| ----------------------- | ------------------------------------------------- |
| send(param, options?) | 发送请求并解析响应;未连接抛 MODBUS_NOT_CONNECTED |
| timeout | 当前默认超时(getter) |
| setTimeout(ms) | 修改默认超时 |
Format 辅助方法
生成 ICySerialPortSendDataFormat,再交给 send:
// 读
await port.send(
port.readCoilsFormat({ slave: 1, starting_address: 0, quantity_of_x: 8 })
);
await port.send(
port.readDiscreteInputsFormat({ slave: 1, starting_address: 0, quantity_of_x: 8 })
);
await port.send(
port.readHoldingRegistersFormat({ slave: 1, starting_address: 0, quantity_of_x: 10 })
);
await port.send(
port.readInputRegistersFormat({ slave: 1, starting_address: 0, quantity_of_x: 10 })
);
// 写
await port.send(
port.writeSingleCoilFormat({
slave: 1,
starting_address: 0,
quantity_of_x: 1,
output_value: [1]
})
);
await port.send(
port.writeSingleRegisterFormat({
slave: 1,
starting_address: 0,
quantity_of_x: 1,
output_value: [100]
})
);
await port.send(
port.writeMultipleCoilsFormat({
slave: 1,
starting_address: 0,
quantity_of_x: 3,
output_value: [1, 0, 1]
})
);
await port.send(
port.writeMultipleRegistersFormat({
slave: 1,
starting_address: 0,
quantity_of_x: 2,
output_value: [1, 2]
})
);
// 功能码文案
port.getFunctionCodeText(EnumModbusOptionType.READ_HOLDING_REGISTERS); // '读保持寄存器'错误约定
| 场景 | 行为 |
| --------------------- | ----------------------------------------------------------- |
| connect / send | 先 onFail(IModbusErrorInfo),再 throw ModbusError |
| disconnect 清理失败 | 仅 onFail,不抛出 |
| 已是 ModbusError | catch 中直接 rethrow,避免重复回调 |
常用错误码:MODBUS_UNSUPPORTED、MODBUS_PERMISSION_DENIED、MODBUS_OPEN_FAILED、MODBUS_NOT_CONNECTED、MODBUS_SEND_FAILED、MODBUS_TIMEOUT_ERROR 等。
import { ModbusError, isModbusError } from 'cy-plugin-modbus';
if (isModbusError(error)) {
console.error(error.code, error.message, error.detail);
}示例:用队列串行发送 Modbus(可选)
串口同一时刻只宜处理一帧请求。若业务侧会并发触发读写,可自行引入串行队列(例如 cy-plugin-queue)调度 port.send。
说明:
cy-plugin-modbus不依赖、不导出 任何队列实现;以下仅为推荐用法示例。
npm install cy-plugin-queueimport { CySerialPort, EnumModbusOptionType, ModbusError } from 'cy-plugin-modbus';
import Queue from 'cy-plugin-queue';
const port = new CySerialPort({
timeout: 1000,
onFail: (err) => console.error('[modbus]', err.code, err.message)
});
const queue = new Queue({
debug: true,
retryCount: 1, // 额外重试次数(不含首次)
timeout: 3000, // 任务超时(ms);未设置则不限制
onError: (err, extra) => console.error('[queue]', err, extra)
});
await port.connect({ baudRate: 9600, parity: 'odd' });
// 读保持寄存器
queue.push({
id: 'read-holding',
extraData: { op: 'read' },
taskParams: port.readHoldingRegistersFormat({
slave: 1,
starting_address: 0,
quantity_of_x: 10
}),
task: async (param) => port.send(param),
onSuccess: (res, extra) => console.log('读成功', res, extra)
});
// 写单个寄存器(排队,等上一个结束后执行)
queue.push({
id: 'write-register',
taskParams: port.writeSingleRegisterFormat({
slave: 1,
starting_address: 0,
quantity_of_x: 1,
output_value: [100]
}),
task: async (param) => port.send(param),
onSuccess: (res) => console.log('写成功', res),
onError: (err) => {
if (err instanceof ModbusError) {
console.error(err.code, err.message);
}
}
});队列的重试、超时、中断(AbortSignal)、clear / abort 等能力,以所选队列库文档为准。
导出一览
import {
CySerialPort,
EnumModbusOptionType,
ModbusError,
isModbusError
} from 'cy-plugin-modbus';
import type {
ICySerialPort,
ICySerialPortSendDataFormat,
ICySerialPortSendOptions,
ISerialOptions,
IReadDataFormat,
IWriteDataFormat,
IModbusErrorInfo,
TModbusErrorCode
} from 'cy-plugin-modbus';
IReadDateFormat/IWriteDateFormat为旧拼写别名,已废弃,请使用IReadDataFormat/IWriteDataFormat。
License
MIT
