diff --git a/README.md b/README.md index 4f023af..c54d8ef 100644 --- a/README.md +++ b/README.md @@ -1,166 +1,199 @@ -# Bitaxe Hashrate Benchmark +# **Bitaxe Hashrate Benchmark** A Python-based benchmarking tool for optimizing Bitaxe mining performance by testing different voltage and frequency combinations while monitoring hashrate, temperature, and power efficiency. -## Features +## **Features** -- Automated benchmarking of different voltage/frequency combinations -- Temperature monitoring and safety cutoffs -- Power efficiency calculations (J/TH) -- Automatic saving of benchmark results -- Graceful shutdown with best settings retention -- Docker support for easy deployment +* Automated benchmarking of different voltage/frequency combinations +* **Direct setting of specific voltage and frequency from command line** +* Temperature monitoring and safety cutoffs +* **Power consumption monitoring and reporting (Watts)** +* **Fan speed monitoring and reporting (RPM/Percentage)** +* Power efficiency calculations (J/TH) +* Automatic saving of benchmark results +* Graceful shutdown with best settings retention +* Docker support for easy deployment -## Prerequisites +## **Prerequisites** -- Python 3.11 or higher -- Access to a Bitaxe miner on your network -- Docker (optional, for containerized deployment) -- Git (optional, for cloning the repository) +* Python 3.11 or higher +* Access to a Bitaxe miner on your network +* Docker (optional, for containerized deployment) +* Git (optional, for cloning the repository) -## Installation +## **Installation** -### Standard Installation +### **Standard Installation** -1. Clone the repository: -```bash -git clone https://github.com/mrv777/Bitaxe-Hashrate-Benchmark.git -cd Bitaxe-Hashrate-Benchmark -``` +1. Clone the repository: + ```bash + git clone https://github.com/mrv777/Bitaxe-Hashrate-Benchmark.git + cd Bitaxe-Hashrate-Benchmark + ``` -2. Create and activate a virtual environment: -```bash -python -m venv venv -# On Windows -venv\Scripts\activate -# On Linux/Mac -source venv/bin/activate -``` +2. Create and activate a virtual environment: + ```bash + python -m venv venv + # On Windows + venv\Scripts\activate + # On Linux/Mac + source venv/bin/activate + ``` -3. Install dependencies: -```bash -pip install -r requirements.txt -``` +3. Install dependencies: + ```bash + pip install -r requirements.txt + ``` + +### **Docker Installation** + +1. Build the Docker image: + `docker build -t bitaxe-benchmark .` -### Docker Installation +## **Usage** -1. Build the Docker image: +### **Standard Usage (Run Full Benchmark)** + +Run the benchmark tool by providing your Bitaxe's IP address and initial settings: ```bash -docker build -t bitaxe-benchmark . +python bitaxe_hashrate_benchmark.py -v -f ``` -## Usage - -### Standard Usage +**Arguments:** -Run the benchmark tool by providing your Bitaxe's IP address: +* ``: **Required.** IP address of your Bitaxe miner (e.g., `192.168.2.26`). +* `-v, --voltage:` **Optional.** Initial voltage in mV for testing (default: `1150`). +* `-f, --frequency:` **Optional.** Initial frequency in MHz for testing (default: `500`). +**Example:** ```bash -python bitaxe_hashrate_benchmark.py +python bitaxe_hashrate_benchmark.py 192.168.1.136 -v 1150 -f 550 ``` -Optional parameters: -- `-v, --voltage`: Initial voltage in mV (default: 1150) -- `-f, --frequency`: Initial frequency in MHz (default: 500) +### **Apply Specific Settings (Without Benchmarking)** -Example: +To quickly apply specific voltage and frequency settings to your Bitaxe without running the full benchmark: ```bash -python bitaxe_hashrate_benchmark.py 192.168.2.29 -v 1175 -f 775 +python bitaxe_hashrate_benchmark.py --set-values -v -f ``` -### Docker Usage (Optional) +**Arguments:** -Run the container with your Bitaxe's IP address: +* ``: **Required.** IP address of your Bitaxe miner. +* `-s, --set-values`: **Flag.** Activates this mode to only set values and exit. +* `-v, --voltage`: **Required.** The exact voltage in mV to apply. +* `-f, --frequency`: **Required.** The exact frequency in MHz to apply. +**Example:** +```bash +python bitaxe_hashrate_benchmark.py 192.168.1.136 --set-values -v 1150 -f 780 +``` + +### **Docker Usage (Optional)** + +Run the container with your Bitaxe's IP address (add --set-values for that mode): ```bash docker run --rm bitaxe-benchmark [options] ``` -Example: +Example (Full Benchmark): ```bash docker run --rm bitaxe-benchmark 192.168.2.26 -v 1200 -f 550 ``` -## Configuration - -The script includes several configurable parameters: - -- Maximum chip temperature: 66°C -- Maximum VR temperature: 86°C -- Maximum allowed voltage: 1400mV -- Minimum allowed voltage: 1000mV -- Maximum allowed frequency: 1200MHz -- Maximum power consumption: 40W -- Minimum allowed frequency: 400MHz -- Minimum input voltage: 4800mV -- Maximum input voltage: 5500mV -- Benchmark duration: 10 minutes -- Sample interval: 15 seconds -- **Minimum required samples: 7** (for valid data processing) -- Voltage increment: 20mV -- Frequency increment: 25MHz - -## Output - -The benchmark results are saved to `bitaxe_benchmark_results_.json`, containing: -- Complete test results for all combinations -- Top 5 performing configurations ranked by hashrate -- Top 5 most efficient configurations ranked by J/TH -- For each configuration: - - Average hashrate (with outlier removal) - - Temperature readings (excluding initial warmup period) - - VR temperature readings (when available) - - Power efficiency metrics (J/TH) - - Input voltage measurements - - Voltage/frequency combinations tested - -## Safety Features - -- Automatic temperature monitoring with safety cutoff (66°C chip temp) -- Voltage regulator (VR) temperature monitoring with safety cutoff (86°C) -- Input voltage monitoring with minimum threshold (4800mV) and maximum threshold (5500mV) -- Power consumption monitoring with safety cutoff (40W) -- Temperature validation (must be above 5°C) -- Graceful shutdown on interruption (Ctrl+C) -- Automatic reset to best performing settings after benchmarking -- Input validation for safe voltage and frequency ranges -- Hashrate validation to ensure stability -- Protection against invalid system data -- Outlier removal from benchmark results - -## Benchmarking Process +Example (Set Settings Only): +```bash +docker run --rm bitaxe-benchmark 192.168.2.26 --set-values -v 1150 -f 780 +``` + +## **Configuration** + +The script includes several configurable parameters. These can be adjusted in the bitaxe_hashrate_benchmark.py file: + +* Maximum chip temperature: 66°C +* Maximum VR temperature: 86°C +* Maximum allowed voltage: 1400mV +* Minimum allowed voltage: 1000mV +* Maximum allowed frequency: 1200MHz +* Maximum power consumption: 30W +* Minimum allowed frequency: 400MHz +* Minimum input voltage: 4800mV +* Maximum input voltage: 5500mV +* Benchmark duration: 600 seconds (10 minutes per combination) +* Sample interval: 15 seconds +* Minimum required samples: 7 (for valid data processing) +* Voltage increment: 15mV +* Frequency increment: 20MHz +* **ASIC Configuration:** asic_count is hardcoded to 1 as it's not always provided by the API. small_core_count is fetched from the Bitaxe. + +## **Output** + +The benchmark results are saved to bitaxe_benchmark_results_.json, containing: + +* Complete test results for all combinations +* Top 5 performing configurations ranked by hashrate +* Top 5 most efficient configurations ranked by J/TH +* For each configuration: + * Average hashrate (with outlier removal) + * Temperature readings (excluding initial warmup period) + * VR temperature readings (when available) + * Power efficiency metrics (J/TH) + * **Average Power (Watts)** + * **Average Fan Speed (Percentage or RPM, if available from API)** + * Input voltage measurements + * Voltage/frequency combinations tested + * Error reason (if any) for a specific iteration + +## **Safety Features** + +* Automatic temperature monitoring with safety cutoff (66°C chip temp) +* Voltage regulator (VR) temperature monitoring with safety cutoff (86°C) +* Input voltage monitoring with minimum threshold (4800mV) and maximum threshold (5500mV) +* Power consumption monitoring with safety cutoff (30W) +* Temperature validation (must be above 5°C) +* Graceful shutdown on interruption (Ctrl+C) +* Automatic reset to best performing settings after benchmarking +* Input validation for safe voltage and frequency ranges +* Hashrate validation to ensure stability +* Protection against invalid system data +* Outlier removal from benchmark results + +## **Benchmarking Process** The tool follows this process: -1. Starts with user-specified or default voltage/frequency -2. Tests each combination for 20 minutes -3. Validates hashrate is within 8% of theoretical maximum -4. Incrementally adjusts settings: - - Increases frequency if stable - - Increases voltage if unstable - - Stops at thermal or stability limits -5. Records and ranks all successful configurations -6. Automatically applies the best performing stable settings -7. Restarts system after each test for stability + +1. Starts with user-specified or default voltage/frequency +2. Tests each combination for 10 minutes +3. Validates hashrate is within 6% of theoretical maximum +4. Incrementally adjusts settings: + * Increases frequency if stable + * Increases voltage if unstable + * Stops at thermal or stability limits +5. Records and ranks all successful configurations +6. Automatically applies the best performing stable settings +7. Restarts system after each test for stability 8. Allows 90-second stabilization period between tests -## Data Processing +## **Data Processing** The tool implements several data processing techniques to ensure accurate results: -- Removes 3 highest and 3 lowest hashrate readings to eliminate outliers -- Excludes first 6 temperature readings during warmup period -- Validates hashrate is within 6% of theoretical maximum -- Averages power consumption across entire test period -- Monitors VR temperature when available -- Calculates efficiency in Joules per Terahash (J/TH) -## Contributing +* Removes 3 highest and 3 lowest hashrate readings to eliminate outliers +* Excludes first 6 temperature readings during warmup period +* Validates hashrate is within 6% of theoretical maximum +* Averages power consumption across entire test period +* Monitors VR temperature when available +* Calculates efficiency in Joules per Terahash (J/TH) +* **Averages fan speed across entire test period** + +## **Contributing** Contributions are welcome! Please feel free to submit a Pull Request. -## License +## **License** This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details. -## Disclaimer +## **Disclaimer** Please use this tool responsibly. Overclocking and voltage modifications can potentially damage your hardware if not done carefully. Always ensure proper cooling and monitor your device during benchmarking. \ No newline at end of file diff --git a/bitaxe_hashrate_benchmark.py b/bitaxe_hashrate_benchmark.py index a208b1c..24986eb 100644 --- a/bitaxe_hashrate_benchmark.py +++ b/bitaxe_hashrate_benchmark.py @@ -11,20 +11,78 @@ RED = "\033[91m" RESET = "\033[0m" -# Add this before the configuration section +# This formatter allows for multi-line descriptions in help messages and adds default values +class RawTextAndDefaultsHelpFormatter(argparse.RawTextHelpFormatter): + def _get_help_string(self, action): + help_text = super()._get_help_string(action) + if action.default is not argparse.SUPPRESS: + # Append default value to help text if available + defaulting_nargs = [argparse.OPTIONAL, argparse.ZERO_OR_MORE] + if action.option_strings or action.nargs in defaulting_nargs: + if "\n" in help_text: + help_text += f"\n(default: {action.default})" + else: + help_text += f" (default: {action.default})" + return help_text + +# Modify the parse_arguments function def parse_arguments(): - parser = argparse.ArgumentParser(description='Bitaxe Hashrate Benchmark Tool') - parser.add_argument('bitaxe_ip', nargs='?', help='IP address of the Bitaxe (e.g., 192.168.2.26)') - parser.add_argument('-v', '--voltage', type=int, default=1150, - help='Initial voltage in mV (default: 1150)') - parser.add_argument('-f', '--frequency', type=int, default=500, - help='Initial frequency in MHz (default: 500)') - + parser = argparse.ArgumentParser( + description= + f"{GREEN}Bitaxe Hashrate Benchmark Tool v1.0{RESET}\n" + "This script allows you to either benchmark your Bitaxe miner across various " + "voltage and frequency settings, or apply specific settings directly.\n", + epilog= + f"{YELLOW}Examples:{RESET}\n" + f" {YELLOW}1. Run a full benchmark (starting at 1150mV, 500MHz):{RESET}\n" + f" {GREEN}python bitaxe_hasrate_benchmark.py 192.168.1.136 -v 1150 -f 500{RESET}\n\n" + f" {YELLOW}2. Apply specific settings (1150mV, 780MHz) and exit:{RESET}\n" + f" {GREEN}python bitaxe_hasrate_benchmark.py 192.168.1.136 --set-values -v 1150 -f 780{RESET}\n\n" + f" {YELLOW}3. Get help (this message):{RESET}\n" + f" {GREEN}python bitaxe_hasrate_benchmark.py --help{RESET}", + formatter_class=RawTextAndDefaultsHelpFormatter # <--- USE THE CUSTOM FORMATTER + ) + + # Positional Argument + parser.add_argument( + 'bitaxe_ip', + nargs='?', # Makes it optional if --help is used alone, but required otherwise + help=f"{YELLOW}IP address of your Bitaxe miner (e.g., 192.168.2.26){RESET}\n" + " This is required for both benchmarking and setting values." + ) + + # Optional Arguments + parser.add_argument( + '-v', '--voltage', + type=int, + default=1150, # Default value for benchmark start or target setting + help=f"{YELLOW}Core voltage in mV.{RESET}\n" + " For benchmark mode: The starting voltage for testing.\n" + " For --set-values mode: The exact voltage to apply." + ) + parser.add_argument( + '-f', '--frequency', + type=int, + default=500, # Default value for benchmark start or target setting + help=f"{YELLOW}Core frequency in MHz.{RESET}\n" + " For benchmark mode: The starting frequency for testing.\n" + " For --set-values mode: The exact frequency to apply." + ) + + # New argument for setting values only + parser.add_argument( + '-s', '--set-values', + action='store_true', + help=f"{YELLOW}Set values only; do not run benchmark.{RESET}\n" + " If this flag is present, the script will apply the voltage (-v) and\n" + " frequency (-f) settings to the Bitaxe and then exit." + ) + # If no arguments are provided, print help and exit if len(sys.argv) == 1: parser.print_help() sys.exit(1) - + return parser.parse_args() # Replace the configuration section @@ -34,8 +92,8 @@ def parse_arguments(): initial_frequency = args.frequency # Configuration -voltage_increment = 20 -frequency_increment = 25 +voltage_increment = 15 +frequency_increment = 20 benchmark_time = 600 # 10 minutes benchmark time sample_interval = 15 # 15 seconds sample interval max_temp = 66 # Will stop if temperature reaches or exceeds this value @@ -44,11 +102,11 @@ def parse_arguments(): max_vr_temp = 86 # Maximum allowed voltage regulator temperature min_input_voltage = 4800 # Minimum allowed input voltage max_input_voltage = 5500 # Maximum allowed input voltage -max_power = 40 # Max of 40W because of DC plug +max_power = 30 # Max of 30W because of DC plug # Add these variables to the global configuration section small_core_count = None -asic_count = None +asic_count = 1 # Add these constants to the configuration section min_allowed_voltage = 1000 # Minimum allowed core voltage @@ -187,8 +245,9 @@ def benchmark_iteration(core_voltage, frequency): print(GREEN + f"[{current_time}] Starting benchmark for Core Voltage: {core_voltage}mV, Frequency: {frequency}MHz" + RESET) hash_rates = [] temperatures = [] - power_consumptions = [] + power_consumptions = [] vr_temps = [] + fan_speeds = [] total_samples = benchmark_time // sample_interval expected_hashrate = frequency * ((small_core_count * asic_count) / 1000) # Calculate expected hashrate based on frequency @@ -196,52 +255,55 @@ def benchmark_iteration(core_voltage, frequency): info = get_system_info() if info is None: print(YELLOW + "Skipping this iteration due to failure in fetching system info." + RESET) - return None, None, None, False, None, "SYSTEM_INFO_FAILURE" + return None, None, None, False, None, None, None, "SYSTEM_INFO_FAILURE" temp = info.get("temp") vr_temp = info.get("vrTemp") # Get VR temperature if available voltage = info.get("voltage") if temp is None: print(YELLOW + "Temperature data not available." + RESET) - return None, None, None, False, None, "TEMPERATURE_DATA_FAILURE" + return None, None, None, False, None, None, None, "TEMPERATURE_DATA_FAILURE" if temp < 5: print(YELLOW + "Temperature is below 5°C. This is unexpected. Please check the system." + RESET) - return None, None, None, False, None, "TEMPERATURE_BELOW_5" + return None, None, None, False, None, None, None, "TEMPERATURE_BELOW_5" # Check both chip and VR temperatures if temp >= max_temp: print(RED + f"Chip temperature exceeded {max_temp}°C! Stopping current benchmark." + RESET) - return None, None, None, False, None, "CHIP_TEMP_EXCEEDED" + return None, None, None, False, None, None, None, "CHIP_TEMP_EXCEEDED" if vr_temp is not None and vr_temp >= max_vr_temp: print(RED + f"Voltage regulator temperature exceeded {max_vr_temp}°C! Stopping current benchmark." + RESET) - return None, None, None, False, None, "VR_TEMP_EXCEEDED" + return None, None, None, False, None, None, None, "VR_TEMP_EXCEEDED" if voltage < min_input_voltage: print(RED + f"Input voltage is below the minimum allowed value of {min_input_voltage}mV! Stopping current benchmark." + RESET) - return None, None, None, False, None, "INPUT_VOLTAGE_BELOW_MIN" + return None, None, None, False, None, None, None, "INPUT_VOLTAGE_BELOW_MIN" if voltage > max_input_voltage: print(RED + f"Input voltage is above the maximum allowed value of {max_input_voltage}mV! Stopping current benchmark." + RESET) - return None, None, None, False, None, "INPUT_VOLTAGE_ABOVE_MAX" + return None, None, None, False, None, None, None, "INPUT_VOLTAGE_ABOVE_MAX" hash_rate = info.get("hashRate") power_consumption = info.get("power") - + fan_speed = info.get("fanspeed") + if hash_rate is None or power_consumption is None: print(YELLOW + "Hashrate or Watts data not available." + RESET) - return None, None, None, False, None, "HASHRATE_POWER_DATA_FAILURE" + return None, None, None, False, None, None, None, "HASHRATE_POWER_DATA_FAILURE" if power_consumption > max_power: print(RED + f"Power consumption exceeded {max_power}W! Stopping current benchmark." + RESET) - return None, None, None, False, None, "POWER_CONSUMPTION_EXCEEDED" + return None, None, None, False, None, None, None, "POWER_CONSUMPTION_EXCEEDED" hash_rates.append(hash_rate) temperatures.append(temp) power_consumptions.append(power_consumption) if vr_temp is not None and vr_temp > 0: vr_temps.append(vr_temp) + if fan_speed is not None: + fan_speeds.append(fan_speed) # Calculate percentage progress percentage_progress = ((sample + 1) / total_samples) * 100 @@ -256,6 +318,15 @@ def benchmark_iteration(core_voltage, frequency): ) if vr_temp is not None and vr_temp > 0: status_line += f" | VR: {int(vr_temp):2d}°C" + + # Add Power (Watts) to the status line if available + if power_consumption is not None: + status_line += f" | P: {int(power_consumption):2d} W" + + # Add Fan Speed to the status line if available + if fan_speed is not None: + status_line += f" | FAN: {int(fan_speed):2d}%" + print(status_line + RESET) # Only sleep if it's not the last iteration @@ -281,13 +352,18 @@ def benchmark_iteration(core_voltage, frequency): average_vr_temp = sum(trimmed_vr_temps) / len(trimmed_vr_temps) average_power = sum(power_consumptions) / len(power_consumptions) + + average_fan_speed = None + if fan_speeds: + average_fan_speed = sum(fan_speeds) / len(fan_speeds) + print(GREEN + f"Average Fan Speed: {average_fan_speed:.2f}%" + RESET) # Add protection against zero hashrate if average_hashrate > 0: efficiency_jth = average_power / (average_hashrate / 1_000) else: print(RED + "Warning: Zero hashrate detected, skipping efficiency calculation" + RESET) - return None, None, None, False, None, "ZERO_HASHRATE" + return None, None, None, False, None, None, None, "ZERO_HASHRATE" # Calculate if hashrate is within 6% of expected hashrate_within_tolerance = (average_hashrate >= expected_hashrate * 0.94) @@ -298,10 +374,10 @@ def benchmark_iteration(core_voltage, frequency): print(GREEN + f"Average VR Temperature: {average_vr_temp:.2f}°C" + RESET) print(GREEN + f"Efficiency: {efficiency_jth:.2f} J/TH" + RESET) - return average_hashrate, average_temperature, efficiency_jth, hashrate_within_tolerance, average_vr_temp, None + return average_hashrate, average_temperature, efficiency_jth, hashrate_within_tolerance, average_vr_temp, average_power, average_fan_speed, None else: print(YELLOW + "No Hashrate or Temperature or Watts data collected." + RESET) - return None, None, None, False, None, "NO_DATA_COLLECTED" + return None, None, None, False, None, None, None, "NO_DATA_COLLECTED" def save_results(): try: @@ -332,6 +408,17 @@ def reset_to_best_setting(): restart_system() +# --- Main execution logic --- +if args.set_values: + print(GREEN + "\n--- Applying Settings Only ---" + RESET) + print(GREEN + f"Applying Core Voltage: {initial_voltage}mV, Frequency: {initial_frequency}MHz to Bitaxe." + RESET) + + # Call the existing set_system_settings function + set_system_settings(initial_voltage, initial_frequency) + + print(GREEN + "Settings applied. Check your Bitaxe web interface to confirm." + RESET) + sys.exit(0) # Exit the script after applying settings + # Main benchmarking process try: fetch_default_settings() @@ -349,7 +436,7 @@ def reset_to_best_setting(): while current_voltage <= max_allowed_voltage and current_frequency <= max_allowed_frequency: set_system_settings(current_voltage, current_frequency) - avg_hashrate, avg_temp, efficiency_jth, hashrate_ok, avg_vr_temp, error_reason = benchmark_iteration(current_voltage, current_frequency) + avg_hashrate, avg_temp, efficiency_jth, hashrate_ok, avg_vr_temp, avg_power, avg_fan_speed, error_reason = benchmark_iteration(current_voltage, current_frequency) if avg_hashrate is not None and avg_temp is not None and efficiency_jth is not None: result = { @@ -357,12 +444,18 @@ def reset_to_best_setting(): "frequency": current_frequency, "averageHashRate": avg_hashrate, "averageTemperature": avg_temp, - "efficiencyJTH": efficiency_jth + "efficiencyJTH": efficiency_jth, + "averagePower": avg_power, + "errorReason": error_reason } # Only add VR temp if it exists if avg_vr_temp is not None: result["averageVRTemp"] = avg_vr_temp + + # Only add Fan Speed if it exists (assuming it's not None) + if avg_fan_speed is not None: + result["averageFanSpeed"] = avg_fan_speed results.append(result) @@ -425,7 +518,9 @@ def reset_to_best_setting(): "averageHashRate": result["averageHashRate"], "averageTemperature": result["averageTemperature"], "efficiencyJTH": result["efficiencyJTH"], - **({"averageVRTemp": result["averageVRTemp"]} if "averageVRTemp" in result else {}) + "averagePower": result["averagePower"], + **({"averageVRTemp": result["averageVRTemp"]} if "averageVRTemp" in result else {}), + **({"averageFanSpeed": result["averageFanSpeed"]} if "averageFanSpeed" in result else {}) } for i, result in enumerate(top_5_results, 1) ], @@ -437,7 +532,9 @@ def reset_to_best_setting(): "averageHashRate": result["averageHashRate"], "averageTemperature": result["averageTemperature"], "efficiencyJTH": result["efficiencyJTH"], - **({"averageVRTemp": result["averageVRTemp"]} if "averageVRTemp" in result else {}) + "averagePower": result["averagePower"], + **({"averageVRTemp": result["averageVRTemp"]} if "averageVRTemp" in result else {}), + **({"averageFanSpeed": result["averageFanSpeed"]} if "averageFanSpeed" in result else {}) } for i, result in enumerate(top_5_efficient_results, 1) ] @@ -459,6 +556,9 @@ def reset_to_best_setting(): print(GREEN + f" Average Hashrate: {result['averageHashRate']:.2f} GH/s" + RESET) print(GREEN + f" Average Temperature: {result['averageTemperature']:.2f}°C" + RESET) print(GREEN + f" Efficiency: {result['efficiencyJTH']:.2f} J/TH" + RESET) + print(GREEN + f" Average Power: {result['averagePower']:.2f} W" + RESET) + if "averageFanSpeed" in result: + print(GREEN + f" Average Fan Speed: {result['averageFanSpeed']:.2f}%" + RESET) if "averageVRTemp" in result: print(GREEN + f" Average VR Temperature: {result['averageVRTemp']:.2f}°C" + RESET) @@ -470,6 +570,9 @@ def reset_to_best_setting(): print(GREEN + f" Average Hashrate: {result['averageHashRate']:.2f} GH/s" + RESET) print(GREEN + f" Average Temperature: {result['averageTemperature']:.2f}°C" + RESET) print(GREEN + f" Efficiency: {result['efficiencyJTH']:.2f} J/TH" + RESET) + print(GREEN + f" Average Power: {result['averagePower']:.2f} W" + RESET) + if "averageFanSpeed" in result: + print(GREEN + f" Average Fan Speed: {result['averageFanSpeed']:.2f}%" + RESET) if "averageVRTemp" in result: print(GREEN + f" Average VR Temperature: {result['averageVRTemp']:.2f}°C" + RESET) else: