@csllc/modbus-types
v2.3.0
Published
Typescript definitions for MODBUS
Downloads
383
Keywords
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-typesOverview
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 aConnection, handles framing and CRC.RtuTransportimplements 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 ofTransactions against aTransport, enforces concurrency limits, handles retries, exception-based retries, and repeatable (polling) transactions.Slave— Listens on aTransportand responds to incoming requests.Functions— PairedRequest/Responseclasses for each MODBUS function code.ModbusResponse— Abstract base class for all response types. Useful for typing event callbacks.
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): TransactionTransactionOptions
| 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 bytescreateResponse(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
}