@ya-modbus/transport 0.9.0 → 0.10.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +68 -0
  3. package/dist/cjs/src/connection.d.ts +90 -0
  4. package/dist/cjs/src/connection.d.ts.map +1 -0
  5. package/dist/cjs/src/connection.js +217 -0
  6. package/dist/cjs/src/connection.js.map +1 -0
  7. package/dist/cjs/src/create-modbus-transport.d.ts +4 -2
  8. package/dist/cjs/src/create-modbus-transport.d.ts.map +1 -1
  9. package/dist/cjs/src/create-modbus-transport.js +29 -28
  10. package/dist/cjs/src/create-modbus-transport.js.map +1 -1
  11. package/dist/cjs/src/factory.d.ts +2 -2
  12. package/dist/cjs/src/factory.js +12 -12
  13. package/dist/cjs/src/factory.js.map +1 -1
  14. package/dist/cjs/src/index.d.ts +1 -0
  15. package/dist/cjs/src/index.d.ts.map +1 -1
  16. package/dist/cjs/src/index.js +4 -1
  17. package/dist/cjs/src/index.js.map +1 -1
  18. package/dist/cjs/src/manager.d.ts +10 -0
  19. package/dist/cjs/src/manager.d.ts.map +1 -1
  20. package/dist/cjs/src/manager.js +18 -6
  21. package/dist/cjs/src/manager.js.map +1 -1
  22. package/dist/cjs/src/rtu-transport.d.ts +4 -0
  23. package/dist/cjs/src/rtu-transport.d.ts.map +1 -1
  24. package/dist/cjs/src/rtu-transport.js +19 -10
  25. package/dist/cjs/src/rtu-transport.js.map +1 -1
  26. package/dist/cjs/src/slave-transport.d.ts +10 -5
  27. package/dist/cjs/src/slave-transport.d.ts.map +1 -1
  28. package/dist/cjs/src/slave-transport.js +42 -39
  29. package/dist/cjs/src/slave-transport.js.map +1 -1
  30. package/dist/cjs/src/tcp-transport.d.ts +3 -0
  31. package/dist/cjs/src/tcp-transport.d.ts.map +1 -1
  32. package/dist/cjs/src/tcp-transport.js +14 -5
  33. package/dist/cjs/src/tcp-transport.js.map +1 -1
  34. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  35. package/dist/esm/src/connection.d.ts +90 -0
  36. package/dist/esm/src/connection.d.ts.map +1 -0
  37. package/dist/esm/src/connection.js +211 -0
  38. package/dist/esm/src/connection.js.map +1 -0
  39. package/dist/esm/src/create-modbus-transport.d.ts +4 -2
  40. package/dist/esm/src/create-modbus-transport.d.ts.map +1 -1
  41. package/dist/esm/src/create-modbus-transport.js +29 -28
  42. package/dist/esm/src/create-modbus-transport.js.map +1 -1
  43. package/dist/esm/src/factory.d.ts +2 -2
  44. package/dist/esm/src/factory.js +12 -12
  45. package/dist/esm/src/factory.js.map +1 -1
  46. package/dist/esm/src/index.d.ts +1 -0
  47. package/dist/esm/src/index.d.ts.map +1 -1
  48. package/dist/esm/src/index.js +1 -0
  49. package/dist/esm/src/index.js.map +1 -1
  50. package/dist/esm/src/manager.d.ts +10 -0
  51. package/dist/esm/src/manager.d.ts.map +1 -1
  52. package/dist/esm/src/manager.js +18 -6
  53. package/dist/esm/src/manager.js.map +1 -1
  54. package/dist/esm/src/rtu-transport.d.ts +4 -0
  55. package/dist/esm/src/rtu-transport.d.ts.map +1 -1
  56. package/dist/esm/src/rtu-transport.js +19 -10
  57. package/dist/esm/src/rtu-transport.js.map +1 -1
  58. package/dist/esm/src/slave-transport.d.ts +10 -5
  59. package/dist/esm/src/slave-transport.d.ts.map +1 -1
  60. package/dist/esm/src/slave-transport.js +42 -39
  61. package/dist/esm/src/slave-transport.js.map +1 -1
  62. package/dist/esm/src/tcp-transport.d.ts +3 -0
  63. package/dist/esm/src/tcp-transport.d.ts.map +1 -1
  64. package/dist/esm/src/tcp-transport.js +14 -5
  65. package/dist/esm/src/tcp-transport.js.map +1 -1
  66. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  67. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.10.0](https://github.com/groupsky/ya-modbus/compare/@ya-modbus/transport@0.9.1...@ya-modbus/transport@0.10.0) (2026-10-12)
7
+
8
+ ### Features
9
+
10
+ - **transport:** survive a lost serial port and reopen it after a backoff ([#549](https://github.com/groupsky/ya-modbus/issues/549)) ([b5b3e34](https://github.com/groupsky/ya-modbus/commit/b5b3e34e3f219b6600cd975f98680adebafe3093)), closes [#517](https://github.com/groupsky/ya-modbus/issues/517)
11
+
12
+ ## [0.9.1](https://github.com/groupsky/ya-modbus/compare/@ya-modbus/transport@0.9.0...@ya-modbus/transport@0.9.1) (2026-10-12)
13
+
14
+ ### Bug Fixes
15
+
16
+ - **transport:** make Modbus TCP work from the CLI and profiler ([#542](https://github.com/groupsky/ya-modbus/issues/542)) ([2aa24ac](https://github.com/groupsky/ya-modbus/commit/2aa24ac1753416c261d05bb8b8b12fccbc10e3e4))
17
+
6
18
  # [0.9.0](https://github.com/groupsky/ya-modbus/compare/@ya-modbus/transport@0.8.1...@ya-modbus/transport@0.9.0) (2026-10-12)
7
19
 
8
20
  - feat!: drop Node.js 20 support (#516) ([70002ab](https://github.com/groupsky/ya-modbus/commit/70002ab28155432e0984c67a70d1469fc5be7cb3)), closes [#516](https://github.com/groupsky/ya-modbus/issues/516)
package/README.md CHANGED
@@ -7,6 +7,7 @@ Modbus transport implementations for RTU (serial) and TCP connections.
7
7
  - RTU (RS-485/serial) transport
8
8
  - TCP/IP transport
9
9
  - Automatic retry on transient failures
10
+ - Survives a lost port (unplugged USB adapter) and opens it again
10
11
  - Factory for auto-detecting transport type
11
12
  - TypeScript support
12
13
 
@@ -69,6 +70,73 @@ try {
69
70
 
70
71
  `normalizeModbusError(error)` applies the same conversion to any caught value.
71
72
 
73
+ ### Lost connections
74
+
75
+ When a USB serial adapter is unplugged or a TCP connection closes, `modbus-serial` emits a
76
+ `close` event, and an `error` event when a write fails. The transports listen for these events,
77
+ so the process does not crash. The connection is then lost:
78
+
79
+ - A request in flight rejects at once. It does not wait for the response timeout.
80
+ - Later requests reject at once, without using the port.
81
+ - The error has the name `ConnectionLostError` and a message like
82
+ `Connection to /dev/ttyUSB0 lost: port closed`, or
83
+ `Connection to /dev/ttyUSB0 lost: EIO: i/o error, write` when a write failed. The underlying
84
+ error is in `cause`. `code` and `errno` are set only when the underlying error is a Node.js
85
+ system error, for example `ECONNREFUSED` when a TCP connection cannot be opened again.
86
+
87
+ After a TCP socket error, `modbus-serial` emits no event. The next request fails with the error of
88
+ `modbus-serial` (for example `Port Not Open`), and the connection is lost from then on.
89
+
90
+ `createTransport` and `TransportManager` open the port again on a later request. There are no
91
+ attempts in the background. The first request 1 second after the loss opens the port again. If
92
+ this fails, the next attempt waits 2 seconds, then 4 seconds, and so on, up to 60 seconds.
93
+ Requests between the attempts reject with the last error. The delay also doubles when the port
94
+ opens but is lost again before a request succeeds. A successful request sets the delay back to
95
+ 1 second. `TransportManager` opens one new client for all devices on the bus.
96
+
97
+ A short-lived program, like a CLI command, can stop at the first `ConnectionLostError`.
98
+
99
+ ```typescript
100
+ import { isConnectionLostError } from '@ya-modbus/transport'
101
+
102
+ try {
103
+ await transport.readHoldingRegisters(0, 10)
104
+ } catch (error) {
105
+ if (isConnectionLostError(error)) {
106
+ // port is gone, the transport opens it again on a later request
107
+ }
108
+ }
109
+ ```
110
+
111
+ A USB adapter can get a new name when it is plugged in again (`/dev/ttyUSB0` becomes
112
+ `/dev/ttyUSB1`), but the port is opened again with the same path. Use a stable path:
113
+
114
+ - `/dev/serial/by-id/...` for adapters with a unique serial number.
115
+ - `/dev/serial/by-path/...` for adapters without a serial number (many CH340 adapters). This name
116
+ is the physical USB port, so it changes when the adapter moves to another USB port.
117
+
118
+ To use your own `modbus-serial` client with the same handling, wrap it in a `ModbusConnection`:
119
+
120
+ ```typescript
121
+ import { createModbusTransport, ModbusConnection, type OpenClient } from '@ya-modbus/transport'
122
+ import ModbusRTU from 'modbus-serial'
123
+
124
+ // Returns a new connected client
125
+ const open: OpenClient = async () => {
126
+ const client = new ModbusRTU()
127
+ await client.connectRTUBuffered('/dev/ttyUSB0', { baudRate: 9600 })
128
+ client.setID(1)
129
+ client.setTimeout(1000)
130
+ return client
131
+ }
132
+
133
+ const connection = new ModbusConnection(await open(), '/dev/ttyUSB0', open)
134
+ const transport = createModbusTransport(connection)
135
+ ```
136
+
137
+ Without the `open` function, a lost connection works again only when you open the same client
138
+ again.
139
+
72
140
  ## License
73
141
 
74
142
  GPL-3.0-or-later
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Detection of lost connections and reopening of modbus-serial clients
3
+ */
4
+ import type ModbusRTU from 'modbus-serial';
5
+ import { type ModbusError } from './normalize-error.js';
6
+ /** Delay before the first attempt to reopen a lost connection, in milliseconds */
7
+ export declare const REOPEN_DELAY_MS = 1000;
8
+ /** Longest delay between attempts to reopen a lost connection, in milliseconds */
9
+ export declare const MAX_REOPEN_DELAY_MS = 60000;
10
+ /**
11
+ * Opens a new connected and configured client
12
+ */
13
+ export type OpenClient = () => Promise<ModbusRTU>;
14
+ /**
15
+ * Check if an error means that the connection is lost (see ModbusConnection)
16
+ *
17
+ * @param error - Value that was thrown or used to reject a promise
18
+ * @returns True for a ConnectionLostError
19
+ */
20
+ export declare function isConnectionLostError(error: unknown): error is ModbusError;
21
+ /** Marks ModbusConnection objects, the same for all copies of this package */
22
+ declare const CONNECTION: unique symbol;
23
+ /**
24
+ * A modbus-serial client together with the state of its connection.
25
+ *
26
+ * modbus-serial emits 'error' (for example when a USB serial adapter is unplugged)
27
+ * and 'close' when the port fails. Node.js throws an 'error' event that has no
28
+ * listener, which crashes the process. ModbusConnection listens for both events
29
+ * and for clients that are no longer open, and then marks the connection as lost:
30
+ * - requests in flight reject at once, without waiting for the response timeout
31
+ * - later requests reject with the same ConnectionLostError without using the port
32
+ * - with an `open` function, the first request after a delay opens a new client.
33
+ * The delay starts at REOPEN_DELAY_MS and doubles after each attempt that does
34
+ * not lead to a successful request, up to MAX_REOPEN_DELAY_MS.
35
+ * - without an `open` function, requests reject until the owner of the client
36
+ * opens it again
37
+ */
38
+ export declare class ModbusConnection {
39
+ private readonly target?;
40
+ private readonly open?;
41
+ readonly [CONNECTION] = true;
42
+ private client;
43
+ private lostError;
44
+ private reopenDelay;
45
+ private reopenAt;
46
+ private reopening;
47
+ private closed;
48
+ private readonly inFlight;
49
+ /**
50
+ * @param client - Connected modbus-serial client
51
+ * @param target - Port path or host:port, used in error messages
52
+ * @param open - Opens a new client after the connection is lost
53
+ */
54
+ constructor(client: ModbusRTU, target?: string | undefined, open?: OpenClient | undefined);
55
+ /**
56
+ * Run a request with the client
57
+ *
58
+ * @param request - Request to run
59
+ * @returns Result of the request
60
+ * @throws ConnectionLostError when the connection is lost before or during the request
61
+ */
62
+ run<T>(request: (client: ModbusRTU) => Promise<T>): Promise<T>;
63
+ /**
64
+ * Close the client and stop reopening it
65
+ */
66
+ close(): Promise<void>;
67
+ private watch;
68
+ private lose;
69
+ /** Set the time of the next reopen attempt, and wait longer after that one */
70
+ private delayReopen;
71
+ /**
72
+ * Get a working client for a lost connection, unless it is too early to try again
73
+ *
74
+ * @param lostError - The error that the connection was lost with
75
+ */
76
+ private reopen;
77
+ private openClient;
78
+ }
79
+ /**
80
+ * Use a ModbusConnection as it is, or wrap a plain client in a new one
81
+ *
82
+ * Checks the mark instead of `instanceof`, because the CommonJS and ES module
83
+ * builds of this package each have their own ModbusConnection class.
84
+ *
85
+ * @param client - A ModbusConnection or a connected modbus-serial client
86
+ * @returns The connection
87
+ */
88
+ export declare function toConnection(client: ModbusRTU | ModbusConnection): ModbusConnection;
89
+ export {};
90
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/connection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,SAAS,MAAM,eAAe,CAAA;AAE1C,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAE7E,kFAAkF;AAClF,eAAO,MAAM,eAAe,OAAO,CAAA;AAEnC,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,QAAS,CAAA;AAEzC;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAAA;AAEjD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAE1E;AAeD,8EAA8E;AAC9E,QAAA,MAAM,UAAU,eAAsD,CAAA;AAqBtE;;;;;;;;;;;;;;GAcG;AACH,qBAAa,gBAAgB;IAiBzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IAjBxB,QAAQ,CAAC,CAAC,UAAU,CAAC,QAAO;IAC5B,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA0C;IAEnE;;;;OAIG;gBAED,MAAM,EAAE,SAAS,EACA,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,IAAI,CAAC,EAAE,UAAU,YAAA;IAMpC;;;;;;OAMG;IACG,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IA0BpE;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,IAAI;IAYZ,8EAA8E;IAC9E,OAAO,CAAC,WAAW;IAKnB;;;;OAIG;IACH,OAAO,CAAC,MAAM;YAkBA,UAAU;CAqBzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,gBAAgB,GAAG,gBAAgB,CAEnF"}
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ /**
3
+ * Detection of lost connections and reopening of modbus-serial clients
4
+ */
5
+ var _a;
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ModbusConnection = exports.MAX_REOPEN_DELAY_MS = exports.REOPEN_DELAY_MS = void 0;
8
+ exports.isConnectionLostError = isConnectionLostError;
9
+ exports.toConnection = toConnection;
10
+ const node_events_1 = require("node:events");
11
+ const normalize_error_js_1 = require("./normalize-error.js");
12
+ /** Delay before the first attempt to reopen a lost connection, in milliseconds */
13
+ exports.REOPEN_DELAY_MS = 1000;
14
+ /** Longest delay between attempts to reopen a lost connection, in milliseconds */
15
+ exports.MAX_REOPEN_DELAY_MS = 60000;
16
+ /**
17
+ * Check if an error means that the connection is lost (see ModbusConnection)
18
+ *
19
+ * @param error - Value that was thrown or used to reject a promise
20
+ * @returns True for a ConnectionLostError
21
+ */
22
+ function isConnectionLostError(error) {
23
+ return error instanceof Error && error.name === 'ConnectionLostError';
24
+ }
25
+ /**
26
+ * Close a client so that a late 'error' event cannot crash the process
27
+ *
28
+ * modbus-serial stops forwarding the 'error' events of its port when the client
29
+ * closes. An error that the port emits after that (for example from an unplugged
30
+ * adapter) would have no listener, so the port keeps one that ignores it.
31
+ */
32
+ function closeClient(client, callback) {
33
+ const port = Reflect.get(client, '_port');
34
+ if (port instanceof node_events_1.EventEmitter)
35
+ port.on('error', () => undefined);
36
+ client.close(callback);
37
+ }
38
+ /** Marks ModbusConnection objects, the same for all copies of this package */
39
+ const CONNECTION = Symbol.for('@ya-modbus/transport/ModbusConnection');
40
+ /**
41
+ * Error for a lost connection, with code and errno of a Node.js system error cause
42
+ */
43
+ function connectionLostError(target, cause) {
44
+ const reason = (0, normalize_error_js_1.normalizeModbusError)(cause);
45
+ const error = new Error(`Connection ${target === undefined ? '' : `to ${target} `}lost: ${reason.message}`, { cause: reason });
46
+ error.name = 'ConnectionLostError';
47
+ // modbus-serial gives all its port errors errno 'ECONNREFUSED', also an unplugged
48
+ // serial adapter. Only Node.js system errors (they have a code) give a real errno.
49
+ if (reason.code !== undefined) {
50
+ error.code = reason.code;
51
+ error.errno = reason.errno;
52
+ }
53
+ return error;
54
+ }
55
+ /**
56
+ * A modbus-serial client together with the state of its connection.
57
+ *
58
+ * modbus-serial emits 'error' (for example when a USB serial adapter is unplugged)
59
+ * and 'close' when the port fails. Node.js throws an 'error' event that has no
60
+ * listener, which crashes the process. ModbusConnection listens for both events
61
+ * and for clients that are no longer open, and then marks the connection as lost:
62
+ * - requests in flight reject at once, without waiting for the response timeout
63
+ * - later requests reject with the same ConnectionLostError without using the port
64
+ * - with an `open` function, the first request after a delay opens a new client.
65
+ * The delay starts at REOPEN_DELAY_MS and doubles after each attempt that does
66
+ * not lead to a successful request, up to MAX_REOPEN_DELAY_MS.
67
+ * - without an `open` function, requests reject until the owner of the client
68
+ * opens it again
69
+ */
70
+ class ModbusConnection {
71
+ /**
72
+ * @param client - Connected modbus-serial client
73
+ * @param target - Port path or host:port, used in error messages
74
+ * @param open - Opens a new client after the connection is lost
75
+ */
76
+ constructor(client, target, open) {
77
+ this.target = target;
78
+ this.open = open;
79
+ this[_a] = true;
80
+ this.reopenDelay = exports.REOPEN_DELAY_MS;
81
+ this.reopenAt = 0;
82
+ this.closed = false;
83
+ this.inFlight = new Set();
84
+ this.client = client;
85
+ this.watch(client);
86
+ }
87
+ /**
88
+ * Run a request with the client
89
+ *
90
+ * @param request - Request to run
91
+ * @returns Result of the request
92
+ * @throws ConnectionLostError when the connection is lost before or during the request
93
+ */
94
+ async run(request) {
95
+ // No await while the connection works, so the request starts at once
96
+ const client = this.lostError === undefined ? this.client : await this.reopen(this.lostError);
97
+ // Assigned at once: the promise executor runs synchronously
98
+ let rejectOnLoss;
99
+ const lost = new Promise((_resolve, reject) => {
100
+ rejectOnLoss = reject;
101
+ });
102
+ // Handled here too, in case request() throws before Promise.race() listens
103
+ lost.catch(() => undefined);
104
+ this.inFlight.add(rejectOnLoss);
105
+ try {
106
+ const value = await Promise.race([request(client), lost]);
107
+ // The port works, so the next loss starts again with the shortest delay
108
+ this.reopenDelay = exports.REOPEN_DELAY_MS;
109
+ return value;
110
+ }
111
+ catch (error) {
112
+ // modbus-serial clears isOpen on some failures without an event (TCP socket errors)
113
+ if (!client.isOpen)
114
+ this.lose(client, error);
115
+ throw error;
116
+ }
117
+ finally {
118
+ this.inFlight.delete(rejectOnLoss);
119
+ }
120
+ }
121
+ /**
122
+ * Close the client and stop reopening it
123
+ */
124
+ async close() {
125
+ this.closed = true;
126
+ // A lost client or a client that is not open needs no close. modbus-serial never
127
+ // calls back when it closes a TCP client whose socket is closed.
128
+ if (this.lostError !== undefined || !this.client.isOpen)
129
+ return;
130
+ const client = this.client;
131
+ await new Promise((resolve) => {
132
+ closeClient(client, () => resolve());
133
+ });
134
+ }
135
+ watch(client) {
136
+ // The listeners stay for the life of the client: a late 'error' from a lost
137
+ // client must not crash the process
138
+ client.on('error', (error) => this.lose(client, error));
139
+ client.on('close', () => this.lose(client, 'port closed'));
140
+ }
141
+ lose(client, cause) {
142
+ // Ignore events from clients that were replaced, and repeated events
143
+ if (client !== this.client || this.lostError !== undefined || this.closed)
144
+ return;
145
+ this.lostError = connectionLostError(this.target, cause);
146
+ this.delayReopen();
147
+ for (const reject of this.inFlight)
148
+ reject(this.lostError);
149
+ // serialport closes the port on a disconnect. A port that is still open keeps
150
+ // its lock, and the reopen would fail.
151
+ if (client.isOpen)
152
+ closeClient(client, () => undefined);
153
+ }
154
+ /** Set the time of the next reopen attempt, and wait longer after that one */
155
+ delayReopen() {
156
+ this.reopenAt = performance.now() + this.reopenDelay;
157
+ this.reopenDelay = Math.min(this.reopenDelay * 2, exports.MAX_REOPEN_DELAY_MS);
158
+ }
159
+ /**
160
+ * Get a working client for a lost connection, unless it is too early to try again
161
+ *
162
+ * @param lostError - The error that the connection was lost with
163
+ */
164
+ reopen(lostError) {
165
+ if (this.open === undefined) {
166
+ // The owner of the client can open it again
167
+ if (this.client.isOpen && !this.closed) {
168
+ this.lostError = undefined;
169
+ return Promise.resolve(this.client);
170
+ }
171
+ return Promise.reject(lostError);
172
+ }
173
+ if (this.closed || performance.now() < this.reopenAt)
174
+ return Promise.reject(lostError);
175
+ // Requests that come while the client opens wait for the same attempt
176
+ this.reopening ?? (this.reopening = this.openClient(this.open, lostError).finally(() => {
177
+ this.reopening = undefined;
178
+ }));
179
+ return this.reopening;
180
+ }
181
+ async openClient(open, lostError) {
182
+ let client;
183
+ try {
184
+ client = await open();
185
+ }
186
+ catch (error) {
187
+ const openError = connectionLostError(this.target, error);
188
+ this.lostError = openError;
189
+ this.delayReopen();
190
+ throw openError;
191
+ }
192
+ if (this.closed) {
193
+ // close() was called while the client was opening
194
+ closeClient(client, () => undefined);
195
+ throw lostError;
196
+ }
197
+ this.client = client;
198
+ this.lostError = undefined;
199
+ this.watch(client);
200
+ return client;
201
+ }
202
+ }
203
+ exports.ModbusConnection = ModbusConnection;
204
+ _a = CONNECTION;
205
+ /**
206
+ * Use a ModbusConnection as it is, or wrap a plain client in a new one
207
+ *
208
+ * Checks the mark instead of `instanceof`, because the CommonJS and ES module
209
+ * builds of this package each have their own ModbusConnection class.
210
+ *
211
+ * @param client - A ModbusConnection or a connected modbus-serial client
212
+ * @returns The connection
213
+ */
214
+ function toConnection(client) {
215
+ return CONNECTION in client ? client : new ModbusConnection(client);
216
+ }
217
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../src/connection.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,18 @@
1
1
  import type { Transport } from '@ya-modbus/driver-types';
2
2
  import type ModbusRTU from 'modbus-serial';
3
+ import { type ModbusConnection } from './connection.js';
3
4
  import { type RetryLogger } from './retry.js';
4
5
  /**
5
6
  * Create a Transport implementation from a ModbusRTU client
6
7
  *
7
8
  * This factory wraps all modbus-serial client methods with retry logic
8
9
  * and converts them to the Transport interface expected by device drivers.
10
+ * Requests on a lost connection reject with a ConnectionLostError (see ModbusConnection).
9
11
  *
10
- * @param client - Configured ModbusRTU client instance
12
+ * @param client - Configured ModbusRTU client instance, or a ModbusConnection that can reopen it
11
13
  * @param maxRetries - Maximum retry attempts (default: 3, use 1 for discovery to disable retries)
12
14
  * @param logger - Optional callback to log retry attempts for debugging
13
15
  * @returns Transport implementation
14
16
  */
15
- export declare function createModbusTransport(client: ModbusRTU, maxRetries?: number, logger?: RetryLogger): Transport;
17
+ export declare function createModbusTransport(client: ModbusRTU | ModbusConnection, maxRetries?: number, logger?: RetryLogger): Transport;
16
18
  //# sourceMappingURL=create-modbus-transport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-modbus-transport.d.ts","sourceRoot":"","sources":["../../../src/create-modbus-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,SAAS,MAAM,eAAe,CAAA;AAE1C,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AAExD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,UAAU,GAAE,MAAU,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,SAAS,CAoGX"}
1
+ {"version":3,"file":"create-modbus-transport.d.ts","sourceRoot":"","sources":["../../../src/create-modbus-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,SAAS,MAAM,eAAe,CAAA;AAE1C,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACrE,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AAExD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,UAAU,GAAE,MAAU,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,SAAS,CA4GX"}
@@ -1,61 +1,64 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createModbusTransport = createModbusTransport;
4
+ const connection_js_1 = require("./connection.js");
4
5
  const retry_js_1 = require("./retry.js");
5
6
  /**
6
7
  * Create a Transport implementation from a ModbusRTU client
7
8
  *
8
9
  * This factory wraps all modbus-serial client methods with retry logic
9
10
  * and converts them to the Transport interface expected by device drivers.
11
+ * Requests on a lost connection reject with a ConnectionLostError (see ModbusConnection).
10
12
  *
11
- * @param client - Configured ModbusRTU client instance
13
+ * @param client - Configured ModbusRTU client instance, or a ModbusConnection that can reopen it
12
14
  * @param maxRetries - Maximum retry attempts (default: 3, use 1 for discovery to disable retries)
13
15
  * @param logger - Optional callback to log retry attempts for debugging
14
16
  * @returns Transport implementation
15
17
  */
16
18
  function createModbusTransport(client, maxRetries = 3, logger) {
19
+ const connection = (0, connection_js_1.toConnection)(client);
17
20
  return {
18
21
  async readHoldingRegisters(address, count) {
19
- return (0, retry_js_1.withRetry)(async () => {
20
- const result = await client.readHoldingRegisters(address, count);
22
+ return (0, retry_js_1.withRetry)(() => connection.run(async (modbus) => {
23
+ const result = await modbus.readHoldingRegisters(address, count);
21
24
  return result.buffer;
22
- }, maxRetries, logger);
25
+ }), maxRetries, logger);
23
26
  },
24
27
  async readInputRegisters(address, count) {
25
- return (0, retry_js_1.withRetry)(async () => {
26
- const result = await client.readInputRegisters(address, count);
28
+ return (0, retry_js_1.withRetry)(() => connection.run(async (modbus) => {
29
+ const result = await modbus.readInputRegisters(address, count);
27
30
  return result.buffer;
28
- }, maxRetries, logger);
31
+ }), maxRetries, logger);
29
32
  },
30
33
  async readCoils(address, count) {
31
- return (0, retry_js_1.withRetry)(async () => {
32
- const result = await client.readCoils(address, count);
34
+ return (0, retry_js_1.withRetry)(() => connection.run(async (modbus) => {
35
+ const result = await modbus.readCoils(address, count);
33
36
  return result.buffer;
34
- }, maxRetries, logger);
37
+ }), maxRetries, logger);
35
38
  },
36
39
  async readDiscreteInputs(address, count) {
37
- return (0, retry_js_1.withRetry)(async () => {
38
- const result = await client.readDiscreteInputs(address, count);
40
+ return (0, retry_js_1.withRetry)(() => connection.run(async (modbus) => {
41
+ const result = await modbus.readDiscreteInputs(address, count);
39
42
  return result.buffer;
40
- }, maxRetries, logger);
43
+ }), maxRetries, logger);
41
44
  },
42
45
  async writeSingleRegister(address, value) {
43
- return (0, retry_js_1.withRetry)(async () => {
44
- await client.writeRegister(address, value);
45
- }, maxRetries, logger);
46
+ return (0, retry_js_1.withRetry)(() => connection.run(async (modbus) => {
47
+ await modbus.writeRegister(address, value);
48
+ }), maxRetries, logger);
46
49
  },
47
50
  async writeMultipleRegisters(address, values) {
48
- return (0, retry_js_1.withRetry)(async () => {
49
- await client.writeRegisters(address, values);
50
- }, maxRetries, logger);
51
+ return (0, retry_js_1.withRetry)(() => connection.run(async (modbus) => {
52
+ await modbus.writeRegisters(address, values);
53
+ }), maxRetries, logger);
51
54
  },
52
55
  async writeSingleCoil(address, value) {
53
- return (0, retry_js_1.withRetry)(async () => {
54
- await client.writeCoil(address, value);
55
- }, maxRetries, logger);
56
+ return (0, retry_js_1.withRetry)(() => connection.run(async (modbus) => {
57
+ await modbus.writeCoil(address, value);
58
+ }), maxRetries, logger);
56
59
  },
57
60
  async writeMultipleCoils(address, values) {
58
- return (0, retry_js_1.withRetry)(async () => {
61
+ return (0, retry_js_1.withRetry)(() => connection.run(async (modbus) => {
59
62
  // Convert Buffer to boolean array
60
63
  const bools = [];
61
64
  for (let i = 0; i < values.length * 8; i++) {
@@ -64,13 +67,11 @@ function createModbusTransport(client, maxRetries = 3, logger) {
64
67
  const byte = values[byteIndex]; // byteIndex < values.length due to loop condition
65
68
  bools.push((byte & (1 << bitIndex)) !== 0);
66
69
  }
67
- await client.writeCoils(address, bools);
68
- }, maxRetries, logger);
70
+ await modbus.writeCoils(address, bools);
71
+ }), maxRetries, logger);
69
72
  },
70
73
  async close() {
71
- return new Promise((resolve) => {
72
- client.close(resolve);
73
- });
74
+ return connection.close();
74
75
  },
75
76
  };
76
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"create-modbus-transport.js","sourceRoot":"","sources":["../../../src/create-modbus-transport.ts"],"names":[],"mappings":";;AAgBA,sDAwGC;AArHD,yCAAwD;AAExD;;;;;;;;;;GAUG;AACH,SAAgB,qBAAqB,CACnC,MAAiB,EACjB,aAAqB,CAAC,EACtB,MAAoB;IAEpB,OAAO;QACL,KAAK,CAAC,oBAAoB,CAAC,OAAe,EAAE,KAAa;YACvD,OAAO,IAAA,oBAAS,EACd,KAAK,IAAI,EAAE;gBACT,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;gBAChE,OAAO,MAAM,CAAC,MAAM,CAAA;YACtB,CAAC,EACD,UAAU,EACV,MAAM,CACP,CAAA;QACH,CAAC;QAED,KAAK,CAAC,kBAAkB,CAAC,OAAe,EAAE,KAAa;YACrD,OAAO,IAAA,oBAAS,EACd,KAAK,IAAI,EAAE;gBACT,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;gBAC9D,OAAO,MAAM,CAAC,MAAM,CAAA;YACtB,CAAC,EACD,UAAU,EACV,MAAM,CACP,CAAA;QACH,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,OAAe,EAAE,KAAa;YAC5C,OAAO,IAAA,oBAAS,EACd,KAAK,IAAI,EAAE;gBACT,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;gBACrD,OAAO,MAAM,CAAC,MAAM,CAAA;YACtB,CAAC,EACD,UAAU,EACV,MAAM,CACP,CAAA;QACH,CAAC;QAED,KAAK,CAAC,kBAAkB,CAAC,OAAe,EAAE,KAAa;YACrD,OAAO,IAAA,oBAAS,EACd,KAAK,IAAI,EAAE;gBACT,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;gBAC9D,OAAO,MAAM,CAAC,MAAM,CAAA;YACtB,CAAC,EACD,UAAU,EACV,MAAM,CACP,CAAA;QACH,CAAC;QAED,KAAK,CAAC,mBAAmB,CAAC,OAAe,EAAE,KAAa;YACtD,OAAO,IAAA,oBAAS,EACd,KAAK,IAAI,EAAE;gBACT,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YAC5C,CAAC,EACD,UAAU,EACV,MAAM,CACP,CAAA;QACH,CAAC;QAED,KAAK,CAAC,sBAAsB,CAAC,OAAe,EAAE,MAAc;YAC1D,OAAO,IAAA,oBAAS,EACd,KAAK,IAAI,EAAE;gBACT,MAAM,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC9C,CAAC,EACD,UAAU,EACV,MAAM,CACP,CAAA;QACH,CAAC;QAED,KAAK,CAAC,eAAe,CAAC,OAAe,EAAE,KAAc;YACnD,OAAO,IAAA,oBAAS,EACd,KAAK,IAAI,EAAE;gBACT,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YACxC,CAAC,EACD,UAAU,EACV,MAAM,CACP,CAAA;QACH,CAAC;QAED,KAAK,CAAC,kBAAkB,CAAC,OAAe,EAAE,MAAc;YACtD,OAAO,IAAA,oBAAS,EACd,KAAK,IAAI,EAAE;gBACT,kCAAkC;gBAClC,MAAM,KAAK,GAAc,EAAE,CAAA;gBAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;oBACnC,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAA;oBACtB,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAW,CAAA,CAAC,kDAAkD;oBAC3F,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;gBAC5C,CAAC;gBACD,MAAM,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YACzC,CAAC,EACD,UAAU,EACV,MAAM,CACP,CAAA;QACH,CAAC;QAED,KAAK,CAAC,KAAK;YACT,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBACnC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YACvB,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"create-modbus-transport.js","sourceRoot":"","sources":["../../../src/create-modbus-transport.ts"],"names":[],"mappings":"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"}
@@ -11,8 +11,8 @@ export type TransportConfig = RTUConfig | TCPConfig;
11
11
  * Create a transport instance based on configuration
12
12
  *
13
13
  * Detects whether to create RTU or TCP transport based on the config:
14
- * - If `port` is provided → RTU transport
15
- * - If `host` is provided → TCP transport
14
+ * - If `host` is provided → TCP transport (`port` is the optional TCP port number)
15
+ * - Otherwise, if `port` is provided → RTU transport (`port` is the serial path)
16
16
  *
17
17
  * @param config - Transport configuration (RTU or TCP)
18
18
  * @returns Transport implementation
@@ -4,33 +4,33 @@ exports.createTransport = createTransport;
4
4
  const rtu_transport_js_1 = require("./rtu-transport.js");
5
5
  const tcp_transport_js_1 = require("./tcp-transport.js");
6
6
  /**
7
- * Type guard to check if config is RTU
7
+ * Type guard to check if config is TCP
8
8
  */
9
- function isRTUConfig(config) {
10
- return 'port' in config && !('host' in config);
9
+ function isTCPConfig(config) {
10
+ return 'host' in config;
11
11
  }
12
12
  /**
13
13
  * Create a transport instance based on configuration
14
14
  *
15
15
  * Detects whether to create RTU or TCP transport based on the config:
16
- * - If `port` is provided → RTU transport
17
- * - If `host` is provided → TCP transport
16
+ * - If `host` is provided → TCP transport (`port` is the optional TCP port number)
17
+ * - Otherwise, if `port` is provided → RTU transport (`port` is the serial path)
18
18
  *
19
19
  * @param config - Transport configuration (RTU or TCP)
20
20
  * @returns Transport implementation
21
21
  * @throws Error if config is invalid
22
22
  */
23
23
  async function createTransport(config) {
24
- // Validate that exactly one of port/host is provided
25
- if ('port' in config && 'host' in config) {
26
- throw new Error('Cannot specify both port (RTU) and host (TCP)');
24
+ if (isTCPConfig(config)) {
25
+ // A string `port` is a serial path, which cannot be combined with a TCP host
26
+ if (typeof config.port === 'string') {
27
+ throw new Error('Cannot specify both port (RTU) and host (TCP)');
28
+ }
29
+ return (0, tcp_transport_js_1.createTCPTransport)(config);
27
30
  }
28
- if (isRTUConfig(config)) {
31
+ if ('port' in config) {
29
32
  return (0, rtu_transport_js_1.createRTUTransport)(config);
30
33
  }
31
- if ('host' in config) {
32
- return (0, tcp_transport_js_1.createTCPTransport)(config);
33
- }
34
34
  throw new Error('Either port (for RTU) or host (for TCP) must be specified');
35
35
  }
36
36
  //# sourceMappingURL=factory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/factory.ts"],"names":[],"mappings":";;AAgCA,0CAeC;AA7CD,yDAAuE;AACvE,yDAAuE;AAWvE;;GAEG;AACH,SAAS,WAAW,CAAC,MAAuB;IAC1C,OAAO,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAA;AAChD,CAAC;AAED;;;;;;;;;;GAUG;AACI,KAAK,UAAU,eAAe,CAAC,MAAuB;IAC3D,qDAAqD;IACrD,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,OAAO,IAAA,qCAAkB,EAAC,MAAM,CAAC,CAAA;IACnC,CAAC;IAED,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;QACrB,OAAO,IAAA,qCAAkB,EAAC,MAAM,CAAC,CAAA;IACnC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;AAC9E,CAAC"}
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/factory.ts"],"names":[],"mappings":";;AAgCA,0CAeC;AA7CD,yDAAuE;AACvE,yDAAuE;AAWvE;;GAEG;AACH,SAAS,WAAW,CAAC,MAAuB;IAC1C,OAAO,MAAM,IAAI,MAAM,CAAA;AACzB,CAAC;AAED;;;;;;;;;;GAUG;AACI,KAAK,UAAU,eAAe,CAAC,MAAuB;IAC3D,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,6EAA6E;QAC7E,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;QAClE,CAAC;QAED,OAAO,IAAA,qCAAkB,EAAC,MAAM,CAAC,CAAA;IACnC,CAAC;IAED,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;QACrB,OAAO,IAAA,qCAAkB,EAAC,MAAM,CAAC,CAAA;IACnC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;AAC9E,CAAC"}
@@ -10,6 +10,7 @@ export { createTCPTransport, type TCPConfig } from './tcp-transport.js';
10
10
  export { createModbusTransport } from './create-modbus-transport.js';
11
11
  export { withRetry, MAX_RETRIES, RETRY_DELAY_MS, type RetryLogger } from './retry.js';
12
12
  export { normalizeModbusError, type ModbusError } from './normalize-error.js';
13
+ export { isConnectionLostError, ModbusConnection, type OpenClient } from './connection.js';
13
14
  export { TransportManager, type TransportStats } from './manager.js';
14
15
  export { MutexTransport } from './mutex-transport.js';
15
16
  export { SlaveTransport } from './slave-transport.js';