benchlab-pytools 3.0.1__tar.gz → 3.0.2__tar.gz
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.
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/CHANGELOG.md +13 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/PKG-INFO +1 -1
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/__init__.py +1 -1
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/config_client.py +3 -4
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/config_manager.py +5 -6
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/datasource.py +4 -7
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/datasource_manager.py +6 -7
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/infrastructure.py +6 -8
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/process_manager.py +1 -2
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/statistics.py +3 -4
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/csv_logger_enhanced.py +2 -4
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/message_batcher.py +2 -5
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/smart_retry.py +6 -8
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/app.py +9 -6
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/hwinfo_export.py +4 -6
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/link_main.py +3 -5
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/sources.py +1 -6
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/tui_core.py +27 -44
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/tui_main.py +9 -14
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_server_manager.py +2 -4
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_tui.py +25 -32
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_updater.py +3 -3
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_fleet.py +2 -2
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_graph.py +3 -4
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_device.py +2 -2
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_manager.py +3 -6
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_session.py +16 -22
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_usb.py +6 -10
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/wigidash_widget.py +2 -4
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/.flake8 +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/.gitignore +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/CONTRIBUTING.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/LICENSE +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/__main__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/bootstrap.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/config_tool.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/diff.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/examples/complete_config.json +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/examples/rgb_lighting.json +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/examples/simple_fan.json +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/schema.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/test_config_client.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/test_config_manager.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/config/test_diff.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/config.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/device_registry.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/discovery.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/retry.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/core/shared_serial.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/csv_log/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/runner.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/test_graph.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/graph/ui.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/hwinfo/test_hwinfo_export.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/launcher.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/.env.EXAMPLE +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/link/test_link_main.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/main.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/menu.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/menu_classic.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/mqtt.config_template +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/mqtt_publisher.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/mqtt/test_mqtt_publisher.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/prefs.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/.env.example +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/favicon.ico +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/readme.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/telemetry_api.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/restapi/test_server.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tools.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/config.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/test_tui_core.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/tui/test_tui_main.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/NOTICE.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/Running_from_source_on_linux.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/assets/vu1_hello_world.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/community_applications.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/config.yaml +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/database.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dial_driver.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/Comms_Hub_Gauge.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/Comms_Hub_Server.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/dials/base_logger.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/installer/inc/icon.ico +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/installer/install.nsi +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/make_version.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/pylintrc +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/serial_driver.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/server.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/server_config.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/server_dial_handler.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/vu_notifications.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/android-chrome-192x192.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/android-chrome-512x512.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/apple-touch-icon.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.rtl.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/demo.rtl.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.rtl.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/tabler.rtl.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/css/theme.min.css +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/img/header.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/img/logo.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/dark-theme.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/dark-theme.min.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/demo.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/demo.min.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/jquery.min.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.esm.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.esm.min.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/tabler.min.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_api.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_key_settings.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_keys.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_dial.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_home.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/assets/js/vu1_gui_root.js +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon-16x16.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon-32x32.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon.ico +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/favicon.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/index.html +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/api_keys.html +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/dial.html +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/footer.html +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/header.html +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/key_settings.html +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/VU-Server/www/views/start.html +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/assets/Barlow-Bold.ttf +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/assets/bl_dial_144x200.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/assets/bl_logo_144x200.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/devices.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/sensors.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/test_devices.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/test_vu_server_config.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/test_vu_server_manager.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/test_vu_tui.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_dial.config_template +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_logo_gen.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_server.config_template +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/vu/vu_server_config.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/README.md +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/__init__.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/assets/Inter-Bold.ttf +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/assets/Inter.ttf +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/assets/benchlab.png +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_overview.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_telemetry.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_ui.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/benchlab_utils.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/requirements.txt +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab/wigidash/test_wigidash.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/benchlab.py +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/pyproject.toml +0 -0
- {benchlab_pytools-3.0.1 → benchlab_pytools-3.0.2}/pytest.ini +0 -0
|
@@ -4,6 +4,18 @@ All notable changes to BENCHLAB PyTools are documented here. Format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
|
|
5
5
|
[SemVer](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [3.0.2] - 2026-08-18
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Several f-strings had their `{...}` expression split across a line
|
|
11
|
+
break, which is [PEP 701](https://peps.python.org/pep-0701/) syntax
|
|
12
|
+
only valid on Python 3.12+. Despite `requires-python = ">=3.10"`, this
|
|
13
|
+
raised `SyntaxError` immediately on 3.10/3.11 (e.g. `benchlab -tui`
|
|
14
|
+
failing with `SyntaxError: unterminated string literal` in
|
|
15
|
+
`benchlab/core/datasource.py`) — invisible in CI since every workflow
|
|
16
|
+
pins Python 3.13. Collapsed all such f-strings back onto single lines
|
|
17
|
+
across 27 files.
|
|
18
|
+
|
|
7
19
|
## [3.0.1] - 2026-08-18
|
|
8
20
|
|
|
9
21
|
### Fixed
|
|
@@ -55,5 +67,6 @@ export, MQTT publisher, VU dials, WigiDash, and config import/export tools,
|
|
|
55
67
|
sharing a common data-source layer (direct serial, FastAPI, MQTT, named
|
|
56
68
|
pipe, service HTTP).
|
|
57
69
|
|
|
70
|
+
[3.0.2]: https://github.com/BenchLab-io/benchlab-pytools/compare/v3.0.1...v3.0.2
|
|
58
71
|
[3.0.1]: https://github.com/BenchLab-io/benchlab-pytools/compare/v3.0.0...v3.0.1
|
|
59
72
|
[3.0.0]: https://github.com/BenchLab-io/benchlab-pytools/compare/v0.8.2...v3.0.0
|
|
@@ -177,8 +177,8 @@ class DirectConfigClient(ConfigClient):
|
|
|
177
177
|
|
|
178
178
|
self.product_id = info.get('ProductId')
|
|
179
179
|
logger.info(
|
|
180
|
-
f"Connected to device on {port},
|
|
181
|
-
|
|
180
|
+
f"Connected to device on {port}, "
|
|
181
|
+
f"Product ID: 0x{self.product_id:02X}")
|
|
182
182
|
|
|
183
183
|
def get_device_info(self) -> Optional[Dict[str, Any]]:
|
|
184
184
|
"""Get device information."""
|
|
@@ -465,8 +465,7 @@ class NamedPipeConfigClient(ConfigClient):
|
|
|
465
465
|
win32pipe.WaitNamedPipe(path, 5000)
|
|
466
466
|
except pywintypes.error as e:
|
|
467
467
|
raise ConnectionError(
|
|
468
|
-
f"Pipe '{
|
|
469
|
-
self.pipe_name}' not available: {e}") from e
|
|
468
|
+
f"Pipe '{self.pipe_name}' not available: {e}") from e
|
|
470
469
|
|
|
471
470
|
self.handle = win32file.CreateFile(
|
|
472
471
|
path,
|
|
@@ -55,8 +55,7 @@ class ConfigManager:
|
|
|
55
55
|
from benchlab_pycore.core import get_fleet_info
|
|
56
56
|
devices = get_fleet_info()
|
|
57
57
|
logger.info(
|
|
58
|
-
f"Discovered {
|
|
59
|
-
len(devices)} device(s) via direct serial")
|
|
58
|
+
f"Discovered {len(devices)} device(s) via direct serial")
|
|
60
59
|
return devices
|
|
61
60
|
except Exception as e:
|
|
62
61
|
logger.error(f"Failed to discover direct devices: {e}")
|
|
@@ -357,8 +356,8 @@ class ConfigManager:
|
|
|
357
356
|
device_config.selector.model_dump(), devices)
|
|
358
357
|
if not identifier:
|
|
359
358
|
logger.error(
|
|
360
|
-
|
|
361
|
-
|
|
359
|
+
"Device not found matching selector: "
|
|
360
|
+
f"{device_config.selector}")
|
|
362
361
|
continue
|
|
363
362
|
|
|
364
363
|
logger.info(f"Selected: {identifier}")
|
|
@@ -453,8 +452,8 @@ class ConfigManager:
|
|
|
453
452
|
if not client.write_fan_config(
|
|
454
453
|
profile.profileId, fan_id, fan_dict):
|
|
455
454
|
logger.error(
|
|
456
|
-
|
|
457
|
-
|
|
455
|
+
"Failed to write fan config "
|
|
456
|
+
f"{profile.profileId}/{fan_id}")
|
|
458
457
|
success = False
|
|
459
458
|
|
|
460
459
|
# Apply RGB profiles
|
|
@@ -372,8 +372,7 @@ class FastAPIDataSource(DataSource):
|
|
|
372
372
|
return True
|
|
373
373
|
else:
|
|
374
374
|
logger.error(
|
|
375
|
-
f"FastAPI health check returned {
|
|
376
|
-
response.status_code}")
|
|
375
|
+
f"FastAPI health check returned {response.status_code}")
|
|
377
376
|
except Exception as e:
|
|
378
377
|
logger.error(f"Failed to connect to FastAPI server: {e}")
|
|
379
378
|
|
|
@@ -1025,9 +1024,8 @@ class ServiceHttpDataSource(DataSource):
|
|
|
1025
1024
|
|
|
1026
1025
|
if resp.status_code != 200:
|
|
1027
1026
|
logger.error(
|
|
1028
|
-
f"BenchLab service health check failed
|
|
1029
|
-
|
|
1030
|
-
self.base_url}/health")
|
|
1027
|
+
f"BenchLab service health check failed "
|
|
1028
|
+
f"(HTTP {resp.status_code}) at {self.base_url}/health")
|
|
1031
1029
|
return False
|
|
1032
1030
|
|
|
1033
1031
|
# Fetch initial device list
|
|
@@ -1051,8 +1049,7 @@ class ServiceHttpDataSource(DataSource):
|
|
|
1051
1049
|
target=self._worker_loop, daemon=True)
|
|
1052
1050
|
self._worker_thread.start()
|
|
1053
1051
|
logger.info(
|
|
1054
|
-
f"Connected to BenchLab service HTTP API at {
|
|
1055
|
-
self.base_url}")
|
|
1052
|
+
f"Connected to BenchLab service HTTP API at {self.base_url}")
|
|
1056
1053
|
return True
|
|
1057
1054
|
|
|
1058
1055
|
def disconnect(self) -> None:
|
|
@@ -109,14 +109,14 @@ class DataSourceManager:
|
|
|
109
109
|
self._datasource = create_datasource(self.source_type, **kwargs)
|
|
110
110
|
|
|
111
111
|
if not self._datasource.connect():
|
|
112
|
-
self._last_error =
|
|
113
|
-
self.source_type} datasource"
|
|
112
|
+
self._last_error = (
|
|
113
|
+
f"Failed to connect to {self.source_type} datasource")
|
|
114
114
|
return False
|
|
115
115
|
|
|
116
116
|
devices = self._datasource.list_devices()
|
|
117
117
|
if not devices:
|
|
118
|
-
self._last_error =
|
|
119
|
-
self.source_type}"
|
|
118
|
+
self._last_error = (
|
|
119
|
+
f"No devices available via {self.source_type}")
|
|
120
120
|
return False
|
|
121
121
|
|
|
122
122
|
if uid and any(d.get('uid') == uid for d in devices):
|
|
@@ -153,9 +153,8 @@ class DataSourceManager:
|
|
|
153
153
|
self._worker_thread.start()
|
|
154
154
|
|
|
155
155
|
logger.info(
|
|
156
|
-
f"Connected to {
|
|
157
|
-
|
|
158
|
-
self._selected_uid}")
|
|
156
|
+
f"Connected to {self.source_type} datasource, "
|
|
157
|
+
f"selected device: {self._selected_uid}")
|
|
159
158
|
return True
|
|
160
159
|
|
|
161
160
|
except Exception as e:
|
|
@@ -80,9 +80,8 @@ class InfrastructureManager:
|
|
|
80
80
|
return True
|
|
81
81
|
|
|
82
82
|
logger.info(
|
|
83
|
-
f"Starting FastAPI server on
|
|
84
|
-
|
|
85
|
-
self.fastapi_port}")
|
|
83
|
+
f"Starting FastAPI server on "
|
|
84
|
+
f"{self.fastapi_host}:{self.fastapi_port}")
|
|
86
85
|
|
|
87
86
|
try:
|
|
88
87
|
# Start FastAPI server as subprocess
|
|
@@ -107,8 +106,8 @@ class InfrastructureManager:
|
|
|
107
106
|
if self._wait_for_port(
|
|
108
107
|
self.fastapi_host, self.fastapi_port, timeout):
|
|
109
108
|
logger.info(
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
"FastAPI server started on port "
|
|
110
|
+
f"{self.fastapi_port}")
|
|
112
111
|
return True
|
|
113
112
|
else:
|
|
114
113
|
logger.error("FastAPI server failed to start")
|
|
@@ -171,9 +170,8 @@ class InfrastructureManager:
|
|
|
171
170
|
return True
|
|
172
171
|
|
|
173
172
|
logger.info(
|
|
174
|
-
f"Starting MQTT publisher to
|
|
175
|
-
|
|
176
|
-
self.mqtt_port}")
|
|
173
|
+
f"Starting MQTT publisher to "
|
|
174
|
+
f"{self.mqtt_broker}:{self.mqtt_port}")
|
|
177
175
|
|
|
178
176
|
try:
|
|
179
177
|
self._stop_event.clear()
|
|
@@ -202,10 +202,9 @@ class StatsFormatter:
|
|
|
202
202
|
if min_val is None or max_val is None or avg_val is None:
|
|
203
203
|
return ""
|
|
204
204
|
|
|
205
|
-
return
|
|
206
|
-
min_val:.{decimals}f}-{
|
|
207
|
-
|
|
208
|
-
avg_val:.{decimals}f}{unit}"
|
|
205
|
+
return (
|
|
206
|
+
f"{min_val:.{decimals}f}-{max_val:.{decimals}f} "
|
|
207
|
+
f"~{avg_val:.{decimals}f}{unit}")
|
|
209
208
|
|
|
210
209
|
|
|
211
210
|
# Convenience function for creating a stats callback
|
|
@@ -141,10 +141,8 @@ class EnhancedCSVLogger:
|
|
|
141
141
|
print("\n--- Available Devices ---")
|
|
142
142
|
for i, dev in enumerate(devices, 1):
|
|
143
143
|
print(
|
|
144
|
-
f" {i}: Port: {
|
|
145
|
-
|
|
146
|
-
dev.uid} FW: {
|
|
147
|
-
dev.firmware}")
|
|
144
|
+
f" {i}: Port: {dev.port:<12} UID: {dev.uid} "
|
|
145
|
+
f"FW: {dev.firmware}")
|
|
148
146
|
|
|
149
147
|
selection = input(
|
|
150
148
|
"\nEnter device numbers (comma-separated), 'all', "
|
|
@@ -95,9 +95,7 @@ class MessageBatcher:
|
|
|
95
95
|
(self.metrics.avg_flush_time * (n - 1) + elapsed) / n
|
|
96
96
|
)
|
|
97
97
|
self.logger.debug(
|
|
98
|
-
f"Flushed {
|
|
99
|
-
len(messages_to_flush)} messages in {
|
|
100
|
-
elapsed:.3f}s")
|
|
98
|
+
f"Flushed {len(messages_to_flush)} messages in {elapsed:.3f}s")
|
|
101
99
|
return True
|
|
102
100
|
|
|
103
101
|
except Exception as e:
|
|
@@ -222,8 +220,7 @@ class CSVBatchWriter:
|
|
|
222
220
|
elif self.format == "json":
|
|
223
221
|
self._write_json_batch(file_info, messages_to_write)
|
|
224
222
|
self.logger.debug(
|
|
225
|
-
f"Wrote {
|
|
226
|
-
len(messages_to_write)} rows for {uid}")
|
|
223
|
+
f"Wrote {len(messages_to_write)} rows for {uid}")
|
|
227
224
|
except Exception as e:
|
|
228
225
|
self.logger.error(f"Failed to write batch for {uid}: {e}")
|
|
229
226
|
buf.extend(messages_to_write) # restore on failure
|
|
@@ -104,8 +104,8 @@ class CircuitBreaker:
|
|
|
104
104
|
if (self.config.circuit_breaker_enabled and
|
|
105
105
|
self.failure_count >= self.config.circuit_failure_threshold):
|
|
106
106
|
self.logger.warning(
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
"Circuit breaker: opening after "
|
|
108
|
+
f"{self.failure_count} failures")
|
|
109
109
|
self.state = CircuitState.OPEN
|
|
110
110
|
|
|
111
111
|
|
|
@@ -144,9 +144,8 @@ class SmartRetryManager:
|
|
|
144
144
|
|
|
145
145
|
if attempt == self.config.max_retries:
|
|
146
146
|
self.logger.error(
|
|
147
|
-
f"Max retries ({
|
|
148
|
-
|
|
149
|
-
func.__name__}")
|
|
147
|
+
f"Max retries ({self.config.max_retries}) "
|
|
148
|
+
f"exceeded for {func.__name__}")
|
|
150
149
|
raise e
|
|
151
150
|
|
|
152
151
|
# Calculate delay
|
|
@@ -242,9 +241,8 @@ class AdaptiveRetryManager:
|
|
|
242
241
|
|
|
243
242
|
if attempt == self.config.max_retries:
|
|
244
243
|
self.logger.error(
|
|
245
|
-
f"Max retries ({
|
|
246
|
-
|
|
247
|
-
func.__name__}")
|
|
244
|
+
f"Max retries ({self.config.max_retries}) "
|
|
245
|
+
f"exceeded for {func.__name__}")
|
|
248
246
|
raise e
|
|
249
247
|
|
|
250
248
|
# Calculate adaptive delay
|
|
@@ -263,12 +263,15 @@ class GraphApp:
|
|
|
263
263
|
min_y - margin, max_y + margin)
|
|
264
264
|
|
|
265
265
|
s = self.session_stats
|
|
266
|
-
min_text =
|
|
267
|
-
s['min']:.2f}"
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
266
|
+
min_text = (
|
|
267
|
+
f"Min: {s['min']:.2f}"
|
|
268
|
+
if s["min"] is not None else "Min: --")
|
|
269
|
+
max_text = (
|
|
270
|
+
f"Max: {s['max']:.2f}"
|
|
271
|
+
if s["max"] is not None else "Max: --")
|
|
272
|
+
avg_text = (
|
|
273
|
+
f"Avg: {s['avg']:.2f}"
|
|
274
|
+
if s["avg"] is not None else "Avg: --")
|
|
272
275
|
for tag, text in (
|
|
273
276
|
("graph_min", min_text),
|
|
274
277
|
("graph_min_float", min_text),
|
|
@@ -71,8 +71,7 @@ def write_hwinfo_sensor(device_name, sensor_type, idx, name, value, unit=None):
|
|
|
71
71
|
# Write Value
|
|
72
72
|
if isinstance(value, float):
|
|
73
73
|
winreg.SetValueEx(
|
|
74
|
-
key, "Value", 0, winreg.REG_SZ, f"{
|
|
75
|
-
value:.3f}")
|
|
74
|
+
key, "Value", 0, winreg.REG_SZ, f"{value:.3f}")
|
|
76
75
|
else:
|
|
77
76
|
winreg.SetValueEx(key, "Value", 0, winreg.REG_SZ, str(value))
|
|
78
77
|
|
|
@@ -156,8 +155,7 @@ def _export_grouped(device_name: str, grouped_sensors: dict):
|
|
|
156
155
|
write_hwinfo_sensor(device_name, group, idx, key, value, unit)
|
|
157
156
|
|
|
158
157
|
summary = ", ".join(
|
|
159
|
-
f"{k}: {
|
|
160
|
-
len(v)}" for k,
|
|
158
|
+
f"{k}: {len(v)}" for k,
|
|
161
159
|
v in grouped_sensors.items() if v)
|
|
162
160
|
logger.debug("Device %s export summary: %s", device_name, summary)
|
|
163
161
|
|
|
@@ -308,8 +306,8 @@ def export_all_devices(update_interval=1, datasource=None):
|
|
|
308
306
|
"HWiNFO export is only supported on Windows. "
|
|
309
307
|
"Please run on a Windows system.")
|
|
310
308
|
raise RuntimeError(
|
|
311
|
-
|
|
312
|
-
|
|
309
|
+
"HWiNFO export requires Windows. "
|
|
310
|
+
f"Current platform: {sys.platform}")
|
|
313
311
|
|
|
314
312
|
# Remove only old BenchLab entries, not user-created sensors
|
|
315
313
|
try:
|
|
@@ -217,8 +217,7 @@ class CloudMQTTClient:
|
|
|
217
217
|
time.sleep(0.1)
|
|
218
218
|
if not self._connected:
|
|
219
219
|
logger.error(
|
|
220
|
-
f"Timed out connecting to {host}:{
|
|
221
|
-
self.cfg['port']}")
|
|
220
|
+
f"Timed out connecting to {host}:{self.cfg['port']}")
|
|
222
221
|
return False
|
|
223
222
|
logger.info(f"Connected to cloud broker {host}:{self.cfg['port']}")
|
|
224
223
|
return True
|
|
@@ -229,9 +228,8 @@ class CloudMQTTClient:
|
|
|
229
228
|
def reconnect(self) -> bool:
|
|
230
229
|
"""Attempt to reconnect using a fresh client."""
|
|
231
230
|
logger.info(
|
|
232
|
-
f"Reconnecting to cloud broker
|
|
233
|
-
|
|
234
|
-
self.cfg['port']}...")
|
|
231
|
+
f"Reconnecting to cloud broker "
|
|
232
|
+
f"{self.cfg['host']}:{self.cfg['port']}...")
|
|
235
233
|
try:
|
|
236
234
|
self._client.loop_stop()
|
|
237
235
|
except Exception:
|
|
@@ -145,12 +145,7 @@ import asyncio
|
|
|
145
145
|
from amqtt.broker import Broker
|
|
146
146
|
|
|
147
147
|
config = {{
|
|
148
|
-
"listeners": {{
|
|
149
|
-
"default": {{
|
|
150
|
-
"type": "tcp",
|
|
151
|
-
"bind": "0.0.0.0:{port}",
|
|
152
|
-
}},
|
|
153
|
-
}},
|
|
148
|
+
"listeners": {{"default": {{"type": "tcp", "bind": "0.0.0.0:{port}"}}}},
|
|
154
149
|
"auth": {{"allow-anonymous": True}},
|
|
155
150
|
"topic-check": {{"enabled": False}},
|
|
156
151
|
}}
|
|
@@ -210,9 +210,9 @@ class TUICore:
|
|
|
210
210
|
|
|
211
211
|
def _render_size_warning(self, width: int, height: int):
|
|
212
212
|
msg = (
|
|
213
|
-
f" Terminal too small ({width}x{height})"
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
f" Terminal too small ({width}x{height})"
|
|
214
|
+
f" — resize to "
|
|
215
|
+
f"{Config.MIN_TERMINAL_COLS}x{Config.MIN_TERMINAL_ROWS} ")
|
|
216
216
|
try:
|
|
217
217
|
self.stdscr.addstr(
|
|
218
218
|
0, 0, msg[:width], # ← truncate, don't center
|
|
@@ -428,25 +428,17 @@ class TUICore:
|
|
|
428
428
|
try:
|
|
429
429
|
self.stdscr.addstr(6, cols['SEL'], f"{'':2}", hdr_attr)
|
|
430
430
|
self.stdscr.addstr(
|
|
431
|
-
6, cols['MODEL'],
|
|
432
|
-
|
|
433
|
-
widths['MODEL']}}", hdr_attr)
|
|
431
|
+
6, cols['MODEL'],
|
|
432
|
+
f"{'Model':<{widths['MODEL']}}", hdr_attr)
|
|
434
433
|
self.stdscr.addstr(
|
|
435
|
-
6, cols['PORT'], f"{
|
|
436
|
-
'Port':<{
|
|
437
|
-
widths['PORT']}}", hdr_attr)
|
|
434
|
+
6, cols['PORT'], f"{'Port':<{widths['PORT']}}", hdr_attr)
|
|
438
435
|
self.stdscr.addstr(
|
|
439
|
-
6, cols['FW'], f"{
|
|
440
|
-
'Firmware':<{
|
|
441
|
-
widths['FW']}}", hdr_attr)
|
|
436
|
+
6, cols['FW'], f"{'Firmware':<{widths['FW']}}", hdr_attr)
|
|
442
437
|
self.stdscr.addstr(
|
|
443
|
-
6, cols['UID'], f"{
|
|
444
|
-
'UID':<{
|
|
445
|
-
widths['UID']}}", hdr_attr)
|
|
438
|
+
6, cols['UID'], f"{'UID':<{widths['UID']}}", hdr_attr)
|
|
446
439
|
self.stdscr.addstr(
|
|
447
|
-
6, cols['STATUS'],
|
|
448
|
-
|
|
449
|
-
widths['STATUS']}}", hdr_attr)
|
|
440
|
+
6, cols['STATUS'],
|
|
441
|
+
f"{'Status':<{widths['STATUS']}}", hdr_attr)
|
|
450
442
|
self.stdscr.addstr(6, cols['ACTIVE'], "Active", hdr_attr)
|
|
451
443
|
except curses.error:
|
|
452
444
|
pass
|
|
@@ -490,21 +482,19 @@ class TUICore:
|
|
|
490
482
|
try:
|
|
491
483
|
self.stdscr.addstr(row, cols['SEL'], cursor, row_color)
|
|
492
484
|
self.stdscr.addstr(
|
|
493
|
-
row, cols['MODEL'],
|
|
494
|
-
|
|
495
|
-
widths['MODEL']}}", row_color)
|
|
485
|
+
row, cols['MODEL'],
|
|
486
|
+
f"{model_str:<{widths['MODEL']}}", row_color)
|
|
496
487
|
self.stdscr.addstr(
|
|
497
|
-
row, cols['PORT'],
|
|
498
|
-
|
|
499
|
-
widths['PORT']}}", row_color)
|
|
488
|
+
row, cols['PORT'],
|
|
489
|
+
f"{port:<{widths['PORT']}}", row_color)
|
|
500
490
|
|
|
501
491
|
if is_busy:
|
|
502
492
|
self.stdscr.addstr(
|
|
503
|
-
row, cols['FW'],
|
|
493
|
+
row, cols['FW'],
|
|
494
|
+
f"{'N/A':<{widths['FW']}}", row_color)
|
|
504
495
|
self.stdscr.addstr(
|
|
505
|
-
row, cols['UID'], f"{
|
|
506
|
-
|
|
507
|
-
widths['UID']}}", curses.color_pair(
|
|
496
|
+
row, cols['UID'], f"{dev_uid:<{widths['UID']}}",
|
|
497
|
+
curses.color_pair(
|
|
508
498
|
Config.COLOR_PAIRS['caution']) | curses.A_BOLD)
|
|
509
499
|
else:
|
|
510
500
|
try:
|
|
@@ -513,18 +503,15 @@ class TUICore:
|
|
|
513
503
|
except (TypeError, ValueError):
|
|
514
504
|
fw_str = "0x????????"
|
|
515
505
|
self.stdscr.addstr(
|
|
516
|
-
row, cols['FW'],
|
|
517
|
-
|
|
518
|
-
widths['FW']}}", row_color)
|
|
506
|
+
row, cols['FW'],
|
|
507
|
+
f"{fw_str:<{widths['FW']}}", row_color)
|
|
519
508
|
self.stdscr.addstr(
|
|
520
|
-
row, cols['UID'],
|
|
521
|
-
|
|
522
|
-
widths['UID']}}", row_color)
|
|
509
|
+
row, cols['UID'],
|
|
510
|
+
f"{dev_uid:<{widths['UID']}}", row_color)
|
|
523
511
|
|
|
524
512
|
self.stdscr.addstr(
|
|
525
|
-
row, cols['STATUS'],
|
|
526
|
-
|
|
527
|
-
widths['STATUS']}}", status_color)
|
|
513
|
+
row, cols['STATUS'],
|
|
514
|
+
f"{status:<{widths['STATUS']}}", status_color)
|
|
528
515
|
|
|
529
516
|
if is_active:
|
|
530
517
|
self.stdscr.addstr(
|
|
@@ -616,8 +603,7 @@ class TUICore:
|
|
|
616
603
|
|
|
617
604
|
self._draw_section(16, 2, "TUI")
|
|
618
605
|
self.stdscr.addstr(
|
|
619
|
-
17, 4, f"{
|
|
620
|
-
'Refresh Interval':<22} {refresh_interval} s")
|
|
606
|
+
17, 4, f"{'Refresh Interval':<22} {refresh_interval} s")
|
|
621
607
|
|
|
622
608
|
except curses.error:
|
|
623
609
|
pass
|
|
@@ -1145,8 +1131,7 @@ class TUICore:
|
|
|
1145
1131
|
self.stdscr.addstr(
|
|
1146
1132
|
row,
|
|
1147
1133
|
cols['NAME'] + 2,
|
|
1148
|
-
f"Fan{
|
|
1149
|
-
i:<5}",
|
|
1134
|
+
f"Fan{i:<5}",
|
|
1150
1135
|
fan_color)
|
|
1151
1136
|
self.stdscr.addstr(
|
|
1152
1137
|
row, cols['DUTY'] + 2, f"{duty:>5}%", fan_color)
|
|
@@ -1282,9 +1267,7 @@ class TUICore:
|
|
|
1282
1267
|
|
|
1283
1268
|
try:
|
|
1284
1269
|
self.stdscr.addstr(
|
|
1285
|
-
y, x, f"{
|
|
1286
|
-
label:<14} {val_str} {
|
|
1287
|
-
unit:<3} ", color)
|
|
1270
|
+
y, x, f"{label:<14} {val_str} {unit:<3} ", color)
|
|
1288
1271
|
self.stdscr.addstr(bar, color)
|
|
1289
1272
|
|
|
1290
1273
|
if stat and stat[0] is not None:
|
|
@@ -118,8 +118,8 @@ class TUIApplication:
|
|
|
118
118
|
|
|
119
119
|
if self.source_type == 'fastapi':
|
|
120
120
|
if hasattr(args, 'api_port'):
|
|
121
|
-
datasource_kwargs['base_url'] =
|
|
122
|
-
args.api_port}"
|
|
121
|
+
datasource_kwargs['base_url'] = (
|
|
122
|
+
f"http://127.0.0.1:{args.api_port}")
|
|
123
123
|
else:
|
|
124
124
|
datasource_kwargs['base_url'] = "http://127.0.0.1:8000"
|
|
125
125
|
datasource_kwargs['timeout'] = 5.0
|
|
@@ -234,26 +234,22 @@ class TUIApplication:
|
|
|
234
234
|
if self.datasource_manager.connect():
|
|
235
235
|
uid = self.datasource_manager.get_selected_uid()
|
|
236
236
|
self.tui_core.set_status(
|
|
237
|
-
f"Connected via {
|
|
238
|
-
self.source_type.upper()}")
|
|
237
|
+
f"Connected via {self.source_type.upper()}")
|
|
239
238
|
logger.info(
|
|
240
|
-
f"Connected to {
|
|
241
|
-
|
|
239
|
+
f"Connected to {self.source_type} datasource, "
|
|
240
|
+
f"selected: {uid}")
|
|
242
241
|
else:
|
|
243
242
|
snapshot = self.datasource_manager.snapshot()
|
|
244
243
|
error_msg = snapshot.get(
|
|
245
|
-
'last_error', f"Failed to connect to {
|
|
246
|
-
self.source_type}")
|
|
244
|
+
'last_error', f"Failed to connect to {self.source_type}")
|
|
247
245
|
self.tui_core.set_status(
|
|
248
246
|
f"Connection failed: {error_msg}", 5.0)
|
|
249
247
|
logger.error(
|
|
250
|
-
f"Failed to connect to {
|
|
251
|
-
self.source_type}: {error_msg}")
|
|
248
|
+
f"Failed to connect to {self.source_type}: {error_msg}")
|
|
252
249
|
except Exception as e:
|
|
253
250
|
self.tui_core.set_status(f"Connection error: {str(e)}", 5.0)
|
|
254
251
|
logger.error(
|
|
255
|
-
f"Exception during {
|
|
256
|
-
self.source_type} connection: {e}")
|
|
252
|
+
f"Exception during {self.source_type} connection: {e}")
|
|
257
253
|
|
|
258
254
|
def _connect_to_device(self, device: Dict[str, Any]):
|
|
259
255
|
port = device.get('port')
|
|
@@ -280,8 +276,7 @@ class TUIApplication:
|
|
|
280
276
|
if self.datasource_manager.select_device(uid):
|
|
281
277
|
self.tui_core.set_status(f"Selected device {uid}")
|
|
282
278
|
logger.info(
|
|
283
|
-
f"Selected device {uid} via {
|
|
284
|
-
self.source_type}")
|
|
279
|
+
f"Selected device {uid} via {self.source_type}")
|
|
285
280
|
else:
|
|
286
281
|
self.tui_core.set_status("Failed to select device", 3.0)
|
|
287
282
|
logger.warning(f"Failed to select device {uid}")
|
|
@@ -147,8 +147,7 @@ def start_vu_server() -> subprocess.Popen | None:
|
|
|
147
147
|
time.sleep(1)
|
|
148
148
|
if check_vu_server(new_cfg["vu_server_url"], new_cfg["api_key"]):
|
|
149
149
|
logger.info(
|
|
150
|
-
f"VU server is now running at {
|
|
151
|
-
new_cfg['vu_server_url']}")
|
|
150
|
+
f"VU server is now running at {new_cfg['vu_server_url']}")
|
|
152
151
|
break
|
|
153
152
|
else:
|
|
154
153
|
logger.error("Failed to verify VU server after startup.")
|
|
@@ -159,8 +158,7 @@ def start_vu_server() -> subprocess.Popen | None:
|
|
|
159
158
|
try:
|
|
160
159
|
VU_SERVER_CONFIG.write_text(json.dumps(new_cfg, indent=2))
|
|
161
160
|
logger.info(
|
|
162
|
-
f"Updated {VU_SERVER_CONFIG} with {
|
|
163
|
-
new_cfg['vu_server_url']}")
|
|
161
|
+
f"Updated {VU_SERVER_CONFIG} with {new_cfg['vu_server_url']}")
|
|
164
162
|
except Exception as e:
|
|
165
163
|
logger.warning(f"Failed to write {VU_SERVER_CONFIG}: {e}")
|
|
166
164
|
|