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

@csllc/modbus-types

v2.0.0

Published

Typescript definitions for MODBUS

Readme

@csllc/modbus-types

Core TypeScript library providing the full MODBUS protocol stack: connection abstraction, RTU transport framing, transaction management, master/slave roles, and typed request/response classes for every supported function code.

Installation

npm install @csllc/modbus-types

Overview

The library is organized in layers from bottom to top:

  • Connection — EventEmitter base class representing a physical transport medium. Subclass it to add a new hardware type.
  • Transport / RtuTransport — Wraps a Connection, handles framing and CRC. RtuTransport implements MODBUS RTU encoding with a CRC-16 checksum and detects end-of-frame by a configurable inter-character silence timeout (~10 ms by default).
  • Transaction — Tracks a single request/response cycle including timeout, retries, and interval-based polling.
  • Master — Manages a queue of Transactions against a Transport, enforces concurrency limits, handles retries, exception-based retries, and repeatable (polling) transactions.
  • Slave — Listens on a Transport and responds to incoming requests.
  • Functions — Paired Request/Response classes for each MODBUS function code.

The public factory functions createMaster() and createSlave() are the recommended entry points. Currently only the rtu transport type is wired up in the factories; direct construction of RtuTransport is also supported.

Usage

Creating a Master (event-based)

import { createMaster } from '@csllc/modbus-types';

// Provide a Connection subclass for your hardware (e.g. SerialConnection from
// @csllc/mb-conn-node-serial)
const connection = new MyConnection();

const master = createMaster({
  transport: { type: 'rtu', connection },
  defaultUnit: 1,
  defaultTimeout: 200,
  defaultMaxRetries: 2,
  maxConcurrentRequests: 1,
});

await connection.open();

// Event-based: listen to the Transaction
const transaction = master.readHoldingRegisters(0x0000, 10);
transaction.on('response', (response) => {
  console.log('registers:', response);
});
transaction.on('error', (err) => {
  console.error('error:', err);
});

Creating a Master (Promise-based)

import { createMaster, Functions } from '@csllc/modbus-types';

const master = createMaster({ transport: { type: 'rtu', connection } });
await connection.open();

const response = await master.requestAsync(
  new Functions.ReadHoldingRegistersRequest({ address: 0, quantity: 4 })
);
console.log('response:', response);

Polling (repeatable transactions)

// Re-executes every 1000 ms until cancelled
const transaction = master.readHoldingRegisters(0x0000, 4, { interval: 1000 });
transaction.on('response', (response) => { /* handle */ });

// Later, stop polling:
transaction.cancel();

Creating a Slave

import { createSlave } from '@csllc/modbus-types';

const slave = createSlave({
  transport: { type: 'rtu', connection },
  unit: 1,
});

slave.on('connected', () => console.log('slave connected'));

Using RtuTransport directly

import { RtuTransport } from '@csllc/modbus-types';

const transport = new RtuTransport({ connection, eofTimeout: 15 });

API Reference

createMaster(options: CreateMasterOptions): Master

Factory function that creates a Master instance.

CreateMasterOptions

| Property | Type | Default | Description | |---|---|---|---| | transport | { type: TransportType; connection: Connection } or Transport | required | The transport to use. Set type: 'rtu' for MODBUS RTU. | | suppressTransactionErrors | boolean | false | When true, suppresses unhandled error events on transactions. | | retryOnException | boolean \| number[] | true | Retry on exception responses. Pass an array of exception codes to only retry those. | | maxConcurrentRequests | number | 1 | Number of in-flight requests allowed simultaneously. | | defaultUnit | number | 0 | Default slave unit ID. | | defaultMaxRetries | number | 3 | Default retry count per transaction. | | defaultTimeout | number | 100 | Default response timeout in milliseconds. |


createSlave(options: CreateSlaveOptions): Slave

Factory function that creates a Slave instance.

CreateSlaveOptions

| Property | Type | Description | |---|---|---| | transport | { type: TransportType; connection: Connection } or Transport | The transport to use. | | unit | number | The slave unit ID. The slave ignores PDUs addressed to other units. |


class Master extends EventEmitter

Manages transaction queuing and execution against a transport.

Constructor

new Master(options: MasterOptions)

MasterOptions has the same fields as CreateMasterOptions except transport must be a Transport instance (not the shorthand object).

Properties

| Property | Type | Description | |---|---|---| | transport | Transport \| null | The active transport. | | connection | Connection \| null | The underlying connection. | | connected | boolean | Whether the connection is currently open. |

