@flux-control/effect-modbus-rs 0.7.0 → 0.8.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 +498 -831
- package/dist/index.d.ts +56 -113
- package/dist/index.js +235 -119
- package/dist/src/AsciiTransportService.d.ts +15 -14
- package/dist/src/RtuTransportService.d.ts +15 -14
- package/dist/src/SerialModbusServerService.d.ts +3 -2
- package/dist/src/SerialTransportService.d.ts +8 -2
- package/dist/src/TcpGatewayService.d.ts +2 -1
- package/dist/src/TcpModbusServerService.d.ts +2 -1
- package/dist/src/TcpTransportService.d.ts +7 -6
- package/dist/src/WasmAsciiTransportService.d.ts +14 -8
- package/dist/src/WasmRtuTransportService.d.ts +14 -8
- package/dist/src/WasmSerialModbusServerService.d.ts +4 -2
- package/dist/src/WasmSerialPort.d.ts +6 -4
- package/dist/src/WasmSerialTransportService.d.ts +9 -2
- package/dist/src/WasmTcpServerService.d.ts +2 -1
- package/dist/src/WasmWsTransportService.d.ts +10 -6
- package/dist/src/batching-client.d.ts +61 -28
- package/dist/src/connection.d.ts +6 -2
- package/dist/src/errors.d.ts +11 -12
- package/dist/src/mocks.d.ts +4 -3
- package/dist/src/modbus-client.d.ts +14 -10
- package/dist/src/read-debouncer.d.ts +8 -22
- package/dist/src/register-cache.d.ts +1 -7
- package/dist/src/register-plan.d.ts +2 -12
- package/dist/src/retry.d.ts +1 -0
- package/dist/src/serial-port-path.d.ts +21 -0
- package/dist/src/shared-transport.d.ts +33 -8
- package/dist/src/span-attributes.d.ts +1 -1
- package/dist/src/write-debouncer.d.ts +15 -49
- package/dist/test/native-transport.test.d.ts +1 -0
- package/dist/test/serial-port-path.test.d.ts +1 -0
- package/package.json +5 -5
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview
|
|
3
|
-
* ones a caller names.
|
|
4
|
-
*
|
|
5
|
-
* `withClient` returns an {@link EffectModbusClient}: it issues exactly the
|
|
6
|
-
* transaction asked for, and it is the right client when a caller knows what the
|
|
7
|
-
* bus should carry. This module is its sibling for the other case — a caller with
|
|
8
|
-
* one accessor per register, which knows what it wants to read and write but not
|
|
9
|
-
* what that ought to cost.
|
|
2
|
+
* @fileoverview Batching clients collect and plan register operations for a unit.
|
|
10
3
|
*
|
|
11
4
|
* @module
|
|
12
5
|
*/
|
|
@@ -82,13 +75,29 @@ export interface BatchingClientOptions {
|
|
|
82
75
|
}
|
|
83
76
|
/** Reads over one register space. */
|
|
84
77
|
export interface BatchingRegisterReader {
|
|
85
|
-
/**
|
|
78
|
+
/**
|
|
79
|
+
* Collects an address for the read window, then returns its value.
|
|
80
|
+
* @param address - Register address.
|
|
81
|
+
* @returns The register value, or a Modbus error.
|
|
82
|
+
*/
|
|
86
83
|
read(address: number): Effect.Effect<number, ModbusError>;
|
|
87
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* Adds an address and flushes collected reads immediately.
|
|
86
|
+
* @param address - Register address.
|
|
87
|
+
* @returns The register value, or a Modbus error.
|
|
88
|
+
*/
|
|
88
89
|
readNow(address: number): Effect.Effect<number, ModbusError>;
|
|
89
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* Collects a group as one reader and returns values in the requested order.
|
|
92
|
+
* @param addresses - Register addresses, in result order.
|
|
93
|
+
* @returns Register values in the requested order, or a Modbus error.
|
|
94
|
+
*/
|
|
90
95
|
readAll(addresses: ReadonlyArray<number>): Effect.Effect<ReadonlyArray<number>, ModbusError>;
|
|
91
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* Adds a group and flushes collected reads immediately.
|
|
98
|
+
* @param addresses - Register addresses, in result order.
|
|
99
|
+
* @returns Register values in the requested order, or a Modbus error.
|
|
100
|
+
*/
|
|
92
101
|
readAllNow(addresses: ReadonlyArray<number>): Effect.Effect<ReadonlyArray<number>, ModbusError>;
|
|
93
102
|
}
|
|
94
103
|
/**
|
|
@@ -111,13 +120,37 @@ export interface BatchingRegisterReader {
|
|
|
111
120
|
export interface BatchingModbusClient extends BatchingRegisterReader {
|
|
112
121
|
/** The unit this client addresses. */
|
|
113
122
|
readonly unitId: number;
|
|
114
|
-
/**
|
|
123
|
+
/**
|
|
124
|
+
* Holds a write for the write window, then issues it with other pending writes.
|
|
125
|
+
* Completion means the carrying batch succeeded; a cache can suppress its bus write.
|
|
126
|
+
* @param write - Register address and value.
|
|
127
|
+
* @param attributes - Optional span attributes for this caller.
|
|
128
|
+
* @returns Completion after the carrying batch succeeds, or its Modbus error.
|
|
129
|
+
*/
|
|
115
130
|
write(write: RegisterWrite, attributes?: ModbusSpanAttributes): Effect.Effect<void, ModbusError>;
|
|
116
|
-
/**
|
|
131
|
+
/**
|
|
132
|
+
* Adds a write and flushes pending writes immediately. The newest value wins.
|
|
133
|
+
* Completion means the carrying batch succeeded; a cache can suppress its bus write.
|
|
134
|
+
* @param write - Register address and value.
|
|
135
|
+
* @param attributes - Optional span attributes for this caller.
|
|
136
|
+
* @returns Completion after the carrying batch succeeds, or its Modbus error.
|
|
137
|
+
*/
|
|
117
138
|
writeNow(write: RegisterWrite, attributes?: ModbusSpanAttributes): Effect.Effect<void, ModbusError>;
|
|
118
|
-
/**
|
|
139
|
+
/**
|
|
140
|
+
* Submits the group to the write debouncer as one caller.
|
|
141
|
+
* Completion reports its flush result; cache filtering can suppress physical writes.
|
|
142
|
+
* @param writes - Register writes.
|
|
143
|
+
* @param attributes - Optional span attributes for this caller.
|
|
144
|
+
* @returns Completion after the carrying batch succeeds, or its Modbus error.
|
|
145
|
+
*/
|
|
119
146
|
writeAll(writes: ReadonlyArray<RegisterWrite>, attributes?: ModbusSpanAttributes): Effect.Effect<void, ModbusError>;
|
|
120
|
-
/**
|
|
147
|
+
/**
|
|
148
|
+
* Adds a group of writes and flushes pending writes immediately.
|
|
149
|
+
* Completion means the carrying batch succeeded; a cache can suppress bus writes.
|
|
150
|
+
* @param writes - Register writes.
|
|
151
|
+
* @param attributes - Optional span attributes for this caller.
|
|
152
|
+
* @returns Completion after the carrying batch succeeds, or its Modbus error.
|
|
153
|
+
*/
|
|
121
154
|
writeAllNow(writes: ReadonlyArray<RegisterWrite>, attributes?: ModbusSpanAttributes): Effect.Effect<void, ModbusError>;
|
|
122
155
|
/** Reads over the input registers (FC04). The unqualified reads are holding registers (FC03). */
|
|
123
156
|
readonly inputs: BatchingRegisterReader;
|
|
@@ -140,17 +173,17 @@ export interface BatchingModbusClient extends BatchingRegisterReader {
|
|
|
140
173
|
*/
|
|
141
174
|
readonly debounce: BatchingDebounceWindows | undefined;
|
|
142
175
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
176
|
+
* Registers an action for the calling scope's finalization.
|
|
177
|
+
* Keep the transport open until that scope closes.
|
|
178
|
+
*
|
|
179
|
+
* The application selects the shutdown value. Use an immediate write method
|
|
180
|
+
* to avoid waiting for a collection window during cleanup.
|
|
145
181
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* addresses it, rather than dispatched from one action over a set of units.
|
|
182
|
+
* An unhandled failure is logged and raised as a defect. Other finalizers
|
|
183
|
+
* still run. Wrap the action in `Effect.ignoreLogged` to accept its failure.
|
|
149
184
|
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* the bus its turn. Wrap the action in `Effect.ignoreLogged` to accept the
|
|
153
|
-
* failure instead.
|
|
185
|
+
* @param action - Shutdown action to run before client teardown.
|
|
186
|
+
* @returns An effect that registers the action in the calling scope.
|
|
154
187
|
*
|
|
155
188
|
* @example
|
|
156
189
|
* const damper = yield* transport.withBatchingClient(3);
|
|
@@ -165,7 +198,7 @@ export interface BatchingModbusClient extends BatchingRegisterReader {
|
|
|
165
198
|
* normally meets it. Call it directly to drive a client this package did not
|
|
166
199
|
* hand out, such as another adapter implementing `EffectModbusClient`, or a stub.
|
|
167
200
|
*
|
|
168
|
-
* @param options -
|
|
201
|
+
* @param options - Unit, client, cache or `undefined`, debounce windows, and planner limits.
|
|
169
202
|
* @returns The batching client, bound to the current scope.
|
|
170
203
|
*/
|
|
171
204
|
export declare const makeBatchingClient: (options: {
|
|
@@ -222,7 +255,7 @@ export interface BatchingRegistry {
|
|
|
222
255
|
* `withBatchingClient` declares. `batchingClient` looks up, and waits for a
|
|
223
256
|
* declaration already under way rather than depending on which fiber ran first.
|
|
224
257
|
*
|
|
225
|
-
* @param deps -
|
|
226
|
-
* @returns
|
|
258
|
+
* @param deps - Raw client factory, link state, and transport scope.
|
|
259
|
+
* @returns Registry methods for declaring and retrieving per-unit clients.
|
|
227
260
|
*/
|
|
228
261
|
export declare const createBatchingRegistry: (deps: BatchingRegistryDeps) => BatchingRegistry;
|
package/dist/src/connection.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** Models transport connection state and supervised reconnection with a circuit guard. */
|
|
1
2
|
import { Data, Duration, Effect, type Scope, SubscriptionRef } from 'effect';
|
|
2
3
|
import { ModbusCircuitOpenError, type ModbusError } from './errors';
|
|
3
4
|
import { type ModbusErrorTag, type ModbusRetryPolicy } from './retry';
|
|
@@ -5,7 +6,7 @@ import { type ModbusErrorTag, type ModbusRetryPolicy } from './retry';
|
|
|
5
6
|
* Live connection state of a transport.
|
|
6
7
|
*
|
|
7
8
|
* Owned by the transport and published through
|
|
8
|
-
*
|
|
9
|
+
* `transport.connectionState`, so an application can show link
|
|
9
10
|
* status without inferring it from failed reads.
|
|
10
11
|
*
|
|
11
12
|
* - `Disconnected` — never opened, or closed. Operations open it lazily.
|
|
@@ -143,7 +144,10 @@ export interface ResolvedReconnect {
|
|
|
143
144
|
readonly resetAfter: Duration.Duration;
|
|
144
145
|
readonly triggers: (error: ModbusError) => boolean;
|
|
145
146
|
}
|
|
146
|
-
/** Applies defaults to
|
|
147
|
+
/** Applies defaults to reconnection options.
|
|
148
|
+
* @param options - Optional policy, reset interval, and trigger tags.
|
|
149
|
+
* @returns Resolved policy, reset duration, and failure predicate.
|
|
150
|
+
*/
|
|
147
151
|
export declare const resolveReconnect: (options: ReconnectOptions) => ResolvedReconnect;
|
|
148
152
|
/**
|
|
149
153
|
* Refuses an operation while the link is being re-established.
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -27,8 +27,7 @@ declare const ModbusTimeoutError_base: new <A extends Record<string, any> = {}>(
|
|
|
27
27
|
*
|
|
28
28
|
* Mapped from {@link ModbusErrorCode.TIMEOUT} via `modbus-rs`.
|
|
29
29
|
* Adjust timeouts via `setRequestTimeout` on the transport, or configure
|
|
30
|
-
* with
|
|
31
|
-
* {@link RtuTransportOptions.responseTimeoutMs | responseTimeoutMs}.
|
|
30
|
+
* with `requestTimeoutMs` or `responseTimeoutMs`, where the binding supports them.
|
|
32
31
|
*
|
|
33
32
|
* The transport also raises this error locally when an operation waits for an
|
|
34
33
|
* open or reconnect longer than the `connectTimeout` transport option.
|
|
@@ -122,9 +121,8 @@ declare const ModbusNotConnectedError_base: new <A extends Record<string, any> =
|
|
|
122
121
|
* connection was established or after it was closed.
|
|
123
122
|
*
|
|
124
123
|
* This is a **local** error — it is never returned by `modbus-rs`.
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* successful connection.
|
|
124
|
+
* Timeout setters require an open connection. Client acquisition opens the
|
|
125
|
+
* connection lazily, but fails after the transport scope has closed.
|
|
128
126
|
*
|
|
129
127
|
* Connect by calling `withClient(unitId)` on the transport service.
|
|
130
128
|
* The connection is established lazily on the first call.
|
|
@@ -147,11 +145,10 @@ declare const ModbusCircuitOpenError_base: new <A extends Record<string, any> =
|
|
|
147
145
|
* so the request was refused without touching the wire.
|
|
148
146
|
*
|
|
149
147
|
* This is a **local** error — it is never returned by `modbus-rs`. It is raised
|
|
150
|
-
* by the transport when its
|
|
151
|
-
*
|
|
148
|
+
* by the transport when supervision is enabled and its state is `Reconnecting`
|
|
149
|
+
* or `Down`. Refused operations do not send a request to the device.
|
|
152
150
|
*
|
|
153
|
-
*
|
|
154
|
-
* cheaply, since each refused attempt costs nothing on the bus.
|
|
151
|
+
* Retry policies retry this error by default within their configured budgets.
|
|
155
152
|
*
|
|
156
153
|
* @see ConnectionState — The transport state that produces this error.
|
|
157
154
|
*/
|
|
@@ -199,9 +196,10 @@ export declare class ModbusUnitAlreadyDeclaredError extends ModbusUnitAlreadyDec
|
|
|
199
196
|
}> {
|
|
200
197
|
}
|
|
201
198
|
/**
|
|
202
|
-
* Union of
|
|
199
|
+
* Union of typed operation and connection errors.
|
|
200
|
+
* Declaration errors are separate from this union.
|
|
203
201
|
*
|
|
204
|
-
* Handle with
|
|
202
|
+
* Handle with `Effect.catchTags`:
|
|
205
203
|
*
|
|
206
204
|
* ```ts
|
|
207
205
|
* Effect.catchTags(client.readHoldingRegisters({ address: 0, quantity: 10 }), {
|
|
@@ -211,7 +209,8 @@ export declare class ModbusUnitAlreadyDeclaredError extends ModbusUnitAlreadyDec
|
|
|
211
209
|
* })
|
|
212
210
|
* ```
|
|
213
211
|
*
|
|
214
|
-
*
|
|
212
|
+
* Binding failures map from {@link ModbusErrorCode}. Local guards can also
|
|
213
|
+
* produce errors in this union.
|
|
215
214
|
*
|
|
216
215
|
* @see ModbusErrorCode — The upstream error code enum driving this mapping.
|
|
217
216
|
*/
|
package/dist/src/mocks.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** Defines in-memory Modbus device schemas and mock transports for deterministic tests. */
|
|
1
2
|
import { Effect, Schema, Scope, SubscriptionRef } from 'effect';
|
|
2
3
|
import { type AsciiTransportOptions, type RtuTransportOptions, type TcpTransportOptions } from 'modbus-rs';
|
|
3
4
|
import type { WasmWsTransportOptions, WasmSerialTransportOptions } from 'modbus-rs/web';
|
|
@@ -133,8 +134,8 @@ export type SlaveDeviceDefinitions = Schema.Schema.Type<typeof SlaveDeviceDefini
|
|
|
133
134
|
* {@link ModbusInvalidArgumentError}.
|
|
134
135
|
*
|
|
135
136
|
* @param devices - Array of slave device definitions to simulate.
|
|
136
|
-
* @returns A transport
|
|
137
|
-
*
|
|
137
|
+
* @returns A factory that accepts transport and fault options and returns the mock transport Effect.
|
|
138
|
+
* @throws A schema decode error when `devices` does not match the device-definition schema.
|
|
138
139
|
*/
|
|
139
140
|
export declare const createMockTransport: (devices: SlaveDeviceDefinitions) => (options: (WithoutUpstreamRetry<RtuTransportOptions> | WithoutUpstreamRetry<AsciiTransportOptions> | WithoutUpstreamRetry<TcpTransportOptions> | WasmWsTransportOptions | WasmSerialTransportOptions) & TransportResilienceOptions & MockFaultOptions) => Effect.Effect<{
|
|
140
141
|
connectionState: SubscriptionRef.SubscriptionRef<{
|
|
@@ -159,6 +160,6 @@ export declare const createMockTransport: (devices: SlaveDeviceDefinitions) => (
|
|
|
159
160
|
setRequestTimeout: (_timeoutMs: number) => Effect.Effect<void, ModbusNotConnectedError, never>;
|
|
160
161
|
clearRequestTimeout: () => Effect.Effect<void, ModbusNotConnectedError, never>;
|
|
161
162
|
reconnect: () => Effect.Effect<void, ModbusError, never>;
|
|
162
|
-
close: () => Effect.Effect<void, never,
|
|
163
|
+
close: (scope: Scope.Closeable) => Effect.Effect<void, never, never>;
|
|
163
164
|
hasPendingRequests: () => false;
|
|
164
165
|
}, never, Scope.Scope>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** Adapts native and WASM Modbus clients to typed Effect operations and transport resilience. */
|
|
1
2
|
import { Effect } from 'effect';
|
|
2
3
|
import type { ReadRegistersOptions, WriteSingleRegisterOptions, WriteMultipleRegistersOptions, ReadWriteMultipleRegistersOptions, ReadBitsOptions, WriteSingleCoilOptions, WriteMultipleCoilsOptions, ReadFifoQueueOptions, ReadFileRecordOptions, WriteFileRecordOptions, DiagnosticsOptions, ReadDeviceIdentificationOptions, FifoQueueResponse, DiagnosticsResponse, DeviceIdentificationResponse, AsyncSerialModbusClient, AsyncTcpModbusClient, CoilState } from 'modbus-rs';
|
|
3
4
|
import type { WasmWsModbusClient, WasmSerialModbusClient } from 'modbus-rs/web';
|
|
@@ -9,6 +10,8 @@ export type NativeModbusClient = AsyncSerialModbusClient | AsyncTcpModbusClient;
|
|
|
9
10
|
export type WasmModbusClient = WasmSerialModbusClient | WasmWsModbusClient;
|
|
10
11
|
/** Any client this package knows how to wrap into an {@link EffectModbusClient}. */
|
|
11
12
|
export type AnyModbusClient = NativeModbusClient | WasmModbusClient;
|
|
13
|
+
/** Wraps one native call. A transport uses it to control when a request reaches the native queue. */
|
|
14
|
+
export type NativeCallWrapper = <T>(call: Effect.Effect<T, ModbusError>) => Effect.Effect<T, ModbusError>;
|
|
12
15
|
/**
|
|
13
16
|
* The Modbus function-code surface, before any resilience is layered on.
|
|
14
17
|
*
|
|
@@ -64,10 +67,10 @@ export interface ModbusOperations {
|
|
|
64
67
|
*/
|
|
65
68
|
writeMultipleRegisters(opts: WriteMultipleRegistersOptions): Effect.Effect<void, ModbusError>;
|
|
66
69
|
/**
|
|
67
|
-
*
|
|
70
|
+
* Writes and reads multiple registers within one request (FC23).
|
|
68
71
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
72
|
+
* The device performs the write before the read. This does not make separate
|
|
73
|
+
* application operations atomic.
|
|
71
74
|
*
|
|
72
75
|
* @param opts - Separate read and write addresses/quantities/values.
|
|
73
76
|
* @returns An Effect resolving to the read register values.
|
|
@@ -79,7 +82,7 @@ export interface ModbusOperations {
|
|
|
79
82
|
* Reads coils (digital outputs) from the Modbus device (FC01).
|
|
80
83
|
*
|
|
81
84
|
* @param opts - Starting address, quantity, and optional `AbortSignal`.
|
|
82
|
-
* @returns An Effect resolving to
|
|
85
|
+
* @returns An Effect resolving to `CoilState` values.
|
|
83
86
|
*
|
|
84
87
|
* @see ReadBitsOptions — Options shape from `modbus-rs`.
|
|
85
88
|
*/
|
|
@@ -87,7 +90,7 @@ export interface ModbusOperations {
|
|
|
87
90
|
/**
|
|
88
91
|
* Writes a single coil (digital output) (FC05).
|
|
89
92
|
*
|
|
90
|
-
* @param opts - Coil address,
|
|
93
|
+
* @param opts - Coil address, `CoilState` value, and optional `AbortSignal`.
|
|
91
94
|
* @returns An Effect that completes when the write is acknowledged.
|
|
92
95
|
*
|
|
93
96
|
* @see WriteSingleCoilOptions — Options shape from `modbus-rs`.
|
|
@@ -96,7 +99,7 @@ export interface ModbusOperations {
|
|
|
96
99
|
/**
|
|
97
100
|
* Writes multiple consecutive coils (FC15).
|
|
98
101
|
*
|
|
99
|
-
* @param opts - Starting address, array of
|
|
102
|
+
* @param opts - Starting address, array of `CoilState` values, and optional `AbortSignal`.
|
|
100
103
|
* @returns An Effect that completes when the write is acknowledged.
|
|
101
104
|
*
|
|
102
105
|
* @see WriteMultipleCoilsOptions — Options shape from `modbus-rs`.
|
|
@@ -106,7 +109,7 @@ export interface ModbusOperations {
|
|
|
106
109
|
* Reads discrete inputs (digital inputs) from the Modbus device (FC02).
|
|
107
110
|
*
|
|
108
111
|
* @param opts - Starting address, quantity, and optional `AbortSignal`.
|
|
109
|
-
* @returns An Effect resolving to
|
|
112
|
+
* @returns An Effect resolving to `CoilState` values.
|
|
110
113
|
*
|
|
111
114
|
* @see ReadBitsOptions — Options shape from `modbus-rs`.
|
|
112
115
|
*/
|
|
@@ -182,13 +185,12 @@ export interface ModbusOperations {
|
|
|
182
185
|
* transport-specific reshaping is needed.
|
|
183
186
|
*
|
|
184
187
|
* @param client - The upstream `modbus-rs` or `modbus-rs/web` client instance.
|
|
185
|
-
* @returns
|
|
186
|
-
* workflows.
|
|
188
|
+
* @returns A client whose methods return typed Effects.
|
|
187
189
|
*
|
|
188
190
|
* @see AsyncSerialModbusClient — Upstream native serial client API.
|
|
189
191
|
* @see AsyncTcpModbusClient — Upstream native TCP client API.
|
|
190
192
|
*/
|
|
191
|
-
export declare const createEffectModbusClient: (client: AnyModbusClient) => ModbusOperations;
|
|
193
|
+
export declare const createEffectModbusClient: (client: AnyModbusClient | Effect.Effect<AnyModbusClient, ModbusError>, around?: NativeCallWrapper) => ModbusOperations;
|
|
192
194
|
/**
|
|
193
195
|
* Transport-owned resilience applied to every operation of a client.
|
|
194
196
|
*
|
|
@@ -197,6 +199,8 @@ export declare const createEffectModbusClient: (client: AnyModbusClient) => Modb
|
|
|
197
199
|
* reconnect serves every client derived from it.
|
|
198
200
|
*/
|
|
199
201
|
export interface ClientResilience {
|
|
202
|
+
/** Protects the guard, native call, and failure report as one transport attempt. */
|
|
203
|
+
readonly aroundAttempt?: NativeCallWrapper;
|
|
200
204
|
/** Refuses the operation while the transport's circuit is open. */
|
|
201
205
|
readonly guard: Effect.Effect<void, ModbusError>;
|
|
202
206
|
/** Records that an operation reached the device successfully. */
|
|
@@ -1,19 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Collects register reads
|
|
3
|
-
*
|
|
4
|
-
* `planReads` merges the addresses a caller holds at one moment. A caller with an
|
|
5
|
-
* accessor per parameter never holds two addresses at the same moment, so a
|
|
6
|
-
* planner alone would force every such caller to be rewritten around a batch API.
|
|
7
|
-
*
|
|
8
|
-
* This module collects the addresses on time instead, so a caller keeps its
|
|
9
|
-
* per-parameter accessors and still gets one transaction per span.
|
|
10
|
-
*
|
|
11
|
-
* The read debouncer is deliberately simpler than the write debouncer. There is
|
|
12
|
-
* no supersede rule, because a second request for an address is not a newer
|
|
13
|
-
* value, it is a second reader. There is no cache, because this package records
|
|
14
|
-
* only what it wrote. There is no ceiling on the hold, because the window does
|
|
15
|
-
* not restart: it opens on the first arrival of a batch and expires on time,
|
|
16
|
-
* which a stream of arrivals can never push out.
|
|
2
|
+
* @fileoverview Collects concurrent register reads and plans them into spans.
|
|
3
|
+
* The first request starts a fixed collection window; later requests do not restart it.
|
|
17
4
|
*
|
|
18
5
|
* @module
|
|
19
6
|
*/
|
|
@@ -25,10 +12,9 @@ export interface ReadDebouncerOptions {
|
|
|
25
12
|
/**
|
|
26
13
|
* How long addresses are collected before the spans are read.
|
|
27
14
|
*
|
|
28
|
-
* The
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* longer than one delays every reader for a batch it did not need.
|
|
15
|
+
* The first arrival starts the window. Later arrivals do not restart it.
|
|
16
|
+
* Compare the window with measured transaction time when selecting a value.
|
|
17
|
+
* Device response time adds to the collection delay.
|
|
32
18
|
*
|
|
33
19
|
* A window of zero disables the debouncer: every read is issued on its own,
|
|
34
20
|
* with no timer and no batch.
|
|
@@ -52,8 +38,8 @@ export interface ReadDebouncer {
|
|
|
52
38
|
/**
|
|
53
39
|
* Adds an address to the batch and reads immediately, rather than waiting.
|
|
54
40
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
41
|
+
* The flush includes readers already collected. Its plan can require several
|
|
42
|
+
* transactions, and their results are delivered to the waiting readers.
|
|
57
43
|
*/
|
|
58
44
|
readNow(address: number): Effect.Effect<number, ModbusError>;
|
|
59
45
|
/**
|
|
@@ -87,7 +73,7 @@ export interface ReadDebouncer {
|
|
|
87
73
|
* When the scope closes, readers still waiting are interrupted.
|
|
88
74
|
*
|
|
89
75
|
* @param options - The window, the planner limits, and the callback that reads.
|
|
90
|
-
* @returns The debouncer.
|
|
76
|
+
* @returns The scoped debouncer. Waiting readers are interrupted when its scope closes.
|
|
91
77
|
*
|
|
92
78
|
* @example
|
|
93
79
|
* const debouncer = yield* createReadDebouncer({
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview
|
|
3
|
-
* that would change nothing.
|
|
4
|
-
*
|
|
5
|
-
* A caller that recomputes an output on every cycle proposes the same value most
|
|
6
|
-
* of the time. In steady state roughly four out of five proposals are a repeat of
|
|
7
|
-
* what the register already holds, and on a half-duplex bus each one costs a
|
|
8
|
-
* turnaround that carries no information.
|
|
2
|
+
* @fileoverview Tracks acknowledged register values to suppress unchanged writes.
|
|
9
3
|
*
|
|
10
4
|
* @module
|
|
11
5
|
*/
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Pure
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* A caller that derives each register independently — one fiber per output, one
|
|
6
|
-
* accessor per parameter — naturally produces one transaction per register. On a
|
|
7
|
-
* half-duplex multi-drop bus that is the dominant cost: every transaction is a
|
|
8
|
-
* turnaround, and the registers a caller wants are usually neighbours.
|
|
9
|
-
*
|
|
10
|
-
* These functions hold no state, run no I/O, and return no `Effect`. They are the
|
|
11
|
-
* bottom layer of the batching stack and are usable on their own — a caller that
|
|
12
|
-
* already owns its scheduling can plan the transactions here and issue them with
|
|
13
|
-
* a plain {@link EffectModbusClient}.
|
|
2
|
+
* @fileoverview Pure functions that plan register reads and writes as Modbus transactions.
|
|
3
|
+
* They do not perform I/O or return Effects.
|
|
14
4
|
*
|
|
15
5
|
* @module
|
|
16
6
|
*/
|
package/dist/src/retry.d.ts
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
/** Maximum serial path length in the native 0.16.2 binding. */
|
|
3
|
+
export declare const MAX_SERIAL_PORT_PATH = 128;
|
|
4
|
+
/**
|
|
5
|
+
* Gives a serial port path that `modbus-rs` accepts.
|
|
6
|
+
*
|
|
7
|
+
* Stable device links, such as `/dev/serial/by-id/...`, can be longer than
|
|
8
|
+
* {@link MAX_SERIAL_PORT_PATH}. Such a link points to a short device path,
|
|
9
|
+
* so a long path is replaced with its target. This function resolves one
|
|
10
|
+
* snapshot. Transport services keep a short alias to the configured path for reconnects.
|
|
11
|
+
*
|
|
12
|
+
* @param portPath - The configured serial port path.
|
|
13
|
+
* @returns The configured path, or the target of a long path.
|
|
14
|
+
* @throws An error with the `MODBUS_INVALID_ARGUMENT` code when the path and
|
|
15
|
+
* its target are both too long. The same error occurs when a long link has
|
|
16
|
+
* no target, for example while its device is unplugged. Retry policies do
|
|
17
|
+
* not retry this error. A later open succeeds after the device returns.
|
|
18
|
+
*/
|
|
19
|
+
export declare const resolveSerialPortPath: (portPath: string) => Promise<string>;
|
|
20
|
+
/** Keeps a short alias in the transport scope. Its target remains the configured stable link. */
|
|
21
|
+
export declare const serialPortPathScoped: (portPath: string) => Effect.Effect<() => Promise<string>, never, import("effect/Scope").Scope>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** Provides scoped lifecycle, lazy connection, client caching, and optional transport resilience. */
|
|
1
2
|
import { Duration, Effect, Scope, SubscriptionRef } from 'effect';
|
|
2
3
|
import type { AsyncAsciiTransport, AsyncRtuTransport, AsyncTcpTransport } from 'modbus-rs';
|
|
3
4
|
import type { WasmAsciiTransport, WasmRtuTransport, WasmWsTransport } from 'modbus-rs/web';
|
|
@@ -32,7 +33,7 @@ export interface TransportResilienceOptions {
|
|
|
32
33
|
* host that does not answer waits until the operating system stops it, which
|
|
33
34
|
* takes about 2 minutes on Linux with default settings.
|
|
34
35
|
*
|
|
35
|
-
* The limit applies to each caller that waits for an open or reconnect.
|
|
36
|
+
* The limit applies independently to each caller that waits for an open or reconnect.
|
|
36
37
|
* When it expires, that caller fails with {@link ModbusTimeoutError}.
|
|
37
38
|
*
|
|
38
39
|
* The native connect cannot be cancelled, so it continues. Later callers wait
|
|
@@ -103,6 +104,7 @@ export interface TransportServiceApi {
|
|
|
103
104
|
*
|
|
104
105
|
* @param unitId - Modbus unit ID to address.
|
|
105
106
|
* @param options - Per-client policy replacing the transport default.
|
|
107
|
+
* @returns An Effect that succeeds with the client or fails with a Modbus error.
|
|
106
108
|
*/
|
|
107
109
|
withClient(unitId: number, options?: {
|
|
108
110
|
readonly retry?: ModbusRetryPolicy;
|
|
@@ -119,9 +121,17 @@ export interface TransportServiceApi {
|
|
|
119
121
|
* ```
|
|
120
122
|
*/
|
|
121
123
|
readonly connectionState: SubscriptionRef.SubscriptionRef<ConnectionState>;
|
|
122
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* Sets native response and admission limits in milliseconds.
|
|
126
|
+
* @param timeoutMs - Request timeout in milliseconds.
|
|
127
|
+
* @returns An Effect that completes after the timeout is set, or fails if the transport is not connected.
|
|
128
|
+
*/
|
|
123
129
|
setRequestTimeout(timeoutMs: number): Effect.Effect<void, ModbusError>;
|
|
124
|
-
/**
|
|
130
|
+
/**
|
|
131
|
+
* Clears native response and admission limits. Fails if not connected.
|
|
132
|
+
* Interruption of an unbounded serial call closes its handle. Later operations reopen it lazily.
|
|
133
|
+
* @returns An Effect that completes after the limits are cleared, or fails if the transport is not connected.
|
|
134
|
+
*/
|
|
125
135
|
clearRequestTimeout(): Effect.Effect<void, ModbusError>;
|
|
126
136
|
/**
|
|
127
137
|
* Reconnects the transport. Opens lazily if no prior connection exists.
|
|
@@ -130,10 +140,19 @@ export interface TransportServiceApi {
|
|
|
130
140
|
* flight join it rather than starting another, and all of them observe its
|
|
131
141
|
* result. Fails with `ModbusNotConnectedError` if the transport was closed
|
|
132
142
|
* while the reconnect was running.
|
|
143
|
+
* @returns An Effect that completes when the transport is open or reconnected, or fails on connection error.
|
|
133
144
|
*/
|
|
134
145
|
reconnect(): Effect.Effect<void, ModbusError>;
|
|
135
|
-
/**
|
|
136
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Closes `scope`, then closes the transport.
|
|
148
|
+
*
|
|
149
|
+
* Pass the scope that holds the work to finish first, such as
|
|
150
|
+
* `onShutdown` writes. The transport closes even if a finalizer fails.
|
|
151
|
+
*
|
|
152
|
+
* @param scope - Caller scope to finalize before closing the connection.
|
|
153
|
+
* @returns An Effect that finalizes the caller scope and attempts transport closure.
|
|
154
|
+
*/
|
|
155
|
+
close(scope: Scope.Closeable): Effect.Effect<void, ModbusError>;
|
|
137
156
|
/**
|
|
138
157
|
* Declares the {@link BatchingModbusClient} for a unit.
|
|
139
158
|
*
|
|
@@ -157,6 +176,7 @@ export interface TransportServiceApi {
|
|
|
157
176
|
*
|
|
158
177
|
* @param unitId - Modbus unit ID to address.
|
|
159
178
|
* @param options - The cache, the windows, and the planner limits.
|
|
179
|
+
* @returns An Effect that succeeds with the client or fails with a Modbus or declaration error.
|
|
160
180
|
*/
|
|
161
181
|
withBatchingClient(unitId: number, options?: BatchingClientOptions & {
|
|
162
182
|
readonly retry?: ModbusRetryPolicy;
|
|
@@ -169,6 +189,7 @@ export interface TransportServiceApi {
|
|
|
169
189
|
* which fiber ran first.
|
|
170
190
|
*
|
|
171
191
|
* @param unitId - Modbus unit ID to address.
|
|
192
|
+
* @returns An Effect that succeeds with the declared client, or fails if no declaration exists.
|
|
172
193
|
*/
|
|
173
194
|
batchingClient(unitId: number): Effect.Effect<BatchingModbusClient, ModbusError>;
|
|
174
195
|
/**
|
|
@@ -202,7 +223,7 @@ type TransportConstructorName = 'AsyncAsciiTransport' | 'AsyncRtuTransport' | 'A
|
|
|
202
223
|
* lifecycle, client caching, timeouts, and reconnection.
|
|
203
224
|
*
|
|
204
225
|
* The transport is opened lazily on the first `withClient()` call and
|
|
205
|
-
* automatically closed when the consuming
|
|
226
|
+
* automatically closed when the consuming scope
|
|
206
227
|
* finalizes via `Effect.addFinalizer`.
|
|
207
228
|
*
|
|
208
229
|
* @typeParam TOptions - Transport options (e.g. `RtuTransportOptions`).
|
|
@@ -213,11 +234,15 @@ type TransportConstructorName = 'AsyncAsciiTransport' | 'AsyncRtuTransport' | 'A
|
|
|
213
234
|
* returning a promise for the opened transport.
|
|
214
235
|
* @param serviceName - Logical name used in log messages and the finalizer guard.
|
|
215
236
|
* @param config - Optional module specifier override for browser WASM transports.
|
|
216
|
-
* @returns
|
|
237
|
+
* @returns A scoped service constructor that produces a {@link TransportServiceApi}.
|
|
217
238
|
*/
|
|
218
239
|
export declare function createTransportScoped<TOptions, TClient extends AnyModbusClient, TTransport extends TransportHandle<TClient>>(transportKey: TransportConstructorName, openMethod: (TC: TransportConstructor, options: TOptions) => Promise<TTransport>, serviceName: string, config?: {
|
|
219
240
|
/** Which `modbus-rs` conditional export to import from. Defaults to `"modbus-rs"` (native). */
|
|
220
241
|
moduleSpecifier?: 'modbus-rs' | 'modbus-rs/web';
|
|
242
|
+
/** Keeps serial calls and reconnects outside an in-flight native call. TCP and WASM do not use it. */
|
|
243
|
+
serializeRequests?: boolean;
|
|
244
|
+
/** Reads the initial serial response limit. Native 0.16.2 defaults to 1000 ms. */
|
|
245
|
+
responseTimeoutMs?: (options: TOptions) => number | undefined;
|
|
221
246
|
}): (options: TOptions & TransportResilienceOptions) => Effect.Effect<{
|
|
222
247
|
connectionState: SubscriptionRef.SubscriptionRef<{
|
|
223
248
|
readonly _tag: "Connected";
|
|
@@ -236,7 +261,7 @@ export declare function createTransportScoped<TOptions, TClient extends AnyModbu
|
|
|
236
261
|
setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, ModbusNotConnectedError, never>;
|
|
237
262
|
clearRequestTimeout: () => Effect.Effect<undefined, ModbusNotConnectedError, never>;
|
|
238
263
|
reconnect: () => Effect.Effect<undefined, ModbusError, never>;
|
|
239
|
-
close: () => Effect.Effect<void, ModbusError,
|
|
264
|
+
close: (scope: Scope.Closeable) => Effect.Effect<void, ModbusError, never>;
|
|
240
265
|
withBatchingClient: (unitId: number, options?: BatchingClientOptions & {
|
|
241
266
|
readonly retry?: ModbusRetryPolicy;
|
|
242
267
|
}) => Effect.Effect<BatchingModbusClient, ModbusError | ModbusUnitAlreadyDeclaredError>;
|