@csllc/modbus-types
v2.0.0
Published
Typescript definitions for MODBUS
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.
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
}