benchlab-pytools 3.0.0__py3-none-any.whl

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 (184) hide show
  1. benchlab/__init__.py +14 -0
  2. benchlab/__main__.py +21 -0
  3. benchlab/config/README.md +325 -0
  4. benchlab/config/__init__.py +9 -0
  5. benchlab/config/config_client.py +631 -0
  6. benchlab/config/config_manager.py +495 -0
  7. benchlab/config/config_tool.py +358 -0
  8. benchlab/config/diff.py +163 -0
  9. benchlab/config/examples/complete_config.json +56 -0
  10. benchlab/config/examples/rgb_lighting.json +24 -0
  11. benchlab/config/examples/simple_fan.json +32 -0
  12. benchlab/config/schema.py +138 -0
  13. benchlab/core/README.md +154 -0
  14. benchlab/core/__init__.py +78 -0
  15. benchlab/core/config.py +145 -0
  16. benchlab/core/datasource.py +1209 -0
  17. benchlab/core/datasource_manager.py +418 -0
  18. benchlab/core/device_registry.py +206 -0
  19. benchlab/core/discovery.py +92 -0
  20. benchlab/core/infrastructure.py +309 -0
  21. benchlab/core/process_manager.py +356 -0
  22. benchlab/core/retry.py +85 -0
  23. benchlab/core/shared_serial.py +235 -0
  24. benchlab/core/statistics.py +224 -0
  25. benchlab/csv_log/README.md +206 -0
  26. benchlab/csv_log/__init__.py +5 -0
  27. benchlab/csv_log/csv_logger_enhanced.py +416 -0
  28. benchlab/csv_log/message_batcher.py +361 -0
  29. benchlab/csv_log/requirements.txt +3 -0
  30. benchlab/csv_log/smart_retry.py +466 -0
  31. benchlab/graph/README.md +117 -0
  32. benchlab/graph/__init__.py +5 -0
  33. benchlab/graph/app.py +353 -0
  34. benchlab/graph/requirements.txt +2 -0
  35. benchlab/graph/runner.py +42 -0
  36. benchlab/graph/ui.py +288 -0
  37. benchlab/hwinfo/README.md +135 -0
  38. benchlab/hwinfo/__init__.py +5 -0
  39. benchlab/hwinfo/hwinfo_export.py +386 -0
  40. benchlab/hwinfo/requirements.txt +1 -0
  41. benchlab/launcher.py +387 -0
  42. benchlab/link/.env.EXAMPLE +10 -0
  43. benchlab/link/README.md +172 -0
  44. benchlab/link/__init__.py +1 -0
  45. benchlab/link/link_main.py +479 -0
  46. benchlab/main.py +462 -0
  47. benchlab/menu.py +729 -0
  48. benchlab/menu_classic.py +410 -0
  49. benchlab/mqtt/README.md +201 -0
  50. benchlab/mqtt/__init__.py +5 -0
  51. benchlab/mqtt/mqtt.config_template +2 -0
  52. benchlab/mqtt/mqtt_publisher.py +540 -0
  53. benchlab/mqtt/requirements.txt +3 -0
  54. benchlab/prefs.py +67 -0
  55. benchlab/restapi/.env.example +17 -0
  56. benchlab/restapi/__init__.py +5 -0
  57. benchlab/restapi/favicon.ico +0 -0
  58. benchlab/restapi/readme.md +202 -0
  59. benchlab/restapi/requirements.txt +5 -0
  60. benchlab/restapi/telemetry_api.py +808 -0
  61. benchlab/sources.py +515 -0
  62. benchlab/tools.py +147 -0
  63. benchlab/tui/README.md +266 -0
  64. benchlab/tui/__init__.py +5 -0
  65. benchlab/tui/config.py +477 -0
  66. benchlab/tui/requirements.txt +2 -0
  67. benchlab/tui/tui_core.py +1298 -0
  68. benchlab/tui/tui_main.py +418 -0
  69. benchlab/vu/README.md +64 -0
  70. benchlab/vu/VU-Server/NOTICE.md +13 -0
  71. benchlab/vu/VU-Server/README.md +80 -0
  72. benchlab/vu/VU-Server/Running_from_source_on_linux.md +97 -0
  73. benchlab/vu/VU-Server/__init__.py +0 -0
  74. benchlab/vu/VU-Server/assets/vu1_hello_world.png +0 -0
  75. benchlab/vu/VU-Server/community_applications.md +13 -0
  76. benchlab/vu/VU-Server/config.yaml +9 -0
  77. benchlab/vu/VU-Server/database.py +256 -0
  78. benchlab/vu/VU-Server/dial_driver.py +534 -0
  79. benchlab/vu/VU-Server/dials/Comms_Hub_Gauge.py +78 -0
  80. benchlab/vu/VU-Server/dials/Comms_Hub_Server.py +100 -0
  81. benchlab/vu/VU-Server/dials/__init__.py +0 -0
  82. benchlab/vu/VU-Server/dials/base_logger.py +100 -0
  83. benchlab/vu/VU-Server/installer/inc/icon.ico +0 -0
  84. benchlab/vu/VU-Server/installer/install.nsi +148 -0
  85. benchlab/vu/VU-Server/make_version.py +40 -0
  86. benchlab/vu/VU-Server/pylintrc +628 -0
  87. benchlab/vu/VU-Server/requirements.txt +9 -0
  88. benchlab/vu/VU-Server/serial_driver.py +244 -0
  89. benchlab/vu/VU-Server/server.py +670 -0
  90. benchlab/vu/VU-Server/server_config.py +255 -0
  91. benchlab/vu/VU-Server/server_dial_handler.py +334 -0
  92. benchlab/vu/VU-Server/vu_notifications.py +24 -0
  93. benchlab/vu/VU-Server/www/android-chrome-192x192.png +0 -0
  94. benchlab/vu/VU-Server/www/android-chrome-512x512.png +0 -0
  95. benchlab/vu/VU-Server/www/apple-touch-icon.png +0 -0
  96. benchlab/vu/VU-Server/www/assets/css/demo.css +291 -0
  97. benchlab/vu/VU-Server/www/assets/css/demo.min.css +9 -0
  98. benchlab/vu/VU-Server/www/assets/css/demo.rtl.css +276 -0
  99. benchlab/vu/VU-Server/www/assets/css/demo.rtl.min.css +9 -0
  100. benchlab/vu/VU-Server/www/assets/css/tabler-flags.css +1084 -0
  101. benchlab/vu/VU-Server/www/assets/css/tabler-flags.min.css +9 -0
  102. benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.css +1084 -0
  103. benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.min.css +9 -0
  104. benchlab/vu/VU-Server/www/assets/css/tabler-payments.css +528 -0
  105. benchlab/vu/VU-Server/www/assets/css/tabler-payments.min.css +9 -0
  106. benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.css +528 -0
  107. benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.min.css +9 -0
  108. benchlab/vu/VU-Server/www/assets/css/tabler-social.css +10 -0
  109. benchlab/vu/VU-Server/www/assets/css/tabler-social.min.css +8 -0
  110. benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.css +10 -0
  111. benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.min.css +8 -0
  112. benchlab/vu/VU-Server/www/assets/css/tabler-vendors.css +1504 -0
  113. benchlab/vu/VU-Server/www/assets/css/tabler-vendors.min.css +9 -0
  114. benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.css +1504 -0
  115. benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.min.css +9 -0
  116. benchlab/vu/VU-Server/www/assets/css/tabler.css +25813 -0
  117. benchlab/vu/VU-Server/www/assets/css/tabler.min.css +13 -0
  118. benchlab/vu/VU-Server/www/assets/css/tabler.rtl.css +25777 -0
  119. benchlab/vu/VU-Server/www/assets/css/tabler.rtl.min.css +13 -0
  120. benchlab/vu/VU-Server/www/assets/css/theme.min.css +261 -0
  121. benchlab/vu/VU-Server/www/assets/img/header.png +0 -0
  122. benchlab/vu/VU-Server/www/assets/img/logo.png +0 -0
  123. benchlab/vu/VU-Server/www/assets/js/dark-theme.js +35 -0
  124. benchlab/vu/VU-Server/www/assets/js/dark-theme.min.js +9 -0
  125. benchlab/vu/VU-Server/www/assets/js/demo.js +132 -0
  126. benchlab/vu/VU-Server/www/assets/js/demo.min.js +9 -0
  127. benchlab/vu/VU-Server/www/assets/js/jquery.min.js +2 -0
  128. benchlab/vu/VU-Server/www/assets/js/tabler.esm.js +7482 -0
  129. benchlab/vu/VU-Server/www/assets/js/tabler.esm.min.js +15 -0
  130. benchlab/vu/VU-Server/www/assets/js/tabler.js +7543 -0
  131. benchlab/vu/VU-Server/www/assets/js/tabler.min.js +15 -0
  132. benchlab/vu/VU-Server/www/assets/js/vu1_api.js +68 -0
  133. benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_key_settings.js +167 -0
  134. benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_keys.js +138 -0
  135. benchlab/vu/VU-Server/www/assets/js/vu1_gui_dial.js +179 -0
  136. benchlab/vu/VU-Server/www/assets/js/vu1_gui_home.js +60 -0
  137. benchlab/vu/VU-Server/www/assets/js/vu1_gui_root.js +125 -0
  138. benchlab/vu/VU-Server/www/favicon-16x16.png +0 -0
  139. benchlab/vu/VU-Server/www/favicon-32x32.png +0 -0
  140. benchlab/vu/VU-Server/www/favicon.ico +0 -0
  141. benchlab/vu/VU-Server/www/favicon.png +0 -0
  142. benchlab/vu/VU-Server/www/index.html +47 -0
  143. benchlab/vu/VU-Server/www/views/api_keys.html +151 -0
  144. benchlab/vu/VU-Server/www/views/dial.html +286 -0
  145. benchlab/vu/VU-Server/www/views/footer.html +27 -0
  146. benchlab/vu/VU-Server/www/views/header.html +86 -0
  147. benchlab/vu/VU-Server/www/views/key_settings.html +132 -0
  148. benchlab/vu/VU-Server/www/views/start.html +124 -0
  149. benchlab/vu/__init__.py +5 -0
  150. benchlab/vu/assets/Barlow-Bold.ttf +0 -0
  151. benchlab/vu/assets/bl_dial_144x200.png +0 -0
  152. benchlab/vu/assets/bl_logo_144x200.png +0 -0
  153. benchlab/vu/devices.py +166 -0
  154. benchlab/vu/requirements.txt +24 -0
  155. benchlab/vu/sensors.py +18 -0
  156. benchlab/vu/vu_dial.config_template +90 -0
  157. benchlab/vu/vu_logo_gen.py +97 -0
  158. benchlab/vu/vu_server.config_template +5 -0
  159. benchlab/vu/vu_server_config.py +40 -0
  160. benchlab/vu/vu_server_manager.py +192 -0
  161. benchlab/vu/vu_tui.py +919 -0
  162. benchlab/vu/vu_updater.py +540 -0
  163. benchlab/wigidash/README.md +182 -0
  164. benchlab/wigidash/__init__.py +5 -0
  165. benchlab/wigidash/assets/Inter-Bold.ttf +0 -0
  166. benchlab/wigidash/assets/Inter.ttf +0 -0
  167. benchlab/wigidash/assets/benchlab.png +0 -0
  168. benchlab/wigidash/benchlab_fleet.py +150 -0
  169. benchlab/wigidash/benchlab_graph.py +517 -0
  170. benchlab/wigidash/benchlab_overview.py +426 -0
  171. benchlab/wigidash/benchlab_telemetry.py +105 -0
  172. benchlab/wigidash/benchlab_ui.py +190 -0
  173. benchlab/wigidash/benchlab_utils.py +182 -0
  174. benchlab/wigidash/requirements.txt +9 -0
  175. benchlab/wigidash/wigidash_device.py +541 -0
  176. benchlab/wigidash/wigidash_manager.py +342 -0
  177. benchlab/wigidash/wigidash_session.py +355 -0
  178. benchlab/wigidash/wigidash_usb.py +247 -0
  179. benchlab/wigidash/wigidash_widget.py +88 -0
  180. benchlab_pytools-3.0.0.dist-info/METADATA +239 -0
  181. benchlab_pytools-3.0.0.dist-info/RECORD +184 -0
  182. benchlab_pytools-3.0.0.dist-info/WHEEL +4 -0
  183. benchlab_pytools-3.0.0.dist-info/entry_points.txt +2 -0
  184. benchlab_pytools-3.0.0.dist-info/licenses/LICENSE +21 -0
