@ya-modbus/device-profiler 0.7.3 → 0.8.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/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
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.8.0](https://github.com/groupsky/ya-modbus/compare/@ya-modbus/device-profiler@0.7.3...@ya-modbus/device-profiler@0.8.0) (2026-02-13)
7
+
8
+ ### Features
9
+
10
+ - **device-profiler:** add JSON output format ([#377](https://github.com/groupsky/ya-modbus/issues/377)) ([0aadf5a](https://github.com/groupsky/ya-modbus/commit/0aadf5a54eacdd3572d4e37ff26751846689aafd)), closes [#372](https://github.com/groupsky/ya-modbus/issues/372)
11
+
6
12
  ## [0.7.3](https://github.com/groupsky/ya-modbus/compare/@ya-modbus/device-profiler@0.7.2...@ya-modbus/device-profiler@0.7.3) (2026-02-11)
7
13
 
8
14
  **Note:** Version bump only for package @ya-modbus/device-profiler
package/README.md CHANGED
@@ -10,6 +10,7 @@ Device profiler for discovering Modbus register maps through automated scanning.
10
10
  - Timing measurement for each read operation
11
11
  - Error classification (timeout, CRC, Modbus exceptions)
12
12
  - Summary table of discovered registers
13
+ - **JSON output format** for automation and integration
13
14
 
14
15
  ## Installation
15
16
 
@@ -22,17 +23,27 @@ npm install @ya-modbus/device-profiler
22
23
  ### CLI
23
24
 
24
25
  ```bash
26
+ # Table output (default)
25
27
  ya-modbus-profile --port /dev/ttyUSB0 --slave-id 1 --baud 9600
28
+
29
+ # JSON output for automation
30
+ ya-modbus-profile --port /dev/ttyUSB0 --slave-id 1 --format json
26
31
  ```
27
32
 
28
33
  Options:
29
34
 
30
- - `--port` - Serial port or TCP host:port
31
- - `--slave-id` - Modbus slave ID
32
- - `--baud` - Baud rate for RTU (default: 9600)
33
- - `--start` - Start register address (default: 0)
34
- - `--end` - End register address (default: 100)
35
- - `--batch` - Batch size for reads (default: 10)
35
+ - `--port` - Serial port (e.g., `/dev/ttyUSB0`) or TCP host:port (e.g., `localhost:502`)
36
+ - `--slave-id` - Modbus slave ID (1-247)
37
+ - `--type` - Register type: `holding` or `input` (default: `holding`)
38
+ - `--start` - Start register address (default: `0`)
39
+ - `--end` - End register address (default: `100`)
40
+ - `--batch` - Batch size for reads (default: `10`)
41
+ - `--baud` - Baud rate for RTU (default: `9600`)
42
+ - `--parity` - Parity for RTU: `none`, `even`, `odd` (default: `none`)
43
+ - `--data-bits` - Data bits for RTU (default: `8`)
44
+ - `--stop-bits` - Stop bits for RTU (default: `1`)
45
+ - `--timeout` - Response timeout in milliseconds (default: `1000`)
46
+ - `-f, --format` - Output format: `table` or `json` (default: `table`)
36
47
 
37
48
  ### Programmatic
38
49
 
@@ -56,14 +67,134 @@ await scanRegisters({
56
67
 
57
68
  ## Output
58
69
 
59
- The scanner produces a summary showing:
70
+ ### Table Format (Default)
71
+
72
+ The scanner produces a summary table showing:
60
73
 
61
74
  - Register address
62
75
  - Register type (holding/input)
63
76
  - Read success/failure
64
- - Response time
77
+ - Register value (hex-encoded)
78
+ - Response time (milliseconds)
65
79
  - Error details (if any)
66
80
 
81
+ Example:
82
+
83
+ ```
84
+ Scanning holding registers from 0 to 10...
85
+
86
+ Progress: 11/11 (100%)
87
+
88
+ Scan complete!
89
+
90
+ ┌─────────┬─────────┬─────────┬───────┬────────┬───────┐
91
+ │ Address │ Type │ Status │ Value │ Timing │ Error │
92
+ ├─────────┼─────────┼─────────┼───────┼────────┼───────┤
93
+ │ 0 │ holding │ ✓ │ 1234 │ 15ms │ │
94
+ │ 1 │ holding │ ✗ │ │ 1000ms │ Timeout waiting for response │
95
+ │ 2 │ holding │ ✓ │ 5678 │ 12ms │ │
96
+ └─────────┴─────────┴─────────┴───────┴────────┴───────┘
97
+ ```
98
+
99
+ ### JSON Format
100
+
101
+ For automation and integration with other tools, use `--format json` to output machine-readable JSON:
102
+
103
+ ```bash
104
+ ya-modbus-profile --port /dev/ttyUSB0 --slave-id 1 --format json
105
+ ```
106
+
107
+ #### JSON Structure
108
+
109
+ The JSON output includes:
110
+
111
+ - **`timestamp`** (string): ISO 8601 timestamp when the scan completed
112
+ - **`scan`** (object): Scan configuration
113
+ - `type` (string): Register type (`"holding"` or `"input"`)
114
+ - `startAddress` (number): Starting register address
115
+ - `endAddress` (number): Ending register address (inclusive)
116
+ - `batchSize` (number): Batch size used for reading
117
+ - **`connection`** (object): Connection details
118
+ - `port` (string): Serial port path or TCP host:port
119
+ - **`results`** (array): Array of scan results, one per register
120
+ - `address` (number): Register address
121
+ - `type` (string): Register type (`"holding"` or `"input"`)
122
+ - `success` (boolean): Whether the read succeeded
123
+ - `value` (number | null): 16-bit register value (0-65535) or `null` if failed
124
+ - `timing` (number): Read operation duration in milliseconds
125
+ - `error` (string, optional): Error message (only present when `success=false`)
126
+ - `errorType` (string, optional): Error classification (only present when `success=false`)
127
+ - `"timeout"`: Device did not respond within timeout period
128
+ - `"crc"`: CRC check failed (data corruption)
129
+ - `"modbus_exception"`: Device returned a Modbus exception
130
+ - `"unknown"`: Other errors
131
+ - **`summary`** (object): Scan statistics
132
+ - `total` (number): Total registers scanned
133
+ - `successful` (number): Number of successful reads
134
+ - `failed` (number): Number of failed reads
135
+ - `totalTimeMs` (number): Total scan duration in milliseconds
136
+ - `averageTimeMs` (number): Average read time per register in milliseconds
137
+
138
+ #### JSON Example
139
+
140
+ ```json
141
+ {
142
+ "timestamp": "2026-02-13T18:17:41.367Z",
143
+ "scan": {
144
+ "type": "holding",
145
+ "startAddress": 0,
146
+ "endAddress": 10,
147
+ "batchSize": 10
148
+ },
149
+ "connection": {
150
+ "port": "/dev/ttyUSB0"
151
+ },
152
+ "results": [
153
+ {
154
+ "address": 0,
155
+ "type": "holding",
156
+ "success": true,
157
+ "value": 4660,
158
+ "timing": 15
159
+ },
160
+ {
161
+ "address": 1,
162
+ "type": "holding",
163
+ "success": false,
164
+ "value": null,
165
+ "timing": 1000,
166
+ "error": "Timeout waiting for response",
167
+ "errorType": "timeout"
168
+ },
169
+ {
170
+ "address": 2,
171
+ "type": "holding",
172
+ "success": true,
173
+ "value": 22136,
174
+ "timing": 12
175
+ }
176
+ ],
177
+ "summary": {
178
+ "total": 3,
179
+ "successful": 2,
180
+ "failed": 1,
181
+ "totalTimeMs": 1027,
182
+ "averageTimeMs": 342.33
183
+ }
184
+ }
185
+ ```
186
+
187
+ #### JSON Output Notes
188
+
189
+ - **Progress messages** are suppressed in JSON mode for clean output
190
+ - **Register values** are 16-bit unsigned integers (0-65535) in big-endian format
191
+ - Direct numeric access, no parsing needed
192
+ - Example: bytes `[0x12, 0x34]` = 4660 decimal (0x1234 hex)
193
+ - Format as hex if needed: `value.toString(16).padStart(4, '0')`
194
+ - **Error fields** (`error`, `errorType`) are only included when `success=false`
195
+ - **Timing precision** is milliseconds with up to 2 decimal places
196
+ - **Output is formatted** with 2-space indentation for readability
197
+
67
198
  ## License
68
199
 
69
200
  GPL-3.0-or-later
@@ -17,6 +17,10 @@ export interface ProfileScanOptions {
17
17
  endAddress: number;
18
18
  /** Maximum registers to read in a single batch (default: 10) */
19
19
  batchSize?: number;
20
+ /** Output format: table or json (default: table) */
21
+ format?: 'table' | 'json';
22
+ /** Connection port (for JSON metadata) */
23
+ port?: string;
20
24
  }
21
25
  /**
22
26
  * Run a register profile scan with console output
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAIxD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAG/C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uBAAuB;IACvB,SAAS,EAAE,SAAS,CAAA;IACpB,4BAA4B;IAC5B,IAAI,EAAE,YAAY,CAAA;IAClB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAA;IACpB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC/E"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAKxD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAG/C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uBAAuB;IACvB,SAAS,EAAE,SAAS,CAAA;IACpB,4BAA4B;IAC5B,IAAI,EAAE,YAAY,CAAA;IAClB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAA;IACpB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oDAAoD;IACpD,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACzB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmD/E"}
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runProfileScan = runProfileScan;
7
7
  const console_formatter_js_1 = require("./console-formatter.js");
8
8
  const constants_js_1 = require("./constants.js");
9
+ const json_formatter_js_1 = require("./json-formatter.js");
9
10
  const register_scanner_js_1 = require("./register-scanner.js");
10
11
  /**
11
12
  * Run a register profile scan with console output
@@ -13,11 +14,14 @@ const register_scanner_js_1 = require("./register-scanner.js");
13
14
  * @param options - Scan configuration
14
15
  */
15
16
  async function runProfileScan(options) {
16
- const { transport, type, startAddress, endAddress, batchSize } = options;
17
+ const { transport, type, startAddress, endAddress, batchSize, format = 'table', port } = options;
17
18
  const results = [];
19
+ const isJsonFormat = format === 'json';
18
20
  try {
19
- console.log(`Scanning ${type} registers from ${startAddress} to ${endAddress}...`);
20
- console.log();
21
+ if (!isJsonFormat) {
22
+ console.log(`Scanning ${type} registers from ${startAddress} to ${endAddress}...`);
23
+ console.log();
24
+ }
21
25
  let lastProgressUpdate = 0;
22
26
  await (0, register_scanner_js_1.scanRegisters)({
23
27
  transport,
@@ -26,20 +30,33 @@ async function runProfileScan(options) {
26
30
  endAddress,
27
31
  ...(batchSize !== undefined && { batchSize }),
28
32
  onProgress: (current, total) => {
29
- const now = Date.now();
30
- if (now - lastProgressUpdate >= constants_js_1.PROGRESS_UPDATE_INTERVAL_MS || current === total) {
31
- process.stdout.write(`\r${(0, console_formatter_js_1.formatProgress)(current, total)}`);
32
- lastProgressUpdate = now;
33
+ if (!isJsonFormat) {
34
+ const now = Date.now();
35
+ if (now - lastProgressUpdate >= constants_js_1.PROGRESS_UPDATE_INTERVAL_MS || current === total) {
36
+ process.stdout.write(`\r${(0, console_formatter_js_1.formatProgress)(current, total)}`);
37
+ lastProgressUpdate = now;
38
+ }
33
39
  }
34
40
  },
35
41
  onResult: (result) => {
36
42
  results.push(result);
37
43
  },
38
44
  });
39
- console.log('\n');
40
- console.log('Scan complete!');
41
- console.log();
42
- console.log((0, console_formatter_js_1.formatSummary)(results));
45
+ if (isJsonFormat) {
46
+ console.log((0, json_formatter_js_1.formatJSON)(results, {
47
+ type,
48
+ startAddress,
49
+ endAddress,
50
+ batchSize: batchSize ?? constants_js_1.DEFAULT_BATCH_SIZE,
51
+ port: port ?? '',
52
+ }));
53
+ }
54
+ else {
55
+ console.log('\n');
56
+ console.log('Scan complete!');
57
+ console.log();
58
+ console.log((0, console_formatter_js_1.formatSummary)(results));
59
+ }
43
60
  }
44
61
  finally {
45
62
  await transport.close();
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli.ts"],"names":[],"mappings":";AAAA;;GAEG;;AA8BH,wCAkCC;AA5DD,iEAAsE;AACtE,iDAA4D;AAE5D,+DAAsE;AAkBtE;;;;GAIG;AACI,KAAK,UAAU,cAAc,CAAC,OAA2B;IAC9D,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IACxE,MAAM,OAAO,GAAiB,EAAE,CAAA;IAEhC,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,mBAAmB,YAAY,OAAO,UAAU,KAAK,CAAC,CAAA;QAClF,OAAO,CAAC,GAAG,EAAE,CAAA;QAEb,IAAI,kBAAkB,GAAG,CAAC,CAAA;QAC1B,MAAM,IAAA,mCAAa,EAAC;YAClB,SAAS;YACT,IAAI;YACJ,YAAY;YACZ,UAAU;YACV,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;YAC7C,UAAU,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;gBAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;gBACtB,IAAI,GAAG,GAAG,kBAAkB,IAAI,0CAA2B,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;oBACjF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAA,qCAAc,EAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,CAAA;oBAC3D,kBAAkB,GAAG,GAAG,CAAA;gBAC1B,CAAC;YACH,CAAC;YACD,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;gBACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACtB,CAAC;SACF,CAAC,CAAA;QAEF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACjB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;QAC7B,OAAO,CAAC,GAAG,EAAE,CAAA;QACb,OAAO,CAAC,GAAG,CAAC,IAAA,oCAAa,EAAC,OAAO,CAAC,CAAC,CAAA;IACrC,CAAC;YAAS,CAAC;QACT,MAAM,SAAS,CAAC,KAAK,EAAE,CAAA;IACzB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAmCH,wCAmDC;AAlFD,iEAAsE;AACtE,iDAAgF;AAChF,2DAAgD;AAEhD,+DAAsE;AAsBtE;;;;GAIG;AACI,KAAK,UAAU,cAAc,CAAC,OAA2B;IAC9D,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IAChG,MAAM,OAAO,GAAiB,EAAE,CAAA;IAChC,MAAM,YAAY,GAAG,MAAM,KAAK,MAAM,CAAA;IAEtC,IAAI,CAAC;QACH,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,mBAAmB,YAAY,OAAO,UAAU,KAAK,CAAC,CAAA;YAClF,OAAO,CAAC,GAAG,EAAE,CAAA;QACf,CAAC;QAED,IAAI,kBAAkB,GAAG,CAAC,CAAA;QAC1B,MAAM,IAAA,mCAAa,EAAC;YAClB,SAAS;YACT,IAAI;YACJ,YAAY;YACZ,UAAU;YACV,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;YAC7C,UAAU,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;gBAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;oBAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;oBACtB,IAAI,GAAG,GAAG,kBAAkB,IAAI,0CAA2B,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;wBACjF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAA,qCAAc,EAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,CAAA;wBAC3D,kBAAkB,GAAG,GAAG,CAAA;oBAC1B,CAAC;gBACH,CAAC;YACH,CAAC;YACD,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;gBACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACtB,CAAC;SACF,CAAC,CAAA;QAEF,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CACT,IAAA,8BAAU,EAAC,OAAO,EAAE;gBAClB,IAAI;gBACJ,YAAY;gBACZ,UAAU;gBACV,SAAS,EAAE,SAAS,IAAI,iCAAkB;gBAC1C,IAAI,EAAE,IAAI,IAAI,EAAE;aACjB,CAAC,CACH,CAAA;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACjB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;YAC7B,OAAO,CAAC,GAAG,EAAE,CAAA;YACb,OAAO,CAAC,GAAG,CAAC,IAAA,oCAAa,EAAC,OAAO,CAAC,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,SAAS,CAAC,KAAK,EAAE,CAAA;IACzB,CAAC;AACH,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * JSON output formatter for device profiler
3
+ */
4
+ import type { RegisterType } from './read-tester.js';
5
+ import type { ScanResult } from './register-scanner.js';
6
+ /**
7
+ * Options for JSON formatter
8
+ */
9
+ export interface JSONFormatterOptions {
10
+ /** Register type scanned */
11
+ type: RegisterType;
12
+ /** Start address of scan */
13
+ startAddress: number;
14
+ /** End address of scan */
15
+ endAddress: number;
16
+ /** Batch size used for scanning */
17
+ batchSize: number;
18
+ /** Connection port (serial or TCP) */
19
+ port: string;
20
+ }
21
+ /**
22
+ * Format scan results as JSON
23
+ *
24
+ * @param results - Array of scan results
25
+ * @param options - Scan configuration metadata
26
+ * @returns Formatted JSON string with 2-space indentation
27
+ */
28
+ export declare function formatJSON(results: ReadonlyArray<ScanResult>, options: JSONFormatterOptions): string;
29
+ //# sourceMappingURL=json-formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-formatter.d.ts","sourceRoot":"","sources":["../../../src/json-formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAEvD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,4BAA4B;IAC5B,IAAI,EAAE,YAAY,CAAA;IAClB,4BAA4B;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,EAClC,OAAO,EAAE,oBAAoB,GAC5B,MAAM,CAuCR"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * JSON output formatter for device profiler
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.formatJSON = formatJSON;
7
+ /**
8
+ * Format scan results as JSON
9
+ *
10
+ * @param results - Array of scan results
11
+ * @param options - Scan configuration metadata
12
+ * @returns Formatted JSON string with 2-space indentation
13
+ */
14
+ function formatJSON(results, options) {
15
+ // Calculate summary statistics
16
+ const successful = results.filter((r) => r.success).length;
17
+ const failed = results.length - successful;
18
+ const totalTimeMs = results.reduce((sum, r) => sum + r.timing, 0);
19
+ const averageTimeMs = results.length > 0 ? Math.round((totalTimeMs / results.length) * 100) / 100 : 0;
20
+ // Build output object
21
+ const output = {
22
+ timestamp: new Date().toISOString(),
23
+ scan: {
24
+ type: options.type,
25
+ startAddress: options.startAddress,
26
+ endAddress: options.endAddress,
27
+ batchSize: options.batchSize,
28
+ },
29
+ connection: {
30
+ port: options.port,
31
+ },
32
+ results: results.map((result) => ({
33
+ address: result.address,
34
+ type: result.type,
35
+ success: result.success,
36
+ value: result.value ? result.value.readUInt16BE(0) : null,
37
+ timing: result.timing,
38
+ ...(result.error && { error: result.error }),
39
+ ...(result.errorType && { errorType: result.errorType }),
40
+ })),
41
+ summary: {
42
+ total: results.length,
43
+ successful,
44
+ failed,
45
+ totalTimeMs,
46
+ averageTimeMs,
47
+ },
48
+ };
49
+ return JSON.stringify(output, null, 2);
50
+ }
51
+ //# sourceMappingURL=json-formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-formatter.js","sourceRoot":"","sources":["../../../src/json-formatter.ts"],"names":[],"mappings":";AAAA;;GAEG;;AA4BH,gCA0CC;AAjDD;;;;;;GAMG;AACH,SAAgB,UAAU,CACxB,OAAkC,EAClC,OAA6B;IAE7B,+BAA+B;IAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;IAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,CAAA;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACjE,MAAM,aAAa,GACjB,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IAEjF,sBAAsB;IACtB,MAAM,MAAM,GAAG;QACb,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,EAAE;YACJ,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B;QACD,UAAU,EAAE;YACV,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB;QACD,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAChC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;YACzD,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YAC5C,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;SACzD,CAAC,CAAC;QACH,OAAO,EAAE;YACP,KAAK,EAAE,OAAO,CAAC,MAAM;YACrB,UAAU;YACV,MAAM;YACN,WAAW;YACX,aAAa;SACd;KACF,CAAA;IAED,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AACxC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../../src/program.ts"],"names":[],"mappings":";AAEA;;GAEG;AAIH,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AAsB3C,eAAO,MAAM,OAAO,SAAgB,CAAA"}
1
+ {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../../src/program.ts"],"names":[],"mappings":";AAEA;;GAEG;AAIH,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AAuB3C,eAAO,MAAM,OAAO,SAAgB,CAAA"}
@@ -29,6 +29,9 @@ exports.program
29
29
  .option('--data-bits <bits>', 'Data bits for RTU', parseNumber, 8)
30
30
  .option('--stop-bits <bits>', 'Stop bits for RTU', parseNumber, 1)
31
31
  .option('--timeout <ms>', 'Response timeout in milliseconds', parseNumber, 1000)
32
+ .addOption(new commander_1.Option('-f, --format <format>', 'Output format: table or json')
33
+ .choices(['table', 'json'])
34
+ .default('table'))
32
35
  .action(async (options) => {
33
36
  try {
34
37
  const registerType = options.type === 'input' ? read_tester_js_1.RegisterType.Input : read_tester_js_1.RegisterType.Holding;
@@ -68,6 +71,8 @@ exports.program
68
71
  startAddress: options.start,
69
72
  endAddress: options.end,
70
73
  batchSize: options.batch,
74
+ format: options.format,
75
+ port: options.port,
71
76
  });
72
77
  }
73
78
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"program.js","sourceRoot":"","sources":["../../../src/program.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"program.js","sourceRoot":"","sources":["../../../src/program.ts"],"names":[],"mappings":"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"}