Methods

| Method | Returns | Description | |---|---|---| | execute(options) | Transaction | Enqueue a transaction directly. | | request(request, options?) | Transaction | Build and enqueue a transaction from a ModbusRequest. | | requestAsync(request, options?) | Promise<ModbusResponse> | Promise-based version of request(). | | readCoils(address, quantity, options?) | Transaction | FC 0x01 — Read coils. | | readDiscreteInputs(address, quantity, options?) | Transaction | FC 0x02 — Read discrete inputs. | | readHoldingRegisters(address, quantity, options?) | Transaction | FC 0x03 — Read holding registers. | | readInputRegisters(address, quantity, options?) | Transaction | FC 0x04 — Read input registers. | | writeSingleCoil(address, state, options?) | Transaction | FC 0x05 — Write single coil. | | writeMultipleRegisters(address, values, options?) | Transaction | FC 0x10 — Write multiple registers. | | reportSlaveId(options?) | Transaction | FC 0x11 — Report slave ID. | | readFifo8(id, max?, options?) | Transaction | Read FIFO (8-bit). | | writeFifo8(id, values, options?) | Transaction | Write FIFO (8-bit). | | readObject(id, options?) | Transaction | Read object by ID. | | writeObject(id, values, options?) | Transaction | Write object by ID. | | readMemory(address, count, options?) | Transaction | Read raw memory bytes. | | writeMemory(address, values, options?) | Transaction | Write raw memory bytes. | | writeMemoryVerify(address, values, options?) | Transaction | Write memory with readback verify. | | command(id, values?, options?) | Transaction | Send a command (FC 0x47). | | sendGeneric(func, values?, options?) | Transaction | Send a generic function code. | | isConnected() | boolean | Returns true if the underlying connection is open. | | getTransport() | Transport \| null | Returns the transport. | | getConnection() | Connection \| null | Returns the connection. | | destroy() | void | Tears down transport and cancels all queued transactions. |

Events

| Event | Args | Description | |---|---|---| | connected | connectionCount: number | Emitted when the connection opens. | | disconnected | — | Emitted when the connection closes (once per open/close cycle). | | error | err: Error | Re-emitted from the underlying connection. |


class Slave extends EventEmitter

Listens on a transport for incoming requests targeting a configured unit ID.

Constructor

new Slave(options: SlaveOptions)

SlaveOptions

| Property | Type | Description | |---|---|---| | transport | Transport | The transport to listen on. | | unit | number | The unit ID this slave responds to. |

Events

| Event | Args | Description | |---|---|---| | connected | connectionCount: number | Emitted when the connection opens. | | disconnected | — | Emitted when the connection closes. | | error | err: Error | Re-emitted from the connection. |


class Transaction extends EventEmitter

Tracks a single request/response cycle.

Static factory

Transaction.fromOptions(options: TransactionOptions): Transaction

TransactionOptions

| Property | Type | Description | |---|---|---| | request | ModbusRequest | The request to send. | | unit | number | Slave unit ID. | | timeout | number | Response timeout in ms. | | maxRetries | number | Maximum retry count. | | interval | number | Polling interval in ms (-1 means not repeatable). | | onResponse | (response) => void | Shorthand response listener. | | onError | (error) => void | Shorthand error listener. | | onComplete | (err, response) => void | Shorthand complete listener. | | onDone | () => void | Shorthand done listener. | | onCancel | () => void | Shorthand cancel listener. |

Methods

| Method | Returns | Description | |---|---|---| | cancel() | void | Cancels the transaction. | | isCancelled() | boolean | Returns true if cancelled. | | isRepeatable() | boolean | Returns true if interval >= 0. | | shouldRetry() | boolean | Returns true if failures count is within retry limit. | | getRequest() | ModbusRequest | Returns the request object. | | getUnit() | number | Returns the target unit ID. | | getTimeout() | number | Returns the timeout in ms. | | getMaxRetries() | number | Returns the retry limit. | | getInterval() | number | Returns the polling interval. | | destroy() | void | Clears all listeners and pending timers. |

Events

| Event | Args | Description | |---|---|---| | response | response: ModbusResponse | Emitted with a successful (non-exception) response. | | complete | err: Error \| null, response: ModbusResponse \| null | Emitted after each attempt (success or failure). | | error | err: Error | Emitted on timeout or transport error. | | timeout | — | Emitted when the response timeout expires. | | done | err, response | Emitted when the transaction is permanently finished (no more retries). | | cancel | — | Emitted when cancel() is called. |