benchlab/__init__.py ADDED
@@ -0,0 +1,14 @@
1
+ """
2
+ BENCHLAB Telemetry Package
3
+ """
4
+
5
+ import os as _os
6
+ import sys as _sys
7
+
8
+ # Ensure the repo root (containing bootstrap.py) is importable. Centralized
9
+ # here so menu.py/tools.py don't each need their own sys.path.insert hack.
10
+ _repo_root = _os.path.dirname(_os.path.dirname(_os.path.abspath(__file__)))
11
+ if _repo_root not in _sys.path:
12
+ _sys.path.insert(0, _repo_root)
13
+
14
+ __version__ = "3.0.0"
benchlab/__main__.py ADDED
@@ -0,0 +1,21 @@
1
+ """Entry point for the Benchlab package.
2
+
3
+ Running ``python -m benchlab`` (or executing this file directly) will
4
+ invoke the package's :func:`benchlab.main.main` function. The module
5
+ now includes a short
6
+ docstring, basic logging, and error handling to provide a clearer failure mode
7
+ if the import or execution of ``main`` raises an exception.
8
+ """
9
+
10
+ from .main import main
11
+ import logging
12
+ import sys
13
+
14
+ logger = logging.getLogger("benchlab.__main__")
15
+
16
+ if __name__ == "__main__":
17
+ try:
18
+ main()
19
+ except Exception as exc: # pragma: no cover – defensive guard
20
+ logger.error("Failed to execute Benchlab main entry point: %s", exc)
21
+ sys.exit(1)
@@ -0,0 +1,325 @@
1
+ # BENCHLAB Device Configuration Tool
2
+
3
+ A command-line tool for importing and exporting BENCHLAB device configuration via JSON files. Supports both direct serial (pycore) and Windows named pipe (BL_Service) data sources.
4
+
5
+ ## Features
6
+
7
+ - **Export Configuration**: Read current device settings and save to JSON
8
+ - **Import Configuration**: Apply JSON configuration to devices
9
+ - **Multi-Source Support**: Works with both direct serial and named pipe connections
10
+ - **Interactive Mode**: Simple interface for loading JSON configs
11
+ - **Validation**: Schema validation with detailed error messages
12
+ - **Batch Operations**: Configure multiple devices from a single JSON file
13
+
14
+ ## Installation
15
+
16
+ The config tool is included in BENCHLAB PyTools. Ensure you have the required dependencies:
17
+
18
+ ```bash
19
+ pip install -r requirements.txt
20
+ ```
21
+
22
+ For direct serial support, you also need:
23
+ ```bash
24
+ pip install benchlab-pycore
25
+ ```
26
+
27
+ For named pipe support (Windows only), you need:
28
+ ```bash
29
+ pip install pywin32
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### Interactive Mode
35
+
36
+ Simply run the tool without arguments to enter interactive mode:
37
+
38
+ ```bash
39
+ python -m benchlab -config
40
+ ```
41
+
42
+ This will:
43
+ 1. List available devices
44
+ 2. Ask whether you want to import or export configuration
45
+ 3. For import: prompt for JSON file, confirm before applying, and ask whether to save to flash
46
+ 4. For export: prompt for output filename and save current device config
47
+
48
+ ### Command-Line Mode
49
+
50
+ #### List Devices
51
+
52
+ ```bash
53
+ # List devices via direct serial
54
+ python -m benchlab -config --list
55
+
56
+ # List devices via named pipe (Windows only)
57
+ python -m benchlab -config --list --source named_pipe
58
+ ```
59
+
60
+ #### Export Configuration
61
+
62
+ ```bash
63
+ # Export from first available device
64
+ python -m benchlab -config --export my_config.json
65
+
66
+ # Export from specific device
67
+ python -m benchlab -config --export my_config.json --device COM4
68
+
69
+ # Export via named pipe
70
+ python -m benchlab -config --export my_config.json --source named_pipe
71
+ ```
72
+
73
+ #### Import Configuration
74
+
75
+ ```bash
76
+ # Import configuration - shows a diff of what would actually change on the
77
+ # device (current value -> new value, only changed fields), then asks for
78
+ # confirmation before applying
79
+ python -m benchlab -config --import my_config.json
80
+
81
+ # Preview changes without applying anything (still connects to the device
82
+ # and reads its current config to compute the diff)
83
+ python -m benchlab -config --import my_config.json --dry-run
84
+
85
+ # Apply without the confirmation prompt (diff is still printed) - for
86
+ # scripts/automation
87
+ python -m benchlab -config --import my_config.json --yes
88
+
89
+ # Import via named pipe
90
+ python -m benchlab -config --import my_config.json --source named_pipe
91
+ ```
92
+
93
+ ## JSON Configuration Format
94
+
95
+ ### Basic Structure
96
+
97
+ ```json
98
+ {
99
+ "version": "1.0",
100
+ "description": "Configuration description",
101
+ "devices": [
102
+ {
103
+ "selector": {
104
+ "type": "any",
105
+ "value": null
106
+ },
107
+ "deviceName": "BENCHLAB_MAIN",
108
+ "fanProfiles": [...],
109
+ "rgbProfiles": [...],
110
+ "saveToFlash": true
111
+ }
112
+ ]
113
+ }
114
+ ```
115
+
116
+ ### Device Selector Types
117
+
118
+ - **`any`**: Select first available device
119
+ - **`guid`**: Match by device UID/GUID (recommended - portable across systems)
120
+ - **`port`**: Match by serial port (e.g., "COM4" - not portable)
121
+ - **`productId`**: Match by product ID (0x10 or 0x11)
122
+ - **`pipeName`**: Match by named pipe name (named_pipe source only)
123
+
124
+ **Note:** When exporting, the tool automatically uses `guid` selector with the device UID for portability. This allows you to export configuration on one system and import it on another, and the tool will find the same device regardless of which COM port it's connected to.
125
+
126
+ ### Fan Configuration
127
+
128
+ ```json
129
+ {
130
+ "fanId": 0,
131
+ "FanMode": 0,
132
+ "TempSource": 0,
133
+ "Temp": [300, 600],
134
+ "Duty": [30, 80],
135
+ "RampStep": 5,
136
+ "FixedDuty": 50,
137
+ "MinDuty": 20,
138
+ "MaxDuty": 100,
139
+ "FanStop": 0
140
+ }
141
+ ```
142
+
143
+ **Fan Modes:**
144
+ - `0` = Auto (temperature-based curve)
145
+ - `1` = Fixed (constant duty cycle)
146
+ - `2` = External (controlled by external signal)
147
+
148
+ **Temperature Source:**
149
+ - `0` = Auto
150
+ - `1-4` = TS_1 through TS_4
151
+ - `5` = Ambient
152
+
153
+ **Temperature Values:** In tenths of °C (e.g., 300 = 30.0°C)
154
+
155
+ ### RGB Configuration
156
+
157
+ ```json
158
+ {
159
+ "profileId": 0,
160
+ "Mode": 9,
161
+ "Red": 255,
162
+ "Green": 0,
163
+ "Blue": 0,
164
+ "Direction": 0,
165
+ "Speed": 50
166
+ }
167
+ ```
168
+
169
+ **RGB Modes:**
170
+ - `0` = Rainbow Cycle
171
+ - `1` = Rainbow Wave
172
+ - `2` = Color Shift
173
+ - `3` = Color Pulse
174
+ - `4` = Color Wave
175
+ - `5` = Breathing
176
+ - `6` = Spectrum Cycle
177
+ - `7` = Alternating
178
+ - `8` = Candle
179
+ - `9` = Single Color
180
+
181
+ ## Examples
182
+
183
+ Example configurations are provided in `benchlab/config/examples/`:
184
+
185
+ ### Simple Fan Control
186
+
187
+ Set all fans to 50% fixed speed:
188
+
189
+ ```bash
190
+ python -m benchlab -config --import benchlab/config/examples/simple_fan.json
191
+ ```
192
+
193
+ ### RGB Lighting
194
+
195
+ Set RGB to solid blue:
196
+
197
+ ```bash
198
+ python -m benchlab -config --import benchlab/config/examples/rgb_lighting.json
199
+ ```
200
+
201
+ ### Complete Configuration
202
+
203
+ Full device setup with fan curves, RGB, and device name:
204
+
205
+ ```bash
206
+ python -m benchlab -config --import benchlab/config/examples/complete_config.json
207
+ ```
208
+
209
+ ## Data Sources
210
+
211
+ ### Direct Serial (pycore)
212
+
213
+ Uses direct USB-to-serial communication via the `benchlab-pycore` library. This is the default source and works on all platforms.
214
+
215
+ **Advantages:**
216
+ - Cross-platform (Windows, Linux, macOS)
217
+ - No additional services required
218
+ - Direct hardware access
219
+
220
+ **Limitations:**
221
+ - Exclusive port access (only one tool can connect at a time)
222
+ - Requires pycore library
223
+
224
+ ### Named Pipe (Windows Service)
225
+
226
+ Uses the Windows BL_Service named pipe interface for communication.
227
+
228
+ **Advantages:**
229
+ - Multiple tools can access device simultaneously
230
+ - Integrates with Windows service
231
+ - No direct serial port management
232
+
233
+ **Limitations:**
234
+ - Windows only
235
+ - Requires BL_Service to be running
236
+ - Requires pywin32 library
237
+
238
+ ## Configuration Profiles
239
+
240
+ ### Profile IDs
241
+
242
+ - **Fan Profiles**: 0-2 (3 profiles available)
243
+ - **RGB Profiles**: 0-1 (2 profiles available)
244
+
245
+ ### Fan IDs
246
+
247
+ - **Fan Channels**: 0-8 (9 fans available)
248
+
249
+ ## Saving to Flash
250
+
251
+ Set `"saveToFlash": true` in the device configuration to persist settings to device flash memory. Without this, changes are only applied to RAM and will be lost on device reset.
252
+
253
+ In **interactive mode**, you will be prompted at runtime whether to save to flash, which overrides the `saveToFlash` value in the JSON file. In **command-line mode** (`--import`), the `saveToFlash` value from the JSON file is used directly.
254
+
255
+ ## Error Handling
256
+
257
+ The tool provides detailed error messages for:
258
+ - Invalid JSON syntax
259
+ - Schema validation failures
260
+ - Device connection errors
261
+ - Configuration write failures
262
+
263
+ Use `--dry-run` to preview exactly what would change on the device (connects and reads current config to compute a diff) without applying anything. Use `--yes` to skip the confirmation prompt while still showing the diff, for scripted/automated use.
264
+
265
+ ## Troubleshooting
266
+
267
+ ### No Devices Found
268
+
269
+ **Direct Serial:**
270
+ - Check USB connection
271
+ - Verify device is powered on
272
+ - Check serial port permissions (Linux: add user to `dialout` group)
273
+
274
+ **Named Pipe:**
275
+ - Ensure BL_Service is running
276
+ - Check Windows service status
277
+ - Verify device is connected to service
278
+
279
+ ### Import Fails
280
+
281
+ - Use `--dry-run` to validate JSON syntax
282
+ - Check device selector matches available devices
283
+ - Verify all required fields are present
284
+ - Check value ranges (duty 0-100%, temp in 0.1°C units)
285
+
286
+ ### Permission Errors
287
+
288
+ **Linux:**
289
+ ```bash
290
+ sudo usermod -a -G dialout $USER
291
+ # Log out and back in
292
+ ```
293
+
294
+ **Windows:**
295
+ - Run as Administrator if needed
296
+ - Check BL_Service permissions
297
+
298
+ ## API Reference
299
+
300
+ For programmatic use, import the configuration manager:
301
+
302
+ ```python
303
+ from benchlab.config.config_manager import ConfigManager
304
+
305
+ # Create manager
306
+ manager = ConfigManager(source='direct')
307
+
308
+ # Discover devices
309
+ devices = manager.discover_devices()
310
+
311
+ # Export configuration
312
+ manager.export_config('COM4', 'output.json')
313
+
314
+ # Import configuration
315
+ manager.import_config('input.json', dry_run=False)
316
+ ```
317
+
318
+ ## See Also
319
+
320
+ - [BENCHLAB PyTools Documentation](../../README.md) - Main PyTools documentation
321
+ - [benchlab-pycore](https://github.com/BenchLab-io/benchlab-pycore) - PyCore library used for direct serial configuration I/O
322
+
323
+ ## License
324
+
325
+ Part of BENCHLAB PyTools. See main project license for details.
@@ -0,0 +1,9 @@
1
+ """
2
+ BENCHLAB Device Configuration Tool
3
+
4
+ Import/export device configuration (fan profiles, RGB, calibration) via
5
+ JSON files.
6
+ Supports both direct serial (pycore) and named pipe (Windows service) sources.
7
+ """
8
+
9
+ __version__ = "1.0.0"