@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 +6 -0
- package/README.md +139 -8
- package/dist/cjs/src/cli.d.ts +4 -0
- package/dist/cjs/src/cli.d.ts.map +1 -1
- package/dist/cjs/src/cli.js +28 -11
- package/dist/cjs/src/cli.js.map +1 -1
- package/dist/cjs/src/json-formatter.d.ts +29 -0
- package/dist/cjs/src/json-formatter.d.ts.map +1 -0
- package/dist/cjs/src/json-formatter.js +51 -0
- package/dist/cjs/src/json-formatter.js.map +1 -0
- package/dist/cjs/src/program.d.ts.map +1 -1
- package/dist/cjs/src/program.js +5 -0
- package/dist/cjs/src/program.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/cli.d.ts +4 -0
- package/dist/esm/src/cli.d.ts.map +1 -1
- package/dist/esm/src/cli.js +29 -12
- package/dist/esm/src/cli.js.map +1 -1
- package/dist/esm/src/json-formatter.d.ts +29 -0
- package/dist/esm/src/json-formatter.d.ts.map +1 -0
- package/dist/esm/src/json-formatter.js +48 -0
- package/dist/esm/src/json-formatter.js.map +1 -0
- package/dist/esm/src/program.d.ts.map +1 -1
- package/dist/esm/src/program.js +5 -0
- package/dist/esm/src/program.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +2 -2
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
|
-
- `--
|
|
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
|
-
|
|
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
|
-
-
|
|
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
|
package/dist/cjs/src/cli.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/cjs/src/cli.js
CHANGED
|
@@ -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
|
-
|
|
20
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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();
|
package/dist/cjs/src/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli.ts"],"names":[],"mappings":";AAAA;;GAEG;;
|
|
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;
|
|
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"}
|
package/dist/cjs/src/program.js
CHANGED
|
@@ -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":";;AAEA;;GAEG;;;AAGH,oDAAsD;AACtD,yCAA2C;AAE3C,qCAAyC;AACzC,iDAAmD;AACnD,qDAA+C;
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../../../src/program.ts"],"names":[],"mappings":"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"}
|