def set_fan(ser, fan, voltage, lock): """Sets voltage of a specific fan. Note: The Grid only supports voltages between 4.0V and 12.0V in 0.5V steps (e.g. 4.0, 7.5. 12.0) Configuring "0V" stops a fan. """ # Valid voltages and corresponding data (two bytes) speed_data = {0: [0x00, 0x00], # 0% (Values below 4V is not supported by the Grid, fans will be stopped) 4.0: [0x04, 0x00], # 33.3% (4.0V) 4.5: [0x04, 0x50], # 37.5% (4.5V) 5.0: [0x05, 0x00], # 41.7% (5V) 5.5: [0x05, 0x50], # 45.8% (5.5V) 6.0: [0x06, 0x00], # 50.0% (6V) 6.5: [0x06, 0x50], # 54.2% (6.5V) 7.0: [0x07, 0x00], # 58.3% (7V) 7.5: [0x07, 0x50], # 62.5% (7.5V) 8.0: [0x08, 0x00], # 66.7% (8V) 8.5: [0x08, 0x50], # 70.1% (8.5V) 9.0: [0x09, 0x00], # 75.0% (9.0V) 9.5: [0x09, 0x50], # 79.2% (9.5V) 10.0: [0x0A, 0x00], # 83.3% (10.0V) 10.5: [0x0A, 0x50], # 87.5% (10.5V) 11.0: [0x0B, 0x00], # 91.7% (11.0V) 11.5: [0x0B, 0x50], # 95.8% (11.5V) 12.0: [0x0C, 0x00]} # 100.0% (12.0V) fan_data = {1: 0x01, # Fan 1 2: 0x02, # Fan 2 3: 0x03, # Fan 3 4: 0x04, # Fan 4 5: 0x05, # Fan 5 6: 0x06} # Fan 6 # Define bytes to be sent to the Grid for configuring a specific fan's voltage # Format is seven bytes: # 44 <fan id> C0 00 00 <voltage integer> <voltage decimal> # # Example configuring "7.5V" for fan "1": # 44 01 C0 00 00 07 50 serial_data = [0x44, fan_data[fan], 0xC0, 0x00, 0x00, speed_data[voltage][0], speed_data[voltage][1]] try: with lock: bytes_written = ser.write(serial.to_bytes(serial_data)) time.sleep(WAIT_GRID) # TODO: Check reponse # Expected response is one byte response = ser.read(size=1) print("Fan " + str(fan) + " updated") except Exception as e: helper.show_error("Could not set speed for fan " + str(fan) + ".\n\n" "Please check settings for serial port " + str(ser.port) + ".\n\n" "Exception:\n" + str(e) + "\n\n" "The application will now exit.") sys.exit(0)
def read_fan_voltage(ser, lock): """Reads the current voltage of each fan. Returns: - If success: a list with voltage data for each fan - If failure to read data: An empty list """ # List to hold fan voltage data to be returned fans = [] with lock: for fan in [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]: try: # Define bytes to be sent to the Grid for reading voltage for a specific fan # Format is two bytes, e.g. [0x84, <fan id>] serial_data = [0x84, fan] ser.reset_output_buffer() bytes_written = ser.write(serial.to_bytes(serial_data)) # Wait before checking response time.sleep(WAIT_GRID) # Expected response is 5 bytes # Example response: 00 00 00 0B 01 = 0x0B 0x01 = 11.01 volt response = ser.read(size=5) # Check if the Grid responded with any data if response: # Check for correct response (first three bytes should be 0x00) if response[0] == int("0xC0", 16) and response[1] == response[2] == int("0x00", 16): # Convert last two bytes to a decimal float value voltage = float(str(response[3]) + "." + str(response[4])) # Add the voltage for the current fan to the list fans.append(voltage) # An incorrect response was received else: print("Error reading fan voltage, incorrect response") return [] # In case no response (0 bytes) is returned from the Grid else: print("Error reading fan voltage, no data returned") return [] except Exception as e: helper.show_error("Could not read fan voltage.\n\n" "Please check serial port " + ser.port + ".\n\n" "Exception:\n" + str(e) + "\n\n" "The application will now exit.") print(str(e)) sys.exit(0) return fans
def thread_exception_handling(self, msg): """Display an error message with details about the exception and reset the "serial port value" to <Select port>. Called when an exception occurs in the polling thread.""" # Show error message helper.show_error(msg) # Reset the "serial port" combo box index = self.ui.comboBoxComPorts.findText("<Select port>") self.ui.comboBoxComPorts.setCurrentIndex(index)
def read_fan_rpm(ser, lock): """Reads the current rpm of each fan. Returns: - If success: A list with rpm data for each fan - If failure to read data: An empty list """ # List to hold fan rpm data to be returned fans = [] with lock: for fan in [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]: try: # Define bytes to be sent to the Grid for reading rpm for a specific fan # Format is two bytes: # 8A <fan id> serial_data = [0x8A, fan] ser.reset_output_buffer() # TODO: Check bytes written bytes_written = ser.write(serial.to_bytes(serial_data)) # Wait before checking response time.sleep(WAIT_GRID) # Expected response is 5 bytes # Example response: C0 00 00 03 00 = 0x0300 = 768 rpm (two bytes unsigned) response = ser.read(size=5) # Check if the Grid responded with any data if response: # Check for correct response, first three bytes should be C0 00 00 if response[0] == int("0xC0", 16) and response[1] == response[2] == int("0x00", 16): # Convert rpm from 2-bytes unsigned value to decimal rpm = response[3] * 256 + response[4] fans.append(rpm) # An incorrect response was received, return an empty list else: return [] # In case no response (0 bytes) received, return an empty list else: return [] except Exception as e: helper.show_error("Could not read rpm for fan " + str(fan) + ".\n\n" "Please check serial port settings.\n\n" "Exception:\n" + str(e) + "\n\n" "The application will now exit.") print(str(e)) sys.exit(0) # Fan return fans
def open_serial(ser, lock): """Open the serial port""" try: with lock: ser.open() except Exception as e: helper.show_error("Could not open serial port " + ser.port + ".\n\n" "Is another instance of Grid Control running?\n\n" "Exception:\n" + str(e) + "\n\n" "The application will now exit.") sys.exit(0)
def setup_serial(ser, port, lock): """Setup all parameters for the serial communication""" try: with lock: ser.baudrate = 4800 ser.port = port ser.bytesize = serial.EIGHTBITS ser.stopbits = serial.STOPBITS_ONE ser.parity = serial.PARITY_NONE ser.timeout = 0.1 # Read timeout in seconds ser.write_timeout = 0.1 # Write timeout in seconds except Exception as e: helper.show_error("Problem initializing serial port " + port + ".\n\n" "Exception:\n" + str(e) + "\n\n" "The application will now exit.") sys.exit(0)
def initialize_hwmon(): """Create a WMI object and verify that OpenHardwareMonitor is installed.""" # Access the OpenHWMon WMI interface try: hwmon = wmi.WMI(namespace="root\OpenHardwareMonitor") return hwmon # WMI exception (e.g. no namespace "root\OpenHardwareMonitor" indicates OpenHWMon is not installed except: helper.show_error( "OpenHardwareMonitor WMI data not found.\n\n" "Please make sure that OpenHardwareMonitor is installed.\n\n" "Latest version is available at:\n\n" "http://openhardwaremonitor.org\n\n" "The application will now exit.") sys.exit(0)
def initialize_grid(ser, lock): """Initialize the Grid by sending "0xC0", expected response is "0x21" Returns: - True for successful initialization - False otherwise """ try: with lock: # Flush input and output buffers ser.reset_input_buffer() ser.reset_output_buffer() # Write data to serial port to initialize the Grid bytes_written = ser.write(serial.to_bytes([0xC0])) # Wait before checking response time.sleep(WAIT_GRID) # Read response, one byte = 0x21 is expected for a successful initialization response = ser.read(size=1) # Check if the Grid responded with any data if response: # Check for correct response (should be 0x21) if response[0] == int("0x21", 16): print("Grid initialized") return True # Incorrect response received from the grid else: helper.show_error("Problem initializing the Grid unit.\n\n" "Response 0x21 expected, got " + hex(ord(response)) + ".\n\n" "Please check serial port " + ser.port +".\n") return False # In case no response (0 bytes) from the Grid else: helper.show_error("Problem initializing the Grid unit.\n\n" "Response 0x21 expected, no response received.\n\n" "Please check serial port " + ser.port +".\n") return False except Exception as e: helper.show_error("Problem initializing the Grid unit.\n\n" "Exception:\n" + str(e) + "\n\n" "The application will now exit.") sys.exit(0)