@flux-control/effect-modbus-rs 0.1.1 → 0.2.0
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 +147 -86
- package/dist/index.d.ts +31 -11
- package/dist/index.js +326 -251
- package/dist/src/AsciiTransportService.d.ts +3 -3
- package/dist/src/RtuTransportService.d.ts +3 -3
- package/dist/src/SerialModbusServerService.d.ts +5 -5
- package/dist/src/SerialTransportService.d.ts +4 -4
- package/dist/src/TcpGatewayService.d.ts +4 -4
- package/dist/src/TcpModbusServerService.d.ts +4 -4
- package/dist/src/TcpTransportService.d.ts +3 -3
- package/dist/src/WasmAsciiTransportService.d.ts +56 -0
- package/dist/src/WasmRtuTransportService.d.ts +56 -0
- package/dist/src/WasmSerialModbusServerService.d.ts +54 -0
- package/dist/src/WasmSerialPort.d.ts +27 -0
- package/dist/src/WasmSerialTransportService.d.ts +48 -0
- package/dist/src/WasmTcpServerService.d.ts +38 -0
- package/dist/src/WasmWsTransportService.d.ts +45 -0
- package/dist/src/mocks.d.ts +6 -5
- package/dist/src/modbus-client.d.ts +29 -21
- package/dist/src/modbus-client.wasm.test.d.ts +1 -0
- package/dist/src/shared-transport.d.ts +8 -4
- package/dist/src/wasm-mocks.test.d.ts +1 -0
- package/package.json +24 -17
package/README.md
CHANGED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
**Type-safe Modbus communication via Effect-TS**, wrapping the [`modbus-rs`](https://github.com/Raghava-Ch/modbus-rs) npm bindings (Rust napi-rs under the hood).
|
|
4
4
|
|
|
5
|
+
For the complete API reference, see the [GitHub Pages documentation](https://flux-control-solutions.github.io/Effect-modbus-rs/).
|
|
6
|
+
|
|
5
7
|
Provides scoped [`Effect.Service`](https://effect.website) constructors for RTU (serial), TCP, and ASCII Modbus transports. Clients expose a typed `Effect`-based API for all standard Modbus function codes.
|
|
6
8
|
|
|
9
|
+
> This project is under active development. Its API may change before the 1.0 release.
|
|
10
|
+
|
|
7
11
|
## Install
|
|
8
12
|
|
|
9
13
|
```sh
|
|
10
|
-
bun add effect-modbus-rs
|
|
14
|
+
bun add @flux-control/effect-modbus-rs
|
|
11
15
|
```
|
|
12
16
|
|
|
13
17
|
TypeScript only while prototyping (JS consumers will be supported before 1.0).
|
|
@@ -17,8 +21,8 @@ TypeScript only while prototyping (JS consumers will be supported before 1.0).
|
|
|
17
21
|
### RTU (serial)
|
|
18
22
|
|
|
19
23
|
```ts
|
|
20
|
-
import { Console, Effect } from
|
|
21
|
-
import { RtuTransportService } from
|
|
24
|
+
import { Console, Effect } from 'effect';
|
|
25
|
+
import { RtuTransportService } from '@flux-control/effect-modbus-rs';
|
|
22
26
|
|
|
23
27
|
const program = Effect.gen(function* () {
|
|
24
28
|
const transport = yield* RtuTransportService;
|
|
@@ -28,25 +32,19 @@ const program = Effect.gen(function* () {
|
|
|
28
32
|
address: 0,
|
|
29
33
|
quantity: 10,
|
|
30
34
|
});
|
|
31
|
-
console.log(
|
|
35
|
+
console.log('Holding registers:', registers);
|
|
32
36
|
});
|
|
33
37
|
|
|
34
38
|
program.pipe(
|
|
35
39
|
Effect.catchTags({
|
|
36
40
|
ModbusTimeoutError: (err) => Console.log(`Timeout: ${err.message}`),
|
|
37
|
-
ModbusTransportError: (err) =>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
ModbusExceptionError: (err) =>
|
|
42
|
-
Console.log(`Modbus exception ${err.exception}: ${err.message}`),
|
|
43
|
-
ModbusInvalidArgumentError: (err) =>
|
|
44
|
-
Console.log(`Invalid argument: ${err.message}`),
|
|
41
|
+
ModbusTransportError: (err) => Console.log(`Transport error: ${err.message}`),
|
|
42
|
+
ModbusConnectionClosedError: (err) => Console.log(`Connection lost: ${err.message}`),
|
|
43
|
+
ModbusExceptionError: (err) => Console.log(`Modbus exception ${err.exception}: ${err.message}`),
|
|
44
|
+
ModbusInvalidArgumentError: (err) => Console.log(`Invalid argument: ${err.message}`),
|
|
45
45
|
}),
|
|
46
46
|
Effect.catchAll((err) => Console.log(`Unhandled error: ${err.message}`)),
|
|
47
|
-
Effect.provide(
|
|
48
|
-
RtuTransportService.Default({ portPath: "/dev/ttyUSB0", baudRate: 9600 }),
|
|
49
|
-
),
|
|
47
|
+
Effect.provide(RtuTransportService.Default({ portPath: '/dev/ttyUSB0', baudRate: 9600 })),
|
|
50
48
|
Effect.scoped,
|
|
51
49
|
Effect.runPromise,
|
|
52
50
|
);
|
|
@@ -55,20 +53,18 @@ program.pipe(
|
|
|
55
53
|
### TCP
|
|
56
54
|
|
|
57
55
|
```ts
|
|
58
|
-
import { Effect } from
|
|
59
|
-
import { TcpTransportService } from
|
|
56
|
+
import { Effect } from 'effect';
|
|
57
|
+
import { TcpTransportService } from '@flux-control/effect-modbus-rs';
|
|
60
58
|
|
|
61
59
|
const program = Effect.gen(function* () {
|
|
62
60
|
const transport = yield* TcpTransportService;
|
|
63
61
|
const client = yield* transport.withClient(1);
|
|
64
62
|
const coils = yield* client.readCoils({ address: 0, quantity: 8 });
|
|
65
|
-
console.log(
|
|
63
|
+
console.log('Coils:', coils);
|
|
66
64
|
});
|
|
67
65
|
|
|
68
66
|
program.pipe(
|
|
69
|
-
Effect.provide(
|
|
70
|
-
TcpTransportService.Default({ host: "192.168.1.100", port: 502 }),
|
|
71
|
-
),
|
|
67
|
+
Effect.provide(TcpTransportService.Default({ host: '192.168.1.100', port: 502 })),
|
|
72
68
|
Effect.scoped,
|
|
73
69
|
Effect.runPromise,
|
|
74
70
|
);
|
|
@@ -77,8 +73,8 @@ program.pipe(
|
|
|
77
73
|
### ASCII
|
|
78
74
|
|
|
79
75
|
```ts
|
|
80
|
-
import { Effect } from
|
|
81
|
-
import { AsciiTransportService } from
|
|
76
|
+
import { Effect } from 'effect';
|
|
77
|
+
import { AsciiTransportService } from '@flux-control/effect-modbus-rs';
|
|
82
78
|
|
|
83
79
|
const program = Effect.gen(function* () {
|
|
84
80
|
const transport = yield* AsciiTransportService;
|
|
@@ -87,48 +83,104 @@ const program = Effect.gen(function* () {
|
|
|
87
83
|
address: 0,
|
|
88
84
|
quantity: 5,
|
|
89
85
|
});
|
|
90
|
-
console.log(
|
|
86
|
+
console.log('Input registers:', registers);
|
|
91
87
|
});
|
|
92
88
|
|
|
93
89
|
program.pipe(
|
|
94
|
-
Effect.provide(
|
|
95
|
-
AsciiTransportService.Default({ portPath: "/dev/ttyUSB0", baudRate: 9600 }),
|
|
96
|
-
),
|
|
90
|
+
Effect.provide(AsciiTransportService.Default({ portPath: '/dev/ttyUSB0', baudRate: 9600 })),
|
|
97
91
|
Effect.scoped,
|
|
98
92
|
Effect.runPromise,
|
|
99
93
|
);
|
|
100
94
|
```
|
|
101
95
|
|
|
96
|
+
### Browser / WASM (`modbus-rs/web`)
|
|
97
|
+
|
|
98
|
+
`modbus-rs` ships its browser bindings through the `modbus-rs/web` WASM module. This package loads that module dynamically and exposes the same scoped, typed `Effect` client API as its native transports. Since browsers can't open raw TCP or serial connections directly, there are two browser-specific transports:
|
|
99
|
+
|
|
100
|
+
- **`WasmWsTransportService`** — Modbus TCP over a WebSocket-to-TCP gateway (e.g. the `modbus-gateway` application).
|
|
101
|
+
- **`WasmRtuTransportService`** / **`WasmAsciiTransportService`** — Modbus RTU/ASCII over the [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API), via `WasmSerialTransportService.fromRtu` / `.fromAscii`.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { Console, Effect } from 'effect';
|
|
105
|
+
import { WasmWsTransportService } from '@flux-control/effect-modbus-rs';
|
|
106
|
+
|
|
107
|
+
const program = Effect.gen(function* () {
|
|
108
|
+
const transport = yield* WasmWsTransportService;
|
|
109
|
+
const client = yield* transport.withClient(1);
|
|
110
|
+
const registers = yield* client.readHoldingRegisters({ address: 0, quantity: 10 });
|
|
111
|
+
console.log('Holding registers:', registers);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
program.pipe(
|
|
115
|
+
Effect.provide(WasmWsTransportService.Default({ wsUrl: 'ws://localhost:8080' })),
|
|
116
|
+
Effect.scoped,
|
|
117
|
+
Effect.runPromise,
|
|
118
|
+
);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Web Serial requires a user-granted port handle. **`requestSerialPort()` must be called synchronously from within a user-gesture event handler** (e.g. a button click) — this is a Web Serial API / browser security requirement, not a library restriction:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { Effect, Layer } from 'effect';
|
|
125
|
+
import { requestSerialPort, WasmRtuTransportService } from '@flux-control/effect-modbus-rs';
|
|
126
|
+
|
|
127
|
+
connectButton.addEventListener('click', () => {
|
|
128
|
+
Effect.runPromise(
|
|
129
|
+
Effect.gen(function* () {
|
|
130
|
+
const port = yield* requestSerialPort();
|
|
131
|
+
yield* program.pipe(
|
|
132
|
+
Effect.provide(WasmRtuTransportService.Default({ port, baudRate: 19200 })),
|
|
133
|
+
Effect.scoped,
|
|
134
|
+
);
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
See `examples/wasm/` for a real, runnable Vite app exercising both transports in an actual browser (`cd examples/wasm && npm install && npm run dev`).
|
|
141
|
+
|
|
142
|
+
#### Browser server (experimental)
|
|
143
|
+
|
|
144
|
+
`wasmWsServerLayer` and `wasmSerialRtuServerLayer` / `wasmSerialAsciiServerLayer` wrap `modbus-rs`'s experimental browser server bindings — same `ServerHandlers` callback shape as the native servers below. Two things differ from native:
|
|
145
|
+
|
|
146
|
+
- Unlike native servers, the WASM server doesn't start serving on bind — these layers fork the required `serve()` loop into the layer's scope automatically, so usage looks the same as the native `tcpServerLayer`.
|
|
147
|
+
- For the serial variants, `options.serialPort` comes from your own app's `navigator.serial.requestPort()` call (not from this package's `requestSerialPort()`, which returns a different wrapper type used only by the client transports).
|
|
148
|
+
|
|
149
|
+
Not demonstrated in `examples/wasm/` (see that app's README) — the same `import { wasmWsServerLayer } from "@flux-control/effect-modbus-rs"` pattern applies.
|
|
150
|
+
|
|
102
151
|
## Transports
|
|
103
152
|
|
|
104
153
|
Each transport is a scoped `Effect.Service`. You provide it with `Effect.provide`, and the connection is opened on service access and closed when the scope ends.
|
|
105
154
|
|
|
106
|
-
| Service
|
|
107
|
-
|
|
108
|
-
| `RtuTransportService`
|
|
109
|
-
| `TcpTransportService`
|
|
110
|
-
| `AsciiTransportService`
|
|
155
|
+
| Service | Options | Connection |
|
|
156
|
+
| ------------------------------------- | ------------------------------ | ----------------------------- |
|
|
157
|
+
| `RtuTransportService` | `{ portPath, baudRate, ... }` | `AsyncRtuTransport.open()` |
|
|
158
|
+
| `TcpTransportService` | `{ host, port, ... }` | `AsyncTcpTransport.connect()` |
|
|
159
|
+
| `AsciiTransportService` | `{ portPath, baudRate, ... }` | `AsyncAsciiTransport.open()` |
|
|
160
|
+
| `WasmWsTransportService` (browser) | `{ wsUrl, requestTimeoutMs? }` | `WasmWsTransport.connect()` |
|
|
161
|
+
| `WasmRtuTransportService` (browser) | `{ port, baudRate, ... }` | `WasmRtuTransport.open()` |
|
|
162
|
+
| `WasmAsciiTransportService` (browser) | `{ port, baudRate, ... }` | `WasmAsciiTransport.open()` |
|
|
111
163
|
|
|
112
|
-
All transport options types are re-exported from `modbus-rs
|
|
164
|
+
All transport options types are re-exported from `modbus-rs` (native transports) or `modbus-rs/web` (browser transports).
|
|
113
165
|
|
|
114
166
|
### Abstract serial transport
|
|
115
167
|
|
|
116
168
|
`SerialTransportService` is a transport-agnostic tag that can be backed by either RTU or ASCII framing — useful when writing code that doesn't need to commit to a specific serial protocol. Provide it with `fromRtu` or `fromAscii`:
|
|
117
169
|
|
|
118
170
|
```ts
|
|
119
|
-
import { Console, Effect } from
|
|
120
|
-
import { SerialTransportService } from
|
|
171
|
+
import { Console, Effect } from 'effect';
|
|
172
|
+
import { SerialTransportService } from '@flux-control/effect-modbus-rs';
|
|
121
173
|
|
|
122
174
|
const program = Effect.gen(function* () {
|
|
123
175
|
const transport = yield* SerialTransportService;
|
|
124
176
|
const client = yield* transport.withClient(1);
|
|
125
177
|
const coils = yield* client.readCoils({ address: 0, quantity: 2 });
|
|
126
|
-
console.log(
|
|
178
|
+
console.log('Coils:', coils);
|
|
127
179
|
});
|
|
128
180
|
|
|
129
181
|
// RTU framing
|
|
130
182
|
program.pipe(
|
|
131
|
-
Effect.provide(SerialTransportService.fromRtu({ portPath:
|
|
183
|
+
Effect.provide(SerialTransportService.fromRtu({ portPath: '/dev/ttyUSB0', baudRate: 9600 })),
|
|
132
184
|
Effect.scoped,
|
|
133
185
|
Effect.runPromise,
|
|
134
186
|
);
|
|
@@ -149,47 +201,47 @@ It also supports `makeMockTransport` for testing:
|
|
|
149
201
|
|
|
150
202
|
### Registers
|
|
151
203
|
|
|
152
|
-
| Method
|
|
153
|
-
|
|
154
|
-
| `readHoldingRegisters({ address, quantity })`
|
|
155
|
-
| `readInputRegisters({ address, quantity })`
|
|
156
|
-
| `writeSingleRegister({ address, value })`
|
|
157
|
-
| `writeMultipleRegisters({ address, values })`
|
|
204
|
+
| Method | Returns |
|
|
205
|
+
| -------------------------------------------------------------------------------------- | ---------- |
|
|
206
|
+
| `readHoldingRegisters({ address, quantity })` | `number[]` |
|
|
207
|
+
| `readInputRegisters({ address, quantity })` | `number[]` |
|
|
208
|
+
| `writeSingleRegister({ address, value })` | `void` |
|
|
209
|
+
| `writeMultipleRegisters({ address, values })` | `void` |
|
|
158
210
|
| `readWriteMultipleRegisters({ readAddress, readQuantity, writeAddress, writeValues })` | `number[]` |
|
|
159
211
|
|
|
160
212
|
### Coils / discrete inputs
|
|
161
213
|
|
|
162
|
-
| Method
|
|
163
|
-
|
|
164
|
-
| `readCoils({ address, quantity })`
|
|
165
|
-
| `writeSingleCoil({ address, value })`
|
|
166
|
-
| `writeMultipleCoils({ address, values })`
|
|
214
|
+
| Method | Returns |
|
|
215
|
+
| ------------------------------------------- | ----------- |
|
|
216
|
+
| `readCoils({ address, quantity })` | `boolean[]` |
|
|
217
|
+
| `writeSingleCoil({ address, value })` | `void` |
|
|
218
|
+
| `writeMultipleCoils({ address, values })` | `void` |
|
|
167
219
|
| `readDiscreteInputs({ address, quantity })` | `boolean[]` |
|
|
168
220
|
|
|
169
221
|
### Diagnostics & file access
|
|
170
222
|
|
|
171
|
-
| Method
|
|
172
|
-
|
|
173
|
-
| `readExceptionStatus()`
|
|
174
|
-
| `diagnostics({ subFunction, data })`
|
|
175
|
-
| `readFifoQueue({ address })`
|
|
176
|
-
| `readFileRecord({ requests })`
|
|
177
|
-
| `writeFileRecord({ requests })`
|
|
223
|
+
| Method | Returns |
|
|
224
|
+
| ---------------------------------------------------------- | ------------------------------ |
|
|
225
|
+
| `readExceptionStatus()` | `number` |
|
|
226
|
+
| `diagnostics({ subFunction, data })` | `DiagnosticsResponse` |
|
|
227
|
+
| `readFifoQueue({ address })` | `FifoQueueResponse` |
|
|
228
|
+
| `readFileRecord({ requests })` | `number[][]` |
|
|
229
|
+
| `writeFileRecord({ requests })` | `void` |
|
|
178
230
|
| `readDeviceIdentification({ readDeviceIdCode, objectId })` | `DeviceIdentificationResponse` |
|
|
179
231
|
|
|
180
232
|
## Error handling
|
|
181
233
|
|
|
182
234
|
Errors from the underlying Rust layer are mapped to typed `Effect` errors via `Data.TaggedError`:
|
|
183
235
|
|
|
184
|
-
| Error class
|
|
185
|
-
|
|
186
|
-
| `ModbusExceptionError`
|
|
187
|
-
| `ModbusTimeoutError`
|
|
188
|
-
| `ModbusTransportError`
|
|
189
|
-
| `ModbusInvalidArgumentError`
|
|
190
|
-
| `ModbusConnectionClosedError` | Connection lost
|
|
191
|
-
| `ModbusNotConnectedError`
|
|
192
|
-
| `ModbusInternalError`
|
|
236
|
+
| Error class | Meaning |
|
|
237
|
+
| ----------------------------- | ----------------------------------------------------- |
|
|
238
|
+
| `ModbusExceptionError` | Modbus protocol exception (contains `exception` code) |
|
|
239
|
+
| `ModbusTimeoutError` | Request timed out |
|
|
240
|
+
| `ModbusTransportError` | Transport-level failure |
|
|
241
|
+
| `ModbusInvalidArgumentError` | Invalid parameters |
|
|
242
|
+
| `ModbusConnectionClosedError` | Connection lost |
|
|
243
|
+
| `ModbusNotConnectedError` | Operation attempted before connection |
|
|
244
|
+
| `ModbusInternalError` | Unclassified error |
|
|
193
245
|
|
|
194
246
|
Handle with `Effect.catchTags`. The `ModbusError` union type covers all seven variants.
|
|
195
247
|
|
|
@@ -198,8 +250,8 @@ Handle with `Effect.catchTags`. The `ModbusError` union type covers all seven va
|
|
|
198
250
|
Each transport service provides a `makeMockTransport(devices)` static method that returns an in-memory mock `Layer` — no serial port or network required.
|
|
199
251
|
|
|
200
252
|
```ts
|
|
201
|
-
import { Console, Effect } from
|
|
202
|
-
import { RtuTransportService } from
|
|
253
|
+
import { Console, Effect } from 'effect';
|
|
254
|
+
import { RtuTransportService } from '@flux-control/effect-modbus-rs';
|
|
203
255
|
|
|
204
256
|
const device = {
|
|
205
257
|
unitId: 1,
|
|
@@ -219,19 +271,15 @@ const program = Effect.gen(function* () {
|
|
|
219
271
|
const transport = yield* RtuTransportService;
|
|
220
272
|
const client = yield* transport.withClient(1);
|
|
221
273
|
const coils = yield* client.readCoils({ address: 0, quantity: 2 });
|
|
222
|
-
console.log(
|
|
274
|
+
console.log('Coils:', coils);
|
|
223
275
|
});
|
|
224
276
|
|
|
225
277
|
const mockLayer = RtuTransportService.makeMockTransport([device])({
|
|
226
|
-
portPath:
|
|
278
|
+
portPath: '/dev/ttyUSB0',
|
|
227
279
|
baudRate: 9600,
|
|
228
280
|
});
|
|
229
281
|
|
|
230
|
-
program.pipe(
|
|
231
|
-
Effect.provide(mockLayer),
|
|
232
|
-
Effect.scoped,
|
|
233
|
-
Effect.runPromise,
|
|
234
|
-
);
|
|
282
|
+
program.pipe(Effect.provide(mockLayer), Effect.scoped, Effect.runPromise);
|
|
235
283
|
```
|
|
236
284
|
|
|
237
285
|
The mock factory is identical for all three transports; swap `RtuTransportService` for `TcpTransportService` or `AsciiTransportService` and adjust the options shape accordingly — each exposes a static `makeMockTransport` method.
|
|
@@ -240,23 +288,23 @@ See `examples/rtu-mock.ts`, `examples/tcp-mock.ts`, and `examples/ascii-mock.ts`
|
|
|
240
288
|
|
|
241
289
|
### Slave device schema
|
|
242
290
|
|
|
243
|
-
| Property
|
|
244
|
-
|
|
245
|
-
| `unitId`
|
|
246
|
-
| `coils`
|
|
247
|
-
| `discreteInputs`
|
|
248
|
-
| `holdingRegisters` | `{ address, default }[]` | `[]`
|
|
249
|
-
| `inputRegisters`
|
|
291
|
+
| Property | Type | Default |
|
|
292
|
+
| ------------------ | ------------------------ | -------- |
|
|
293
|
+
| `unitId` | `number` | required |
|
|
294
|
+
| `coils` | `{ address, default }[]` | `[]` |
|
|
295
|
+
| `discreteInputs` | `{ address, default }[]` | `[]` |
|
|
296
|
+
| `holdingRegisters` | `{ address, default }[]` | `[]` |
|
|
297
|
+
| `inputRegisters` | `{ address, default }[]` | `[]` |
|
|
250
298
|
|
|
251
299
|
Coil/default values default to `false` if omitted at the address level; register values default to `0`. Reads beyond the highest configured address produce a `ModbusInvalidArgumentError`.
|
|
252
300
|
|
|
253
301
|
## Development
|
|
254
302
|
|
|
255
|
-
| Action
|
|
256
|
-
|
|
257
|
-
| Install
|
|
258
|
-
| Type-check
|
|
259
|
-
| Test
|
|
303
|
+
| Action | Command |
|
|
304
|
+
| ----------- | ---------------------------- |
|
|
305
|
+
| Install | `bun install` |
|
|
306
|
+
| Type-check | `bun run typecheck` |
|
|
307
|
+
| Test | `bun test` |
|
|
260
308
|
| Run example | `bun run examples/<name>.ts` |
|
|
261
309
|
|
|
262
310
|
No build step — `noEmit` is on; Bun runs `.ts` directly.
|
|
@@ -266,13 +314,23 @@ No build step — `noEmit` is on; Bun runs `.ts` directly.
|
|
|
266
314
|
```
|
|
267
315
|
src/
|
|
268
316
|
errors.ts — Data.TaggedError types + toModbusError converter
|
|
269
|
-
modbus-client.ts — EffectModbusClient interface + factory
|
|
317
|
+
modbus-client.ts — EffectModbusClient interface + factory (native + WASM)
|
|
270
318
|
mocks.ts — Schema-validated mock transport + slave device definitions
|
|
271
319
|
shared-transport.ts — Generic scoped transport lifecycle management
|
|
272
320
|
RtuTransportService.ts — Scoped Effect.Service wrapping AsyncRtuTransport
|
|
273
321
|
TcpTransportService.ts — Scoped Effect.Service wrapping AsyncTcpTransport
|
|
274
322
|
AsciiTransportService.ts — Scoped Effect.Service wrapping AsyncAsciiTransport
|
|
275
323
|
SerialTransportService.ts — Abstract serial transport (RTU/ASCII) tag
|
|
324
|
+
TcpModbusServerService.ts — tcpServerLayer
|
|
325
|
+
SerialModbusServerService.ts — serialRtuServerLayer / serialAsciiServerLayer
|
|
326
|
+
TcpGatewayService.ts — tcpGatewayLayer
|
|
327
|
+
WasmSerialPort.ts — requestSerialPort() Effect helper (browser, user-gesture gated)
|
|
328
|
+
WasmWsTransportService.ts — Scoped Effect.Service wrapping WasmWsTransport (browser, WS gateway)
|
|
329
|
+
WasmRtuTransportService.ts — Scoped Effect.Service wrapping WasmRtuTransport (browser, Web Serial RTU)
|
|
330
|
+
WasmAsciiTransportService.ts — Scoped Effect.Service wrapping WasmAsciiTransport (browser, Web Serial ASCII)
|
|
331
|
+
WasmSerialTransportService.ts — Abstract browser serial transport (RTU/ASCII) tag
|
|
332
|
+
WasmTcpServerService.ts — wasmWsServerLayer (experimental)
|
|
333
|
+
WasmSerialModbusServerService.ts — wasmSerialRtuServerLayer / wasmSerialAsciiServerLayer (experimental)
|
|
276
334
|
examples/
|
|
277
335
|
rtu-basic.ts — RTU usage pattern
|
|
278
336
|
tcp-basic.ts — TCP usage pattern
|
|
@@ -283,6 +341,9 @@ examples/
|
|
|
283
341
|
ascii-mock.ts — ASCII with in-memory mock (error-case)
|
|
284
342
|
tcp-polling-stream.ts — TCP polling, reconnect, and stream
|
|
285
343
|
tcp-finalizer-reset.ts — TCP scope finalizer reset demo
|
|
344
|
+
tcp-server.ts — TCP server example
|
|
345
|
+
serial-server.ts — Serial RTU server example
|
|
346
|
+
wasm/ — Standalone runnable Vite app for the browser transports (own README, own npm project)
|
|
286
347
|
index.ts — Re-exports public API
|
|
287
348
|
```
|
|
288
349
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* # effect-modbus-rs
|
|
2
|
+
* # @flux-control/effect-modbus-rs
|
|
3
3
|
*
|
|
4
4
|
* Type-safe Modbus communication via Effect-TS, wrapping the `modbus-rs`
|
|
5
5
|
* npm bindings (Rust `napi-rs` under the hood).
|
|
@@ -11,6 +11,14 @@
|
|
|
11
11
|
* - {@link AsciiTransportService} — Serial ASCII transport.
|
|
12
12
|
* - {@link TcpTransportService} — TCP/IP transport (Modbus/TCP).
|
|
13
13
|
*
|
|
14
|
+
* ## Browser (WASM) transport services
|
|
15
|
+
*
|
|
16
|
+
* - {@link WasmSerialTransportService} — Abstract Web Serial transport (ASCII or RTU).
|
|
17
|
+
* - {@link WasmRtuTransportService} — Web Serial RTU transport.
|
|
18
|
+
* - {@link WasmAsciiTransportService} — Web Serial ASCII transport.
|
|
19
|
+
* - {@link WasmWsTransportService} — TCP-over-WebSocket transport (Modbus/TCP via a WS gateway).
|
|
20
|
+
* - {@link requestSerialPort} — Requests a Web Serial port handle (user-gesture gated).
|
|
21
|
+
*
|
|
14
22
|
* ## Server layers
|
|
15
23
|
*
|
|
16
24
|
* Run a server layer with {@link Layer.launch} and execute with a runtime:
|
|
@@ -23,6 +31,8 @@
|
|
|
23
31
|
* - {@link serialAsciiServerLayer} — Serial ASCII server.
|
|
24
32
|
* - {@link tcpServerLayer} — TCP server.
|
|
25
33
|
* - {@link tcpGatewayLayer} — TCP gateway.
|
|
34
|
+
* - {@link wasmWsServerLayer} — Browser WS-gateway server (experimental upstream surface).
|
|
35
|
+
* - {@link wasmSerialRtuServerLayer} / {@link wasmSerialAsciiServerLayer} — Browser Web Serial servers (experimental).
|
|
26
36
|
*
|
|
27
37
|
* ## Errors
|
|
28
38
|
*
|
|
@@ -36,14 +46,24 @@
|
|
|
36
46
|
* })
|
|
37
47
|
* ```
|
|
38
48
|
*
|
|
39
|
-
* @module effect-modbus-rs
|
|
49
|
+
* @module @flux-control/effect-modbus-rs
|
|
40
50
|
*/
|
|
41
|
-
export * from
|
|
42
|
-
export {
|
|
43
|
-
export {
|
|
44
|
-
export {
|
|
45
|
-
export {
|
|
46
|
-
export {
|
|
47
|
-
export {
|
|
48
|
-
export {
|
|
49
|
-
export
|
|
51
|
+
export * from './src/errors';
|
|
52
|
+
export type { EffectModbusClient } from './src/modbus-client';
|
|
53
|
+
export { AsciiTransportService } from './src/AsciiTransportService';
|
|
54
|
+
export { SerialTransportService } from './src/SerialTransportService';
|
|
55
|
+
export { TcpTransportService } from './src/TcpTransportService';
|
|
56
|
+
export { RtuTransportService } from './src/RtuTransportService';
|
|
57
|
+
export { serialRtuServerLayer, serialAsciiServerLayer } from './src/SerialModbusServerService';
|
|
58
|
+
export { tcpServerLayer } from './src/TcpModbusServerService';
|
|
59
|
+
export { tcpGatewayLayer } from './src/TcpGatewayService';
|
|
60
|
+
export { WasmWsTransportService } from './src/WasmWsTransportService';
|
|
61
|
+
export { WasmRtuTransportService } from './src/WasmRtuTransportService';
|
|
62
|
+
export type { WasmRtuTransportOpenOptions } from './src/WasmRtuTransportService';
|
|
63
|
+
export { WasmAsciiTransportService } from './src/WasmAsciiTransportService';
|
|
64
|
+
export type { WasmAsciiTransportOpenOptions } from './src/WasmAsciiTransportService';
|
|
65
|
+
export { WasmSerialTransportService } from './src/WasmSerialTransportService';
|
|
66
|
+
export { requestSerialPort } from './src/WasmSerialPort';
|
|
67
|
+
export { wasmWsServerLayer } from './src/WasmTcpServerService';
|
|
68
|
+
export { wasmSerialRtuServerLayer, wasmSerialAsciiServerLayer, } from './src/WasmSerialModbusServerService';
|
|
69
|
+
export type { CoilDefinition, DiscreteInputDefinition, RegisterDefinition, SlaveDeviceDefinition, SlaveDeviceDefinitions, } from './src/mocks';
|