class Connection extends EventEmitter

Abstract base class for physical transport media. Subclass this to implement a new connection type.

Methods (override in subclasses)

| Method | Signature | Description | |---|---|---| | open() | async open(): Promise<void> | Open the connection. | | close() | async close(): Promise<void> | Close the connection. | | write(data) | async write(data: ArrayBuffer): Promise<boolean> | Write raw bytes. | | isOpen() | isOpen(): boolean | Return whether the connection is currently open. | | destroy() | async destroy(): Promise<void> | Clean up the connection. | | drain() | async drain(): Promise<void> | Wait for pending writes to flush. |

Events (emit from subclasses)

| Event | Args | Description | |---|---|---| | open | — | Connection is now open. | | close | — | Connection has closed. | | data | data: ArrayBuffer | Bytes received. | | error | err: Error | An error occurred. |


class Transport extends EventEmitter

Abstract base class for transports. Subclass to implement a new framing layer.

Methods

| Method | Description | |---|---| | getConnection() | Returns the associated Connection. | | sendRequest(transaction) | Initiates a transaction (override in subclasses). | | destroy() | Tears down the transport. |


class RtuTransport extends Transport

Implements MODBUS RTU framing with CRC-16. Frames outbound PDUs with unit ID and checksum, accumulates inbound bytes, and triggers frame parsing after an inter-character silence timeout.

Constructor

new RtuTransport(options: RtuTransportOptions)

RtuTransportOptions

| Property | Type | Default | Description | |---|---|---|---| | connection | Connection | required | The physical connection. | | eofTimeout | number | 10 | Silence period in ms that marks end-of-frame. |


Functions namespace

All request and response classes are exported under the Functions namespace and accessible as named exports.

Request/Response pairs:

| Request | Response | FC | Description | |---|---|---|---| | ReadCoilsRequest | ReadCoilsResponse | 0x01 | Read coils | | ReadDiscreteInputsRequest | ReadDiscreteInputsResponse | 0x02 | Read discrete inputs | | ReadHoldingRegistersRequest | ReadHoldingRegistersResponse | 0x03 | Read holding registers | | ReadInputRegistersRequest | ReadInputRegistersResponse | 0x04 | Read input registers | | WriteSingleCoilRequest | WriteSingleCoilResponse | 0x05 | Write single coil | | WriteMultipleRegistersRequest | WriteMultipleRegistersResponse | 0x10 | Write multiple registers | | ReportSlaveIdRequest | ReportSlaveIdResponse | 0x11 | Report slave ID | | ReadFifo8Request | ReadFifo8Response | — | Read FIFO (8-bit) | | WriteFifo8Request | WriteFifo8Response | — | Write FIFO (8-bit) | | ReadObjectRequest | ReadObjectResponse | 0x43 | Read object by ID | | WriteObjectRequest | WriteObjectResponse | 0x44 | Write object by ID | | ReadMemoryRequest | ReadMemoryResponse | 0x45 | Read raw memory | | WriteMemoryRequest | WriteMemoryResponse | 0x46 | Write raw memory | | WriteMemoryVerifyRequest | WriteMemoryVerifyResponse | 0x64 | Write memory with verify | | CommandRequest | CommandResponse | 0x47 | Command | | GenericRequest | GenericResponse | any | Arbitrary function code | | ExceptionResponse | — | — | MODBUS exception response |

All Request classes implement:

  • toBuffer(): ArrayBuffer — serialize to PDU bytes
  • createResponse(buffer: ArrayBuffer): ModbusResponse — deserialize a response PDU

Enums and Types

FunctionCode

enum FunctionCode {
  Command = 0x47
}

ModbusException

enum ModbusException {
  IllegalFunction    = 0x01,
  IllegalDataAddress = 0x02,
  IllegalDataValue   = 0x03,
  SlaveFailure       = 0x04,
  Acknowledge        = 0x05,
  SlaveBusy          = 0x06,
  Nak                = 0x07,
  MemoryParityError  = 0x08,
  GatewayNoPath      = 0x0A,
  GatewayNoResponse  = 0x0B,
  VerifyFail         = 0x80
}

TransportType (string union)

type TransportType = 'ip' | 'rtu' | 'socketcand' | 'j1939' | 'CS1179' | 'ascii' | 'tunnel';

Currently only 'rtu' is implemented in createMaster / createSlave.

ConnectionInfo

interface ConnectionInfo {
  id: string;    // unique identifier for this connection
  type: string;  // connection type string
}