modbus-rs-wasm 0.13.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Browser-native WebAssembly bindings for [modbus-rs](https://github.com/Raghava-Ch/modbus-rs), enabling Modbus TCP (via WebSockets) and Modbus RTU/ASCII (via Web Serial) directly in the browser.
4
4
 
5
- > **Note:** If you are building a Node.js backend application, use the native [`modbus-rs`](https://www.npmjs.com/package/modbus-rs) package instead.
5
+ > **Note:** This package is designed for browser-native environments (using WebSockets and Web Serial). If you are building a Node.js backend application, use the native [`modbus-rs`](https://www.npmjs.com/package/modbus-rs) package instead. Running this package in pure Node.js requires `--experimental-wasm-modules` and is not officially supported.
6
6
 
7
7
  ## Installation
8
8
 
@@ -10,29 +10,49 @@ Browser-native WebAssembly bindings for [modbus-rs](https://github.com/Raghava-C
10
10
  npm install modbus-rs-wasm
11
11
  ```
12
12
 
13
- ## Quick Start (Modbus TCP via WebSocket Gateway)
13
+ ## Integration & Frameworks (Vite, Svelte, React, etc.)
14
14
 
15
- First, run the gateway [modbus-gateway](https://github.com/Raghava-Ch/modbus-gateway).
15
+ No custom resolver aliases or configuration workarounds are required starting in `v0.14.0`. Standard package entry points are resolved automatically based on your builder/bundler targets.
16
+
17
+ ### Web (Direct / HTML / Vanilla JS)
18
+ When loading the package in browser environments without a bundler, import the web entry point and await the initialization promise:
16
19
 
17
20
  ```javascript
18
- import { WasmModbusClient } from 'modbus-rs-wasm';
21
+ import init, { WasmTcpTransport } from 'modbus-rs-wasm/dist/web/modbus-rs.js';
19
22
 
20
- async function readRegisters() {
21
- // Connect to a WebSocket proxy that forwards to a Modbus TCP device
22
- // (e.g. ws_url, unit_id, response_timeout_ms, retries, tick_interval_ms)
23
- const client = new WasmModbusClient('ws://localhost:8502', 1, 5000, 3, 20);
23
+ await init();
24
+ const transport = new WasmTcpTransport('ws://localhost:8502', {
25
+ responseTimeoutMs: 5000,
26
+ retryAttempts: 3,
27
+ tickIntervalMs: 20
28
+ });
29
+ const client = transport.create_client({ unitId: 1 });
30
+ ```
24
31
 
25
- try {
26
- // Read 10 holding registers starting at address 0
27
- const registers = await client.read_holding_registers(0, 10);
28
- console.log('Holding registers:', registers); // Uint16Array
29
- } catch (error) {
30
- console.error('Failed to read registers:', error);
31
- }
32
- }
32
+ ### Bundlers & Frameworks (Vite, SvelteKit, Next.js, etc.)
33
+ When using modern bundlers, the root import automatically maps to the bundler target:
34
+
35
+ ```javascript
36
+ import { WasmTcpTransport } from 'modbus-rs-wasm';
33
37
  ```
38
+ *(Make sure your bundler is configured to load WebAssembly, e.g., using `vite-plugin-wasm` and `vite-plugin-top-level-await` in Vite).*
34
39
 
35
- ## Quick Start (Modbus RTU via Web Serial)
40
+ ## Quick Start
41
+
42
+ ### Examples
43
+ Ready-to-run HTML examples demonstrating both Modbus client and server functionality in the browser:
44
+
45
+ - **[wasm_client/network_smoke.html](./examples/wasm_client/network_smoke.html)**: WebSocket Modbus TCP client example.
46
+ - **[wasm_client/serial_smoke.html](./examples/wasm_client/serial_smoke.html)**: Web Serial Modbus RTU client example.
47
+ - **[wasm_server/network_smoke.html](./examples/wasm_server/network_smoke.html)**: WebSocket Modbus TCP server example.
48
+ - **[wasm_server/serial_smoke.html](./examples/wasm_server/serial_smoke.html)**: Web Serial Modbus RTU server example.
49
+
50
+ To run the examples locally:
51
+ ```bash
52
+ npx serve examples/
53
+ ```
54
+
55
+ ### Modbus RTU via Web Serial
36
56
 
37
57
  *Web Serial requires a Chromium-based browser (Chrome, Edge, Opera) and must be initiated by a user gesture (e.g., button click).*
38
58
 
@@ -41,19 +61,29 @@ If you are using modbus-rs on Node.js, you can use the native [`modbus-rs`](http
41
61
  If you have limitation on serial port using browser, then you may be interested in connecting serial port over ws/tcp so you can use the gateway application [modbus-gateway](https://github.com/Raghava-Ch/modbus-gateway).
42
62
 
43
63
  ```javascript
44
- import { request_serial_port, WasmSerialModbusClient } from 'modbus-rs-wasm';
64
+ import { request_serial_port, WasmSerialTransport } from 'modbus-rs-wasm';
45
65
 
46
66
  document.getElementById('connect-btn').addEventListener('click', async () => {
47
67
  try {
48
68
  // 1. Prompt user to select a serial port
49
69
  const portHandle = await request_serial_port();
50
70
 
51
- // 2. Connect client (handle, unit_id, mode, baud, data_bits, stop_bits, parity, timeout, retries, tick)
52
- const client = new WasmSerialModbusClient(
53
- portHandle, 1, 'rtu', 19200, 8, 1, 'even', 1000, 3, 20
54
- );
55
-
56
- // 3. Read coils
71
+ // 2. Create RTU Transport
72
+ const transport = new WasmSerialTransport(portHandle, {
73
+ mode: 'rtu',
74
+ baudRate: 19200,
75
+ dataBits: 8,
76
+ stopBits: 1,
77
+ parity: 'even',
78
+ responseTimeoutMs: 1000,
79
+ retryAttempts: 3,
80
+ tickIntervalMs: 20
81
+ });
82
+
83
+ // 3. Spawn a client for a specific slave (Unit ID)
84
+ const client = transport.create_client({ unitId: 10 });
85
+
86
+ // 4. Read coils
57
87
  const coils = await client.read_coils(0, 8);
58
88
  console.log('Coils:', coils); // Uint8Array
59
89
 
@@ -63,6 +93,101 @@ document.getElementById('connect-btn').addEventListener('click', async () => {
63
93
  });
64
94
  ```
65
95
 
96
+ ### Modbus TCP via WebSocket Gateway
97
+ First, run the gateway [modbus-gateway](https://github.com/Raghava-Ch/modbus-gateway).
98
+
99
+ ```javascript
100
+ import { WasmTcpTransport } from 'modbus-rs-wasm';
101
+
102
+ async function readRegisters() {
103
+ // 1. Connect to a WebSocket proxy that forwards to a Modbus TCP device
104
+ const transport = new WasmTcpTransport('ws://localhost:8502', {
105
+ responseTimeoutMs: 5000,
106
+ retryAttempts: 3,
107
+ tickIntervalMs: 20
108
+ });
109
+
110
+ // 2. Spawn a client attached to Unit ID 1
111
+ const client = transport.create_client({ unitId: 1 });
112
+
113
+ try {
114
+ // 3. Read 10 holding registers starting at address 0
115
+ const registers = await client.read_holding_registers(0, 10);
116
+ console.log('Holding registers:', registers); // Uint16Array
117
+ } catch (error) {
118
+ console.error('Failed to read registers:', error);
119
+ }
120
+ }
121
+ ```
122
+
123
+ ### Modbus server demo with modbus-rs-wasm
124
+
125
+ The `modbus-rs-wasm` package also provides building blocks for server simulation inside the browser. You can instantiate a `WasmTcpServer` or `WasmSerialServer` by providing a configuration and a JavaScript callback to process incoming requests.
126
+
127
+ Here is a quick example of setting up a simulated server via a WebSocket TCP gateway:
128
+
129
+ ```javascript
130
+ import { WasmTcpGatewayConfig, WasmTcpServer } from 'modbus-rs-wasm';
131
+
132
+ async function simulateServer() {
133
+ // 1. Configure the server (e.g., pointing to a WebSocket gateway)
134
+ const config = new WasmTcpGatewayConfig("ws://localhost:8080");
135
+
136
+ // 2. Create the server and define the request handler
137
+ const server = new WasmTcpServer(config, async (request) => {
138
+ console.log("Received Modbus request:", request);
139
+
140
+ // Simulate processing the request
141
+ // The handler can be fully asynchronous and return a Promise
142
+ return {
143
+ // Return appropriate response fields based on the request
144
+ success: true,
145
+ data: [100, 200, 300]
146
+ };
147
+ });
148
+
149
+ // 3. Start the server
150
+ server.start();
151
+
152
+ // Observe the server status
153
+ console.log("Server running:", server.is_running());
154
+ console.log("Server status:", server.status_snapshot());
155
+ }
156
+ ```
157
+
158
+ ### Serial Server Simulation
159
+
160
+ You can also create a simulated serial server (RTU or ASCII) and attach a browser `SerialPort` to it using the Web Serial API:
161
+
162
+ ```javascript
163
+ import { WasmSerialServerConfig, WasmSerialServer } from 'modbus-rs-wasm';
164
+
165
+ async function simulateSerialServer() {
166
+ // 1. Request a serial port from the user (requires user gesture)
167
+ const port = await navigator.serial.requestPort();
168
+
169
+ // 2. Configure the server for RTU or ASCII mode
170
+ const config = WasmSerialServerConfig.rtu(); // or .ascii()
171
+
172
+ // 3. Create the server with a request handler callback
173
+ const server = new WasmSerialServer(config, async (request) => {
174
+ console.log("Received Modbus request via Serial:", request);
175
+ return {
176
+ success: true,
177
+ data: [100, 200, 300]
178
+ };
179
+ });
180
+
181
+ // 4. Attach the browser serial port
182
+ server.attach_serial_port(port);
183
+
184
+ // 5. Start the server
185
+ server.start();
186
+
187
+ console.log("Serial Server running:", server.is_running());
188
+ }
189
+ ```
190
+
66
191
  ## License
67
192
 
68
193
  GPL-3.0-only — see [LICENSE](./LICENSE). A commercial license is available for proprietary use.
@@ -1,10 +1,35 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
3
 
4
+ export interface WasmSerialTransportOptions {
5
+ mode?: "rtu" | "ascii";
6
+ baudRate: number;
7
+ dataBits?: 5 | 6 | 7 | 8;
8
+ stopBits?: 1 | 2;
9
+ parity?: "none" | "even" | "odd";
10
+ responseTimeoutMs?: number;
11
+ retryAttempts?: number;
12
+ tickIntervalMs?: number;
13
+ }
14
+
15
+
16
+
17
+ export interface WasmTcpTransportOptions {
18
+ responseTimeoutMs?: number;
19
+ retryAttempts?: number;
20
+ tickIntervalMs?: number;
21
+ }
22
+ export interface WasmCreateClientOptions {
23
+ unitId?: number;
24
+ }
25
+
26
+
27
+
4
28
  /**
5
- * Browser-facing Modbus client that communicates over a WebSocket transport.
29
+ * Browser-facing Modbus client bound to a specific unit ID.
6
30
  */
7
31
  export class WasmModbusClient {
32
+ private constructor();
8
33
  free(): void;
9
34
  [Symbol.dispose](): void;
10
35
  /**
@@ -28,13 +53,11 @@ export class WasmModbusClient {
28
53
  */
29
54
  get_comm_event_log(): Promise<any>;
30
55
  /**
31
- * Returns `true` if there are in-flight Modbus requests waiting for
32
- * response/timeout resolution.
56
+ * Returns `true` if there are in-flight Modbus requests.
33
57
  */
34
58
  has_pending_requests(): boolean;
35
59
  /**
36
- * Returns `true` when the underlying WebSocket is open and the transport
37
- * considers itself connected.
60
+ * Returns `true` when the underlying WebSocket is open.
38
61
  */
39
62
  is_connected(): boolean;
40
63
  /**
@@ -44,17 +67,6 @@ export class WasmModbusClient {
44
67
  * Returns a `Promise` resolving with `true` or rejects on error.
45
68
  */
46
69
  mask_write_register(address: number, and_mask: number, or_mask: number): Promise<any>;
47
- /**
48
- * Create a new Modbus master client and immediately start the background tick loop.
49
- *
50
- * # Arguments
51
- * - `ws_url` — WebSocket URL of the Modbus/TCP gateway (e.g. `"ws://192.168.1.1:8502"`).
52
- * - `unit_id` — Modbus unit ID / slave address of the target device (1–247).
53
- * - `response_timeout_ms` — How long (ms) to wait before retrying or failing a request.
54
- * - `retry_attempts` — Number of retries before reporting an error to JS.
55
- * - `tick_interval_ms` — How often (ms) the tick loop calls `poll()`. 20 ms is a safe default.
56
- */
57
- constructor(ws_url: string, unit_id: number, response_timeout_ms: number, retry_attempts: number, tick_interval_ms: number);
58
70
  /**
59
71
  * Read `quantity` coils starting at `address`.
60
72
  *
@@ -142,11 +154,6 @@ export class WasmModbusClient {
142
154
  * Returns a `Promise` resolving with a `Uint16Array` (the values read) or rejects on error.
143
155
  */
144
156
  read_write_multiple_registers(read_address: number, read_quantity: number, write_address: number, _write_quantity: number, values: Uint16Array): Promise<any>;
145
- /**
146
- * Drop all pending in-flight requests and attempt to reconnect the WebSocket.
147
- * Outstanding Promises for dropped requests will be rejected with `"ConnectionLost"`.
148
- */
149
- reconnect(): boolean;
150
157
  /**
151
158
  * Report Server ID (FC 17).
152
159
  *
@@ -188,9 +195,10 @@ export class WasmModbusClient {
188
195
  }
189
196
 
190
197
  /**
191
- * Browser-facing Modbus client that communicates over Web Serial RTU or ASCII.
198
+ * Browser-facing Modbus client bound to a specific serial unit ID.
192
199
  */
193
200
  export class WasmSerialModbusClient {
201
+ private constructor();
194
202
  free(): void;
195
203
  [Symbol.dispose](): void;
196
204
  /**
@@ -214,12 +222,11 @@ export class WasmSerialModbusClient {
214
222
  */
215
223
  get_comm_event_log(): Promise<any>;
216
224
  /**
217
- * Returns `true` if there are in-flight Modbus requests waiting for
218
- * response/timeout resolution.
225
+ * Returns `true` if there are in-flight Modbus requests.
219
226
  */
220
227
  has_pending_requests(): boolean;
221
228
  /**
222
- * Returns `true` when the serial port is open and the transport considers itself connected.
229
+ * Returns `true` when the serial port is open.
223
230
  */
224
231
  is_connected(): boolean;
225
232
  /**
@@ -229,13 +236,6 @@ export class WasmSerialModbusClient {
229
236
  * Returns a `Promise` resolving with `true` or rejects on error.
230
237
  */
231
238
  mask_write_register(address: number, and_mask: number, or_mask: number): Promise<any>;
232
- /**
233
- * Creates a Modbus serial client over browser Web Serial.
234
- *
235
- * `mode` accepts "rtu" or "ascii" (case-insensitive).
236
- * `parity` accepts "none", "even", or "odd".
237
- */
238
- constructor(port_handle: WasmSerialPortHandle, unit_id: number, mode: string, baud_rate: number, data_bits: number, stop_bits: number, parity: string, response_timeout_ms: number, retry_attempts: number, tick_interval_ms: number);
239
239
  /**
240
240
  * Read `quantity` coils starting at `address`.
241
241
  *
@@ -320,11 +320,6 @@ export class WasmSerialModbusClient {
320
320
  * Returns a `Promise` resolving with a `Uint16Array` (the values read) or rejects on error.
321
321
  */
322
322
  read_write_multiple_registers(read_address: number, read_quantity: number, write_address: number, _write_quantity: number, values: Uint16Array): Promise<any>;
323
- /**
324
- * Drop all pending in-flight requests and attempt to reopen the serial port.
325
- * Outstanding Promises for dropped requests will be rejected with `"ConnectionLost"`.
326
- */
327
- reconnect(): boolean;
328
323
  /**
329
324
  * Report Server ID (FC 17).
330
325
  *
@@ -461,6 +456,41 @@ export class WasmSerialServerConfig {
461
456
  static rtu(): WasmSerialServerConfig;
462
457
  }
463
458
 
459
+ /**
460
+ * Connection and polling manager for browser Modbus Serial clients.
461
+ */
462
+ export class WasmSerialTransport {
463
+ free(): void;
464
+ [Symbol.dispose](): void;
465
+ /**
466
+ * Closes the serial port connection and rejects all pending requests.
467
+ */
468
+ close(): void;
469
+ /**
470
+ * Creates a device client bound to the specified unit ID.
471
+ */
472
+ createClient(options?: WasmCreateClientOptions | null): WasmSerialModbusClient;
473
+ /**
474
+ * Returns `true` if there are in-flight Modbus requests.
475
+ */
476
+ has_pending_requests(): boolean;
477
+ /**
478
+ * Returns `true` when the serial port is open and connected.
479
+ */
480
+ is_connected(): boolean;
481
+ /**
482
+ * Creates a new Serial (RTU) transport using the provided `port_handle`.
483
+ *
484
+ * The transport claims the underlying serial stream and manages the
485
+ * read/write loop, allowing multiple clients to multiplex requests over it.
486
+ */
487
+ constructor(port_handle: WasmSerialPortHandle, options?: WasmSerialTransportOptions | null);
488
+ /**
489
+ * Drop all pending in-flight requests and attempt to reopen the serial port.
490
+ */
491
+ reconnect(): boolean;
492
+ }
493
+
464
494
  /**
465
495
  * High-level design descriptor for phased server binding rollout.
466
496
  */
@@ -637,6 +667,41 @@ export class WasmTcpServer {
637
667
  ws_url(): string;
638
668
  }
639
669
 
670
+ /**
671
+ * Connection and background polling manager for browser Modbus TCP clients.
672
+ */
673
+ export class WasmTcpTransport {
674
+ free(): void;
675
+ [Symbol.dispose](): void;
676
+ /**
677
+ * Closes the connection and rejects all pending requests.
678
+ */
679
+ close(): void;
680
+ /**
681
+ * Creates a device client bound to the specified unit ID.
682
+ */
683
+ createClient(options?: WasmCreateClientOptions | null): WasmModbusClient;
684
+ /**
685
+ * Returns `true` if there are in-flight Modbus requests.
686
+ */
687
+ has_pending_requests(): boolean;
688
+ /**
689
+ * Returns `true` when the underlying WebSocket is open and connected.
690
+ */
691
+ is_connected(): boolean;
692
+ /**
693
+ * Creates a new TCP/WebSocket transport.
694
+ *
695
+ * This establishes a connection to the provided `ws_url` and handles
696
+ * the underlying read/write loops.
697
+ */
698
+ constructor(ws_url: string, options?: WasmTcpTransportOptions | null);
699
+ /**
700
+ * Drop all pending in-flight requests and attempt to reconnect.
701
+ */
702
+ reconnect(): boolean;
703
+ }
704
+
640
705
  /**
641
706
  * Requests a browser serial port from `navigator.serial.requestPort()`.
642
707
  *
@@ -5,5 +5,5 @@ import { __wbg_set_wasm } from "./modbus-rs_bg.js";
5
5
  __wbg_set_wasm(wasm);
6
6
  wasm.__wbindgen_start();
7
7
  export {
8
- WasmModbusClient, WasmSerialModbusClient, WasmSerialPortHandle, WasmSerialServer, WasmSerialServerConfig, WasmServerBindingPlan, WasmServerStatusSnapshot, WasmServerTransportKind, WasmTcpGatewayConfig, WasmTcpServer, request_serial_port
8
+ WasmModbusClient, WasmSerialModbusClient, WasmSerialPortHandle, WasmSerialServer, WasmSerialServerConfig, WasmSerialTransport, WasmServerBindingPlan, WasmServerStatusSnapshot, WasmServerTransportKind, WasmTcpGatewayConfig, WasmTcpServer, WasmTcpTransport, request_serial_port
9
9
  } from "./modbus-rs_bg.js";