npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cy-plugin-modbus

v2.0.0

Published

modbus 插件

Readme

cy-plugin-modbus

浏览器端 Modbus RTU 串口通信插件,基于 Web Serial API

npm

特性

  • 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_UNSUPPORTEDMODBUS_PERMISSION_DENIEDMODBUS_OPEN_FAILEDMODBUS_NOT_CONNECTEDMODBUS_SEND_FAILEDMODBUS_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-queue
import { 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