def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None): FanBase.__init__(self) self.is_psu_fan = psu_fan if not self.is_psu_fan: # API index is starting from 0, DellEMC platform index is # starting from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 self.index = (self.fantrayindex - 1) * 2 + self.fanindex self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], is_discrete=True) self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"]) self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) if self.fanindex == 1: self.max_speed_offset = FAN1_MAX_SPEED_OFFSET else: self.max_speed_offset = FAN2_MAX_SPEED_OFFSET self.fan_direction_offset = FAN_DIRECTION_OFFSET else: self.dependency = dependency self.fanindex = fan_index self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex]) self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET self.fan_direction_offset = PSU_FAN_DIRECTION_OFFSET #self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(7+(fan_index-1)) self.max_speed = 18000
def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None): self.is_psu_fan = psu_fan if not self.is_psu_fan: # API index is starting from 0, DellEMC platform index is # starting from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 if (self.fanindex == 1): self.max_speed_offset = FAN1_MAX_SPEED_OFFSET else: self.max_speed_offset = FAN2_MAX_SPEED_OFFSET self.fan_direction_offset = FAN_DIRECTION_OFFSET self.index = (self.fantrayindex - 1) * 2 + self.fanindex self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], is_discrete=True) self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"]) self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) else: self.dependency = dependency self.fanindex = fan_index self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex]) self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET self.fan_direction_offset = PSU_FAN_DIRECTION_OFFSET self.max_speed = self.fru.get_fru_data(self.max_speed_offset,2)[1] self.max_speed = self.max_speed[1] << 8 | self.max_speed[0]
def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None): FanBase.__init__(self) self.is_psu_fan = psu_fan if not self.is_psu_fan: # API index is starting from 0, DellEMC platform index is # starting from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 self.index = (self.fantrayindex - 1) * 2 + self.fanindex self.prsnt_sensor = IpmiSensor( self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], is_discrete=True) self.state_sensor = IpmiSensor( self.FAN_SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.speed_sensor = IpmiSensor( self.FAN_SENSOR_MAPPING[self.index]["Speed"]) self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(fantray_index) if self.fanindex == 1: self.max_speed = 24700 else: self.max_speed = 29700 else: self.dependency = dependency self.fanindex = fan_index self.state_sensor = IpmiSensor( self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], is_discrete=True) self.speed_sensor = IpmiSensor( self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(7 + (fan_index - 1)) self.max_speed = 26500
def __init__(self, psu_index): PsuBase.__init__(self) # PSU is 1-based in DellEMC platforms self.index = psu_index + 1 self.state_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Voltage"]) self.current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Current"]) self.power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Power"]) self.temp_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index ]["Temperature"]) self.fru = IpmiFru(self.FRU_MAPPING[self.index]) self.psu_type_raw_cmd = "0x3A 0x0B {}".format(psu_index+1) self._fan_list.append(Fan(fan_index=self.index, psu_fan=True, dependency=self))
def __init__(self, psu_index): PsuBase.__init__(self) # PSU is 1-based in DellEMC platforms self.index = psu_index + 1 self.state_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.voltage_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Voltage"]) self.current_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Current"]) self.power_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Power"]) self.fru = IpmiFru(self.FRU_MAPPING[self.index])
def __init__(self, psu_index): PsuBase.__init__(self) # PSU is 1-based in DellEMC platforms self.index = psu_index + 1 self.state_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Voltage"]) self.current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Current"]) self.power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Power"]) self.fru = IpmiFru(self.FRU_MAPPING[self.index]) self._fan_list.append(Fan(fantray_index=1,fan_index=self.index, psu_fan=True, dependency=self))
class Fan(FanBase): """DellEMC Platform-specific Fan class""" # { FAN-ID: { Sensor-Name: Sensor-ID } } FAN_SENSOR_MAPPING = {1: {"Prsnt": 0x57, "State": 0x20, "Speed": 0x1c}, 2: {"Prsnt": 0x57, "State": 0x21, "Speed": 0x1d}, 3: {"Prsnt": 0x56, "State": 0x22, "Speed": 0x1a}, 4: {"Prsnt": 0x56, "State": 0x23, "Speed": 0x1b}, 5: {"Prsnt": 0x55, "State": 0x24, "Speed": 0x18}, 6: {"Prsnt": 0x55, "State": 0x25, "Speed": 0x19}, 7: {"Prsnt": 0x54, "State": 0x26, "Speed": 0x16}, 8: {"Prsnt": 0x54, "State": 0x27, "Speed": 0x17}, 9: {"Prsnt": 0x53, "State": 0x28, "Speed": 0x14}, 10: {"Prsnt": 0x53, "State": 0x29, "Speed": 0x15}, 11: {"Prsnt": 0x52, "State": 0x2a, "Speed": 0x12}, 12: {"Prsnt": 0x52, "State": 0x2b, "Speed": 0x13}, 13: {"Prsnt": 0x51, "State": 0x2c, "Speed": 0x10}, 14: {"Prsnt": 0x51, "State": 0x2d, "Speed": 0x11}} PSU_FAN_SENSOR_MAPPING = {1: {"State": 0x40, "Speed": 0x45}, 2: {"State": 0x30, "Speed": 0x35}} # { FANTRAY-ID: FRU-ID } FAN_FRU_MAPPING = {1: 3, 2: 4, 3: 5, 4: 6, 5: 7, 6: 8, 7: 9} PSU_FRU_MAPPING = {1: 1, 2: 2} def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None): FanBase.__init__(self) self.is_psu_fan = psu_fan if not self.is_psu_fan: # API index is starting from 0, DellEMC platform index is # starting from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 self.index = (self.fantrayindex - 1) * 2 + self.fanindex self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], is_discrete=True) self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"]) self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) if self.fanindex == 1: self.max_speed_offset = FAN1_MAX_SPEED_OFFSET else: self.max_speed_offset = FAN2_MAX_SPEED_OFFSET self.fan_direction_offset = FAN_DIRECTION_OFFSET else: self.dependency = dependency self.fanindex = fan_index self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex]) self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET self.fan_direction_offset = PSU_FAN_DIRECTION_OFFSET #self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(7+(fan_index-1)) self.max_speed = 18000 def get_name(self): """ Retrieves the name of the device Returns: String: The name of the device """ if self.is_psu_fan: return "PSU{} Fan".format(self.fanindex) else: return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex) def get_model(self): """ Retrieves the part number of the FAN Returns: String: Part number of FAN """ if self.is_psu_fan: return 'NA' else: return self.fru.get_board_part_number() def get_serial(self): """ Retrieves the serial number of the FAN Returns: String: Serial number of FAN """ if self.is_psu_fan: return 'NA' else: return self.fru.get_board_serial() def get_presence(self): """ Retrieves the presence of the FAN Returns: bool: True if fan is present, False if not """ presence = False if self.is_psu_fan: return self.dependency.get_presence() else: is_valid, state = self.prsnt_sensor.get_reading() if is_valid: if state & 0b1: presence = True return presence def get_status(self): """ Retrieves the operational status of the FAN Returns: bool: True if FAN is operating properly, False if not """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if state <= 1: status = True return status def get_direction(self): """ Retrieves the fan airfow direction Returns: A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction Notes: In DellEMC platforms, - Forward/Exhaust : Air flows from Port side to Fan side. - Reverse/Intake : Air flows from Fan side to Port side. """ direction = [self.FAN_DIRECTION_EXHAUST, self.FAN_DIRECTION_INTAKE] fan_status = self.get_status() if not fan_status: return None is_valid, fan_direction = self.fru.get_fru_data(self.fan_direction_offset) if is_valid: return direction[fan_direction[0]] return None def get_speed(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ if self.max_speed == 0: self.max_speed = self.fru.get_fru_data(self.max_speed_offset, 2)[1] self.max_speed = self.max_speed[1] << 8 | self.max_speed[0] is_valid, fan_speed = self.speed_sensor.get_reading() if not is_valid or self.max_speed == 0: return None else: speed = (100 * fan_speed)//self.max_speed return speed def get_speed_rpm(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ is_valid, fan_speed = self.speed_sensor.get_reading() return fan_speed if is_valid else None def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return self.fanindex def is_replaceable(self): """ Indicate whether Fan is replaceable. Returns: bool: True if it is replaceable. """ return False def get_speed_tolerance(self): """ Retrieves the speed tolerance of the fan Returns: An integer, the percentage of variance from target speed which is considered tolerable """ if self.get_presence(): # The tolerance value is fixed as 20% for all the DellEMC platforms tolerance = 20 else: tolerance = 0 return tolerance def set_status_led(self, color): """ Set led to expected color Args: color: A string representing the color with which to set the fan status LED Returns: bool: True if set success, False if fail. """ # Fan tray status LED controlled by HW # Return True to avoid thermalctld alarm return True
class Psu(PsuBase): """DellEMC Platform-specific PSU class""" # { PSU-ID: { Sensor-Name: Sensor-ID } } SENSOR_MAPPING = { 1: { "State": 0x2f, "Current": 0x37, "Power": 0x38, "Voltage": 0x36, "Temperature": 0x35 }, 2: { "State": 0x39, "Current": 0x41, "Power": 0x42, "Voltage": 0x40, "Temperature": 0x3F } } # ( PSU-ID: FRU-ID } FRU_MAPPING = {1: 3, 2: 4} def __init__(self, psu_index): PsuBase.__init__(self) # PSU is 1-based in DellEMC platforms self.index = psu_index + 1 self.state_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.voltage_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Voltage"]) self.current_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Current"]) self.power_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Power"]) self.temp_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Temperature"]) self.fru = IpmiFru(self.FRU_MAPPING[self.index]) self.psu_type_raw_cmd = "0x3A 0x0B {}".format(psu_index + 1) self._fan_list.append( Fan(fan_index=self.index, psu_fan=True, dependency=self)) def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return "PSU{}".format(self.index) def get_presence(self): """ Retrieves the presence of the Power Supply Unit (PSU) Returns: bool: True if PSU is present, False if not """ presence = False is_valid, state = self.state_sensor.get_reading() if is_valid: if state & 0b1: presence = True return presence def get_model(self): """ Retrieves the part number of the PSU Returns: string: Part number of PSU """ return self.fru.get_board_part_number() def get_serial(self): """ Retrieves the serial number of the PSU Returns: string: Serial number of PSU """ return self.fru.get_board_serial() def get_status(self): """ Retrieves the operational status of the PSU Returns: bool: True if PSU is operating properly, False if not """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state & 0b1010) == 0: status = True return status def get_voltage(self): """ Retrieves current PSU voltage output Returns: A float number, the output voltage in volts, e.g. 12.1 """ is_valid, voltage = self.voltage_sensor.get_reading() if not is_valid: return None return float(voltage) def get_voltage_low_threshold(self): """ Returns PSU low threshold in Volts """ is_valid, low_threshold = self.voltage_sensor.get_threshold( "LowerCritical") if not is_valid: low_threshold = 11.4 low_threshold = "{:.2f}".format(low_threshold) return float(low_threshold) def get_voltage_high_threshold(self): """ Returns PSU high threshold in Volts """ is_valid, high_threshold = self.voltage_sensor.get_threshold( "UpperCritical") if not is_valid: high_threshold = 12.6 high_threshold = "{:.2f}".format(high_threshold) return float(high_threshold) def get_temperature(self): """ Retrieves current temperature reading from thermal Returns: A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, temperature = self.temp_sensor.get_reading() if not is_valid: temperature = 0 return float(temperature) def get_temperature_high_threshold(self): """ Returns the high temperature threshold for PSU in Celsius """ is_valid, high_threshold = self.temp_sensor.get_threshold( "UpperCritical") if not is_valid: high_threshold = 113 high_threshold = "{:.2f}".format(high_threshold) return float(high_threshold) def get_current(self): """ Retrieves present electric current supplied by PSU Returns: A float number, electric current in amperes, e.g. 15.4 """ is_valid, current = self.current_sensor.get_reading() if not is_valid: return None return float(current) def get_power(self): """ Retrieves current energy supplied by PSU Returns: A float number, the power in watts, e.g. 302.6 """ is_valid, power = self.power_sensor.get_reading() if not is_valid: return None return float(power) def get_powergood_status(self): """ Retrieves the powergood status of PSU Returns: A boolean, True if PSU has stablized its output voltages and passed all its internal self-tests, False if not. """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state & 0b1010) == 0: status = True return status def get_mfr_id(self): """ Retrives the Manufacturer Id of PSU Returns: A string, the manunfacturer id. """ return self.fru.get_board_mfr_id() def get_type(self): """ Retrives the Power Type of PSU Returns : A string, PSU power type """ psu_type = [None, 'AC', 'AC', 'DC'] type_res = get_ipmitool_raw_output(self.psu_type_raw_cmd) if type_res is not None and len(type_res) == 1: return psu_type[type_res[0]] return None def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return self.index def is_replaceable(self): """ Indicate whether this PSU is replaceable. Returns: bool: True if it is replaceable. """ return True
class Psu(PsuBase): """DellEMC Platform-specific PSU class""" # { PSU-ID: { Sensor-Name: Sensor-ID } } SENSOR_MAPPING = { 1: { "State": 0x31, "Current": 0x39, "Power": 0x37, "Voltage": 0x38 }, 2: { "State": 0x32, "Current": 0x3F, "Power": 0x3D, "Voltage": 0x3E } } # ( PSU-ID: FRU-ID } FRU_MAPPING = { 1: 1, 2: 2 } def __init__(self, psu_index): PsuBase.__init__(self) # PSU is 1-based in DellEMC platforms self.index = psu_index + 1 self.state_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Voltage"]) self.current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Current"]) self.power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Power"]) self.fru = IpmiFru(self.FRU_MAPPING[self.index]) self._fan_list.append(Fan(fan_index=self.index, psu_fan=True, dependency=self)) def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return "PSU{}".format(self.index) def get_presence(self): """ Retrieves the presence of the Power Supply Unit (PSU) Returns: bool: True if PSU is present, False if not """ presence = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state & 0b1): presence = True return presence def get_model(self): """ Retrieves the part number of the PSU Returns: string: Part number of PSU """ return self.fru.get_board_part_number() def get_serial(self): """ Retrieves the serial number of the PSU Returns: string: Serial number of PSU """ return self.fru.get_board_serial() def get_status(self): """ Retrieves the operational status of the PSU Returns: bool: True if PSU is operating properly, False if not """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state == 0x01): status = True return status def get_voltage(self): """ Retrieves current PSU voltage output Returns: A float number, the output voltage in volts, e.g. 12.1 """ is_valid, voltage = self.voltage_sensor.get_reading() if not is_valid: voltage = 0 return float(voltage) def get_current(self): """ Retrieves present electric current supplied by PSU Returns: A float number, electric current in amperes, e.g. 15.4 """ is_valid, current = self.current_sensor.get_reading() if not is_valid: current = 0 return float(current) def get_power(self): """ Retrieves current energy supplied by PSU Returns: A float number, the power in watts, e.g. 302.6 """ is_valid, power = self.power_sensor.get_reading() if not is_valid: power = 0 return float(power) def get_powergood_status(self): """ Retrieves the powergood status of PSU Returns: A boolean, True if PSU has stablized its output voltages and passed all its internal self-tests, False if not. """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state == 0x01): status = True return status def get_mfr_id(self): """ Retrives the Manufacturer Id of PSU Returns: A string, the manunfacturer id. """ return self.fru.get_board_mfr_id() def get_type(self): """ Retrives the Power Type of PSU Returns : A string, PSU power type """ info = self.fru.get_board_product().split(',') if 'AC' in info : return 'AC' if 'DC' in info : return 'DC' return 'Unknown'
class Thermal(ThermalBase): """DellEMC Platform-specific Thermal class""" # [ Sensor-Name, Sensor-ID ] SENSOR_MAPPING = [['CPU On-board', 0x6], ['ASIC On-board', 0x8], ['System Front Left', 0x3], ['System Front Middle', 0x7], ['System Front Right', 0x4], ['Inlet Airflow Sensor', 0x5], ['PSU1 Airflow Sensor', 0x2], ['PSU2 Airflow Sensor', 0x1]] def __init__(self, thermal_index): ThermalBase.__init__(self) self.index = thermal_index + 1 self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1]) def get_name(self): """ Retrieves the name of the thermal Returns: string: The name of the thermal """ return self.SENSOR_MAPPING[self.index - 1][0] def get_presence(self): """ Retrieves the presence of the thermal Returns: bool: True if thermal is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the Thermal Returns: string: Model/part number of Thermal """ return 'NA' def get_serial(self): """ Retrieves the serial number of the Thermal Returns: string: Serial number of Thermal """ return 'NA' def get_status(self): """ Retrieves the operational status of the thermal Returns: A boolean value, True if thermal is operating properly, False if not """ return True def get_temperature(self): """ Retrieves current temperature reading from thermal Returns: A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, temperature = self.sensor.get_reading() if not is_valid: temperature = 0 return float(temperature) def get_high_threshold(self): """ Retrieves the high threshold temperature of thermal Returns: A float number, the high threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, high_threshold = self.sensor.get_threshold( "UpperNonRecoverable") if not is_valid: high_threshold = 0 return float(high_threshold) def get_low_threshold(self): """ Retrieves the low threshold temperature of thermal Returns: A float number, the low threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, low_threshold = self.sensor.get_threshold( "LowerNonRecoverable") if not is_valid: low_threshold = 0 return float(low_threshold) def set_high_threshold(self, temperature): """ Sets the high threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ # Thermal threshold values are pre-defined based on HW. return False def set_low_threshold(self, temperature): """ Sets the low threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ # Thermal threshold values are pre-defined based on HW. return False
class Psu(PsuBase): """DellEMC Platform-specific PSU class""" # { PSU-ID: { Sensor-Name: Sensor-ID } } SENSOR_MAPPING = { 1: { "State": 0x31, "Current": 0x39, "Power": 0x37, "Voltage": 0x38, "InCurrent": 0x36, "InPower": 0x34, "InVoltage": 0x35, "Temperature": 0xc }, 2: { "State": 0x32, "Current": 0x3F, "Power": 0x3D, "Voltage": 0x3E, "InCurrent": 0x3C, "InPower": 0x3A, "InVoltage": 0x3B, "Temperature": 0xd } } # ( PSU-ID: FRU-ID } FRU_MAPPING = {1: 1, 2: 2} def __init__(self, psu_index): PsuBase.__init__(self) # PSU is 1-based in DellEMC platforms self.index = psu_index + 1 self.state_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.voltage_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Voltage"]) self.current_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Current"]) self.power_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Power"]) self.input_voltage_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["InVoltage"]) self.input_current_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["InCurrent"]) self.input_power_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["InPower"]) self.temp_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Temperature"]) self.fru = IpmiFru(self.FRU_MAPPING[self.index]) self._fan_list.append( Fan(fan_index=self.index, psu_fan=True, dependency=self)) def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return "PSU{}".format(self.index) def get_presence(self): """ Retrieves the presence of the Power Supply Unit (PSU) Returns: bool: True if PSU is present, False if not """ presence = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state == 0x01): presence = True return presence def get_temperature(self): """ Retrieves current temperature reading from thermal Returns: A float number of current temperature in Celcius up to nearest thousandth of one degree celcius, e.g. 30.125 """ is_valid, temperature = self.temp_sensor.get_reading() if not is_valid: temperature = 0 return float(temperature) def get_temperature_high_threshold(self): """ Returns the high temperature threshold for PSU in Celsius """ is_valid, high_threshold = self.temp_sensor.get_threshold( "UpperCritical") if not is_valid: high_threshold = 105 high_threshold = "{:.2f}".format(high_threshold) return float(high_threshold) def get_model(self): """ Retrieves the part number of the PSU Returns: string: Part number of PSU """ return self.fru.get_board_part_number() def get_serial(self): """ Retrieves the serial number of the PSU Returns: string: Serial number of PSU """ return self.fru.get_board_serial() def get_revision(self): """ Retrives thehardware revision of the device Returns: String: revision value of device """ serial = self.fru.get_board_serial() if serial != "NA" and len(serial) == 23: return serial[-3:] else: return "NA" def is_replaceable(self): """ Indicate whether this PSU is replaceable. Returns: bool: True if it is replaceable. """ return True def get_status(self): """ Retrieves the operational status of the PSU Returns: bool: True if PSU is operating properly, False if not """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state == 0x01): status = True return status def get_voltage(self): """ Retrieves current PSU voltage output Returns: A float number, the output voltage in volts, e.g. 12.1 """ is_valid, voltage = self.voltage_sensor.get_reading() if not is_valid: return 0.0 return float(voltage) def get_voltage_low_threshold(self): """ Returns PSU low threshold in Volts """ is_valid, low_threshold = self.voltage_sensor.get_threshold( "LowerCritical") if not is_valid: low_threshold = 11.6 low_threshold = "{:.2f}".format(low_threshold) return float(low_threshold) def get_voltage_high_threshold(self): """ Returns PSU high threshold in Volts """ is_valid, high_threshold = self.voltage_sensor.get_threshold( "UpperCritical") if not is_valid: high_threshold = 12.8 high_threshold = "{:.2f}".format(high_threshold) return float(high_threshold) def get_current(self): """ Retrieves present electric current supplied by PSU Returns: A float number, electric current in amperes, e.g. 15.4 """ is_valid, current = self.current_sensor.get_reading() if not is_valid: return 0.0 return float(current) def get_power(self): """ Retrieves current energy supplied by PSU Returns: A float number, the power in watts, e.g. 302.6 """ is_valid, power = self.power_sensor.get_reading() if not is_valid: return 0.0 return float(power) def get_input_voltage(self): """ Retrieves current PSU voltage input Returns: A float number, the input voltage in volts, e.g. 12.1 """ is_valid, input_voltage = self.input_voltage_sensor.get_reading() if not is_valid: return 0.0 return float(input_voltage) def get_input_current(self): """ Retrieves present electric current supplied to PSU Returns: A float number, electric current in amperes, e.g. 15.4 """ is_valid, input_current = self.input_current_sensor.get_reading() if not is_valid: return 0.0 return float(input_current) def get_input_power(self): """ Retrieves current energy supplied to PSU Returns: A float number, the power in watts, e.g. 302.6 """ is_valid, input_power = self.input_power_sensor.get_reading() if not is_valid: return None return float(input_power) def get_powergood_status(self): """ Retrieves the powergood status of PSU Returns: A boolean, True if PSU has stablized its output voltages and passed all its internal self-tests, False if not. """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state == 0x01): status = True return status def get_mfr_id(self): """ Retrives the Manufacturer Id of PSU Returns: A string, the manunfacturer id. """ return self.fru.get_board_mfr_id() def get_type(self): """ Retrives the Power Type of PSU Returns : A string, PSU power type """ board_product = self.fru.get_board_product() if board_product is not None: info = board_product.split(',') if 'AC' in info: return 'AC' if 'DC' in info: return 'DC' return None def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return self.index def get_maximum_supplied_power(self): """ Retrieves the maximum supplied power by PSU Returns: A float number, the maximum power output in Watts. e.g. 1200.1 """ return float(750) def set_status_led(self, color): """ Sets the state of the PSU status LED Args: color: A string representing the color with which to set the PSU status LED Note: Only support green and off Returns: bool: True if status LED state is set successfully, False if not """ # Hardware not supported return False
class Thermal(ThermalBase): """DellEMC Platform-specific Thermal class""" # [ Sensor-Name, Sensor-ID ] SENSOR_MAPPING = [['CPU On-board', 0x5], ['Baseboard U3', 0x4], ['SW Internal', 0x61], ['Fan U52', 0x0], ['Fan U17', 0x1], ['SW U52', 0x2], ['SW U16', 0x3], ['PSU1 Inlet', 0x34], ['PSU1 Hotspot', 0x35], ['PSU2 Inlet', 0x3E], ['PSU2 Hotspot', 0x3F], ['SW U04', 0x4F], ['SW U14', 0x56], ['SW U4403', 0x5D]] def __init__(self, thermal_index=0): ThermalBase.__init__(self) self.index = thermal_index + 1 self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1]) def get_name(self): """ Retrieves the name of the thermal Returns: string: The name of the thermal """ return self.SENSOR_MAPPING[self.index - 1][0] def get_presence(self): """ Retrieves the presence of the thermal Returns: bool: True if thermal is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the Thermal Returns: string: Model/part number of Thermal """ return 'NA' def get_serial(self): """ Retrieves the serial number of the Thermal Returns: string: Serial number of Thermal """ return 'NA' def get_status(self): """ Retrieves the operational status of the thermal Returns: A boolean value, True if thermal is operating properly, False if not """ return True def get_temperature(self): """ Retrieves current temperature reading from thermal Returns: A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, temperature = self.sensor.get_reading() if not is_valid: temperature = 0 return float(temperature) def get_high_threshold(self): """ Retrieves the high threshold temperature of thermal Returns: A float number, the high threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, high_threshold = self.sensor.get_threshold( "UpperNonCritical") if not is_valid: return super(Thermal, self).get_high_threshold() return float(high_threshold) def get_low_threshold(self): """ Retrieves the low threshold temperature of thermal Returns: A float number, the low threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, low_threshold = self.sensor.get_threshold( "LowerNonRecoverable") if not is_valid: low_threshold = 0 return float(low_threshold) def get_high_critical_threshold(self): """ Retrieves the high critical threshold temperature of thermal Returns: A float number, the high critical threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, high_crit_threshold = self.sensor.get_threshold( "UpperCritical") if not is_valid: return super(Thermal, self).get_high_critical_threshold() return float(high_crit_threshold) def set_high_threshold(self, temperature): """ Sets the high threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ # Thermal threshold values are pre-defined based on HW. return False def set_low_threshold(self, temperature): """ Sets the low threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ # Thermal threshold values are pre-defined based on HW. return False
def __init__(self, thermal_index=0): ThermalBase.__init__(self) self.index = thermal_index + 1 self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1]) self.has_high_threshold = self.SENSOR_MAPPING[self.index - 1][2] self.has_high_crit_threshold = self.SENSOR_MAPPING[self.index - 1][3]
class Thermal(ThermalBase): """DellEMC Platform-specific Thermal class""" # [ Sensor-Name, Sensor-ID, high threshold, high critical_threshold ] SENSOR_MAPPING = [ ['CPU On-board', 0x5, False, True], ['Baseboard U3', 0x4, False, False], ['SW Internal', 0x61, True, True], ['Fan U52', 0x0, True, True], ['Fan U17', 0x1, False, False], ['SW U52', 0x2, False, False], ['SW U16', 0x3, True, True], ['PSU1 Inlet', 0x34, False, False], ['PSU1 Hotspot', 0x35, False, False], ['PSU2 Inlet', 0x3E, False, False], ['PSU2 Hotspot', 0x3F, False, False], ['SW U04', 0x4F, False, False], ['SW U14', 0x56, False, False], ['SW U4403', 0x5D, False, False] ] def __init__(self, thermal_index=0): ThermalBase.__init__(self) self.index = thermal_index + 1 self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1]) self.has_high_threshold = self.SENSOR_MAPPING[self.index - 1][2] self.has_high_crit_threshold = self.SENSOR_MAPPING[self.index - 1][3] def get_name(self): """ Retrieves the name of the thermal Returns: string: The name of the thermal """ return self.SENSOR_MAPPING[self.index - 1][0] def get_presence(self): """ Retrieves the presence of the thermal Returns: bool: True if thermal is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the Thermal Returns: string: Model/part number of Thermal """ return 'NA' def get_serial(self): """ Retrieves the serial number of the Thermal Returns: string: Serial number of Thermal """ return 'NA' def get_status(self): """ Retrieves the operational status of the thermal Returns: A boolean value, True if thermal is operating properly, False if not """ return True def get_temperature(self): """ Retrieves current temperature reading from thermal Returns: A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, temperature = self.sensor.get_reading() if not is_valid: temperature = 0 return float(temperature) def get_high_threshold(self): """ Retrieves the high threshold temperature of thermal Returns: A float number, the high threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ if self.has_high_threshold: is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical") if is_valid: return float(high_threshold) return super(Thermal, self).get_high_threshold() def get_low_threshold(self): """ Retrieves the low threshold temperature of thermal Returns: A float number, the low threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ return 0.0 def get_high_critical_threshold(self): """ Retrieves the high critical threshold temperature of thermal Returns: A float number, the high critical threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ if self.has_high_crit_threshold: is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical") if is_valid: return float(high_crit_threshold) return super(Thermal, self).get_high_critical_threshold() def set_high_threshold(self, temperature): """ Sets the high threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ # Thermal threshold values are pre-defined based on HW. return False def set_low_threshold(self, temperature): """ Sets the low threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ # Thermal threshold values are pre-defined based on HW. return False def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return self.index def is_replaceable(self): """ Indicate whether this Thermal is replaceable. Returns: bool: True if it is replaceable. """ return False
def __init__(self, psu_index): PsuBase.__init__(self) # PSU is 1-based in DellEMC platforms self.index = psu_index + 1 self.state_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.voltage_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Voltage"]) self.current_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Current"]) self.power_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Power"]) self.input_voltage_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["InVoltage"]) self.input_current_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["InCurrent"]) self.input_power_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["InPower"]) self.temp_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Temperature"]) self.psu_type_offset = PSU_TYPE_OFFSET self.fru = IpmiFru(self.FRU_MAPPING[self.index]) self._fan_list.append( Fan(fan_index=self.index, psu_fan=True, dependency=self))
class Psu(PsuBase): """DellEMC Platform-specific PSU class""" # { PSU-ID: { Sensor-Name: Sensor-ID } } SENSOR_MAPPING = { 1: { "State": 0x2f, "Current": 0x37, "Power": 0x38, "Voltage": 0x36 }, 2: { "State": 0x39, "Current": 0x41, "Power": 0x42, "Voltage": 0x40 } } # ( PSU-ID: FRU-ID } FRU_MAPPING = {1: 3, 2: 4} def __init__(self, psu_index): PsuBase.__init__(self) # PSU is 1-based in DellEMC platforms self.index = psu_index + 1 self.state_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.voltage_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Voltage"]) self.current_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Current"]) self.power_sensor = IpmiSensor( self.SENSOR_MAPPING[self.index]["Power"]) self.fru = IpmiFru(self.FRU_MAPPING[self.index]) self.psu_type_raw_cmd = "0x3A 0x0B {}".format(psu_index + 1) self._fan_list.append( Fan(fan_index=self.index, psu_fan=True, dependency=self)) def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return "PSU{}".format(self.index) def get_presence(self): """ Retrieves the presence of the Power Supply Unit (PSU) Returns: bool: True if PSU is present, False if not """ presence = False is_valid, state = self.state_sensor.get_reading() if is_valid: if state & 0b1: presence = True return presence def get_model(self): """ Retrieves the part number of the PSU Returns: string: Part number of PSU """ return self.fru.get_board_part_number() def get_serial(self): """ Retrieves the serial number of the PSU Returns: string: Serial number of PSU """ return self.fru.get_board_serial() def get_status(self): """ Retrieves the operational status of the PSU Returns: bool: True if PSU is operating properly, False if not """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state & 0b1010) == 0: status = True return status def get_voltage(self): """ Retrieves current PSU voltage output Returns: A float number, the output voltage in volts, e.g. 12.1 """ is_valid, voltage = self.voltage_sensor.get_reading() if not is_valid: return None return "{:.1f}".format(voltage) def get_current(self): """ Retrieves present electric current supplied by PSU Returns: A float number, electric current in amperes, e.g. 15.4 """ is_valid, current = self.current_sensor.get_reading() if not is_valid: return None return "{:.1f}".format(current) def get_power(self): """ Retrieves current energy supplied by PSU Returns: A float number, the power in watts, e.g. 302.6 """ is_valid, power = self.power_sensor.get_reading() if not is_valid: return None return "{:.1f}".format(power) def get_powergood_status(self): """ Retrieves the powergood status of PSU Returns: A boolean, True if PSU has stablized its output voltages and passed all its internal self-tests, False if not. """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if (state & 0b1010) == 0: status = True return status def get_mfr_id(self): """ Retrives the Manufacturer Id of PSU Returns: A string, the manunfacturer id. """ return self.fru.get_board_mfr_id() def get_type(self): """ Retrives the Power Type of PSU Returns : A string, PSU power type """ psu_type = [None, 'AC', 'AC', 'DC'] type_res = get_ipmitool_raw_output(self.psu_type_raw_cmd) if type_res is not None and len(type_res) == 1: return psu_type[type_res[0]] return None
class Fan(FanBase): """DellEMC Platform-specific Fan class""" # { FAN-ID: { Sensor-Name: Sensor-ID } } FAN_SENSOR_MAPPING = { 1: { "Prsnt": 0x57, "State": 0x57, "Speed": 0x24 }, 2: { "Prsnt": 0x5b, "State": 0x5b, "Speed": 0x20 }, 3: { "Prsnt": 0x58, "State": 0x58, "Speed": 0x25 }, 4: { "Prsnt": 0x5c, "State": 0x5c, "Speed": 0x21 }, 5: { "Prsnt": 0x57, "State": 0x59, "Speed": 0x26 }, 6: { "Prsnt": 0x59, "State": 0x5d, "Speed": 0x22 }, 7: { "Prsnt": 0x5a, "State": 0x5a, "Speed": 0x27 }, 8: { "Prsnt": 0x5e, "State": 0x5e, "Speed": 0x23 } } PSU_FAN_SENSOR_MAPPING = { 1: { "State": 0x31, "Speed": 0x2e }, 2: { "State": 0x32, "Speed": 0x2f } } # { FANTRAY-ID: FRU-ID } FAN_FRU_MAPPING = {1: 0, 2: 0, 3: 0, 4: 0} PSU_FRU_MAPPING = {1: 0, 2: 0} def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None): self.is_psu_fan = psu_fan if not self.is_psu_fan: # API index is starting from 0, DellEMC platform index is # starting from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 if (self.fanindex == 1): self.max_speed_offset = FAN1_MAX_SPEED_OFFSET else: self.max_speed_offset = FAN2_MAX_SPEED_OFFSET self.index = (self.fantrayindex - 1) * 2 + self.fanindex self.prsnt_sensor = IpmiSensor( self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], is_discrete=True) self.state_sensor = IpmiSensor( self.FAN_SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.speed_sensor = IpmiSensor( self.FAN_SENSOR_MAPPING[self.index]["Speed"]) self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) else: self.dependency = dependency self.fanindex = fan_index self.state_sensor = IpmiSensor( self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], is_discrete=True) self.speed_sensor = IpmiSensor( self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex]) self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET self.max_speed = 16000 def get_name(self): """ Retrieves the name of the device Returns: String: The name of the device """ if self.is_psu_fan: return "PSU{} Fan".format(self.fanindex) else: return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex) def get_model(self): """ Retrieves the part number of the FAN Returns: String: Part number of FAN """ return self.fru.get_board_part_number() def get_serial(self): """ Retrieves the serial number of the FAN Returns: String: Serial number of FAN """ return self.fru.get_board_serial() def get_presence(self): """ Retrieves the presence of the FAN Returns: bool: True if fan is present, False if not """ if self.is_psu_fan: return self.dependency.get_presence() else: # In S5212F, Fans are fixed return True def get_status(self): """ Retrieves the operational status of the FAN Returns: bool: True if FAN is operating properly, False if not """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if self.is_psu_fan: if not state > 1: status = True else: if state == 0x00: status = True return status def get_direction(self): """ Retrieves the fan airfow direction Returns: A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction Notes: In DellEMC platforms, - Forward/Exhaust : Air flows from Port side to Fan side. - Reverse/Intake : Air flows from Fan side to Port side. """ board_info = self.fru.get_board_part_number() if board_info is not None: board_part_no = board_info[0:6] if board_part_no in switch_sku: return switch_sku[board_part_no][1] return None def get_speed(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ speed = None if not self.is_psu_fan: if self.max_speed == 0: self.max_speed = self.fru.get_fru_data(self.max_speed_offset, 2)[1] self.max_speed = self.max_speed[1] << 8 | self.max_speed[0] is_valid, fan_speed = self.speed_sensor.get_reading() if is_valid and self.max_speed > 0: speed = (100 * fan_speed) // self.max_speed return speed def get_speed_rpm(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ fan_speed = None if not self.is_psu_fan: is_valid, fan_speed = self.speed_sensor.get_reading() return fan_speed if is_valid else None def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return self.fanindex def is_replaceable(self): """ Indicate whether Fan is replaceable. Returns: bool: True if it is replaceable. """ return False def get_speed_tolerance(self): """ Retrieves the speed tolerance of the fan Returns: An integer, the percentage of variance from target speed which is considered tolerable """ if self.get_presence(): # The tolerance value is fixed as 20% for all the DellEMC platforms tolerance = 20 else: tolerance = 0 return tolerance def set_status_led(self, color): """ Set led to expected color Args: color: A string representing the color with which to set the fan status LED Returns: bool: True if set success, False if fail. """ # Fan tray status LED controlled by HW # Return True to avoid thermalctld alarm return True
class Fan(FanBase): """DellEMC Platform-specific Fan class""" # { FAN-ID: { Sensor-Name: Sensor-ID } } FAN_SENSOR_MAPPING = { 1: {"Prsnt": 0x6, "State": 0x6, "Speed": 0xd}, 2: {"Prsnt": 0x6, "State": 0x6, "Speed": 0x45}, 3: {"Prsnt": 0x7, "State": 0x7, "Speed": 0xe}, 4: {"Prsnt": 0x7, "State": 0x7, "Speed": 0x46}, 5: {"Prsnt": 0x8, "State": 0x8, "Speed": 0xf}, 6: {"Prsnt": 0x8, "State": 0x8, "Speed": 0x47}, 7: {"Prsnt": 0x9, "State": 0x9, "Speed": 0x10}, 8: {"Prsnt": 0x9, "State": 0x9, "Speed": 0x48}, 9: {"Prsnt": 0xa, "State": 0xa, "Speed": 0x11}, 10: {"Prsnt": 0xa, "State": 0xa, "Speed": 0x49}, 11: {"Prsnt": 0xb, "State": 0xb, "Speed": 0x12}, 12: {"Prsnt": 0xb, "State": 0xb, "Speed": 0x4a}, 13: {"Prsnt": 0xc, "State": 0xc, "Speed": 0x13}, 14: {"Prsnt": 0xc, "State": 0xc, "Speed": 0x4b} } PSU_FAN_SENSOR_MAPPING = { 1: {"State": 0x2f, "Speed": 0x33}, 2: {"State": 0x39, "Speed": 0x3d} } # { FANTRAY-ID: FRU-ID } FAN_FRU_MAPPING = { 1: 6, 2: 7, 3: 8, 4: 9, 5: 10, 6: 11, 7: 12 } PSU_FRU_MAPPING = { 1: 3, 2: 4 } def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None): self.is_psu_fan = psu_fan if not self.is_psu_fan: # API index is starting from 0, DellEMC platform index is # starting from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 self.index = (self.fantrayindex - 1) * 2 + self.fanindex self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], is_discrete=True) self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"]) self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(fantray_index) else: self.dependency = dependency self.fanindex = fan_index self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex]) self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(7+(fan_index-1)) self.max_speed = 23500 def get_name(self): """ Retrieves the name of the device Returns: String: The name of the device """ if self.is_psu_fan: return "PSU{} Fan".format(self.fanindex) else: return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex) def get_model(self): """ Retrieves the part number of the FAN Returns: String: Part number of FAN """ if self.is_psu_fan: return None else: return self.fru.get_board_part_number() def get_serial(self): """ Retrieves the serial number of the FAN Returns: String: Serial number of FAN """ if self.is_psu_fan: return None else: return self.fru.get_board_serial() def get_presence(self): """ Retrieves the presence of the FAN Returns: bool: True if fan is present, False if not """ presence = False if self.is_psu_fan: return self.dependency.get_presence() else: is_valid, state = self.prsnt_sensor.get_reading() if is_valid: if (state & 0b1): presence = True return presence def get_status(self): """ Retrieves the operational status of the FAN Returns: bool: True if FAN is operating properly, False if not """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if state & 0b1: status = True return status def get_direction(self): """ Retrieves the fan airfow direction Returns: A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction Notes: In DellEMC platforms, - Forward/Exhaust : Air flows from Port side to Fan side. - Reverse/Intake : Air flows from Fan side to Port side. """ direction = [self.FAN_DIRECTION_EXHAUST, self.FAN_DIRECTION_INTAKE] fan_status = self.get_presence() if not fan_status: return None dir_res = get_ipmitool_raw_output(self.fan_dir_raw_cmd) if dir_res is not None and len(dir_res) == 1 : return direction[dir_res[0]] else: return None def get_speed(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ if self.max_speed == 0: self.max_speed = 23500 is_valid, fan_speed = self.speed_sensor.get_reading() if not is_valid or self.max_speed == 0: return None else: speed = (100 * fan_speed)/self.max_speed return speed def get_speed_rpm(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ is_valid, fan_speed = self.speed_sensor.get_reading() return fan_speed if is_valid else None
def __init__(self, thermal_index): ThermalBase.__init__(self) self.index = thermal_index + 1 self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1])
class Fan(FanBase): """DellEMC Platform-specific Fan class""" # { FAN-ID: { Sensor-Name: Sensor-ID } } FAN_SENSOR_MAPPING = { 1: {"Prsnt": 0x53, "State": 0x57, "Speed": 0x24}, 2: {"Prsnt": 0x53, "State": 0x5b, "Speed": 0x20}, 3: {"Prsnt": 0x54, "State": 0x58, "Speed": 0x25}, 4: {"Prsnt": 0x54, "State": 0x5c, "Speed": 0x21}, 5: {"Prsnt": 0x55, "State": 0x59, "Speed": 0x26}, 6: {"Prsnt": 0x55, "State": 0x5d, "Speed": 0x22}, 7: {"Prsnt": 0x56, "State": 0x5a, "Speed": 0x27}, 8: {"Prsnt": 0x56, "State": 0x5e, "Speed": 0x23} } PSU_FAN_SENSOR_MAPPING = { 1: {"State": 0x31, "Speed": 0x28}, 2: {"State": 0x32, "Speed": 0x29} } # { FANTRAY-ID: FRU-ID } FAN_FRU_MAPPING = { 1: 3, 2: 4, 3: 5, 4: 6 } PSU_FRU_MAPPING = { 1: 1, 2: 2 } def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None): self.is_psu_fan = psu_fan if not self.is_psu_fan: # API index is starting from 0, DellEMC platform index is # starting from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 if (self.fanindex == 1): self.max_speed_offset = FAN1_MAX_SPEED_OFFSET else: self.max_speed_offset = FAN2_MAX_SPEED_OFFSET self.fan_direction_offset = FAN_DIRECTION_OFFSET self.index = (self.fantrayindex - 1) * 2 + self.fanindex self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], is_discrete=True) self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"]) self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) else: self.dependency = dependency self.fanindex = fan_index self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex]) self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET self.fan_direction_offset = PSU_FAN_DIRECTION_OFFSET self.max_speed = self.fru.get_fru_data(self.max_speed_offset,2)[1] self.max_speed = self.max_speed[1] << 8 | self.max_speed[0] def get_name(self): """ Retrieves the name of the device Returns: String: The name of the device """ if self.is_psu_fan: return "PSU{} Fan".format(self.fanindex) else: return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex) def get_model(self): """ Retrieves the part number of the FAN Returns: String: Part number of FAN """ if self.is_psu_fan: return 'NA' else: return self.fru.get_board_part_number() def get_serial(self): """ Retrieves the serial number of the FAN Returns: String: Serial number of FAN """ if self.is_psu_fan: return 'NA' else: return self.fru.get_board_serial() def get_presence(self): """ Retrieves the presence of the FAN Returns: bool: True if fan is present, False if not """ presence = False if self.is_psu_fan: return self.dependency.get_presence() else: is_valid, state = self.prsnt_sensor.get_reading() if is_valid: if (state & 0b1): presence = True return presence def get_status(self): """ Retrieves the operational status of the FAN Returns: bool: True if FAN is operating properly, False if not """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if not state > 1: status = True return status def get_direction(self): """ Retrieves the fan airfow direction Returns: A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction Notes: In DellEMC platforms, - Forward/Exhaust : Air flows from Port side to Fan side. - Reverse/Intake : Air flows from Fan side to Port side. """ direction = [self.FAN_DIRECTION_EXHAUST, self.FAN_DIRECTION_INTAKE] fan_status = self.get_presence() if not fan_status: return 'NA' is_valid, fan_direction = self.fru.get_fru_data(self.fan_direction_offset) if is_valid and fan_direction[0] < len(direction): return direction[fan_direction[0]] else: return 'NA' def get_speed(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ if self.max_speed == 0: self.max_speed = self.fru.get_fru_data(self.max_speed_offset,2)[1] self.max_speed = self.max_speed[1] << 8 | self.max_speed[0] is_valid, fan_speed = self.speed_sensor.get_reading() if not is_valid or self.max_speed == 0: speed = 0 else: speed = (100 * fan_speed)//self.max_speed return speed def get_speed_rpm(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ fan_speed = 0 is_valid, fan_speed = self.speed_sensor.get_reading() return fan_speed
class Fan(FanBase): """DellEMC Platform-specific Fan class""" # { FAN-ID: { Sensor-Name: Sensor-ID } } FAN_SENSOR_MAPPING = { 1: { "Prsnt": 0x6, "State": 0x6, "Speed": 0xd }, 2: { "Prsnt": 0x6, "State": 0x6, "Speed": 0x45 }, 3: { "Prsnt": 0x7, "State": 0x7, "Speed": 0xe }, 4: { "Prsnt": 0x7, "State": 0x7, "Speed": 0x46 }, 5: { "Prsnt": 0x8, "State": 0x8, "Speed": 0xf }, 6: { "Prsnt": 0x8, "State": 0x8, "Speed": 0x47 }, 7: { "Prsnt": 0x9, "State": 0x9, "Speed": 0x10 }, 8: { "Prsnt": 0x9, "State": 0x9, "Speed": 0x48 }, 9: { "Prsnt": 0xa, "State": 0xa, "Speed": 0x11 }, 10: { "Prsnt": 0xa, "State": 0xa, "Speed": 0x49 }, 11: { "Prsnt": 0xb, "State": 0xb, "Speed": 0x12 }, 12: { "Prsnt": 0xb, "State": 0xb, "Speed": 0x4a }, 13: { "Prsnt": 0xc, "State": 0xc, "Speed": 0x13 }, 14: { "Prsnt": 0xc, "State": 0xc, "Speed": 0x4b } } PSU_FAN_SENSOR_MAPPING = { 1: { "State": 0x2f, "Speed": 0x33 }, 2: { "State": 0x39, "Speed": 0x3d } } def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None): FanBase.__init__(self) self.is_psu_fan = psu_fan if not self.is_psu_fan: # API index is starting from 0, DellEMC platform index is # starting from 1 self.fantrayindex = fantray_index + 1 self.fanindex = fan_index + 1 self.index = (self.fantrayindex - 1) * 2 + self.fanindex self.prsnt_sensor = IpmiSensor( self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], is_discrete=True) self.state_sensor = IpmiSensor( self.FAN_SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.speed_sensor = IpmiSensor( self.FAN_SENSOR_MAPPING[self.index]["Speed"]) self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(fantray_index) if self.fanindex == 1: self.max_speed = 24700 else: self.max_speed = 29700 else: self.dependency = dependency self.fanindex = fan_index self.state_sensor = IpmiSensor( self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], is_discrete=True) self.speed_sensor = IpmiSensor( self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(7 + (fan_index - 1)) self.max_speed = 26500 def get_name(self): """ Retrieves the name of the device Returns: String: The name of the device """ if self.is_psu_fan: return "PSU{} Fan".format(self.fanindex) else: return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex) def get_model(self): """ Retrieves the part number of the FAN Returns: String: Part number of FAN """ return 'NA' def get_serial(self): """ Retrieves the serial number of the FAN Returns: String: Serial number of FAN """ return 'NA' def get_presence(self): """ Retrieves the presence of the FAN Returns: bool: True if fan is present, False if not """ presence = False if self.is_psu_fan: return self.dependency.get_presence() else: is_valid, state = self.prsnt_sensor.get_reading() if is_valid: if (state & 0b1): presence = True return presence def get_status(self): """ Retrieves the operational status of the FAN Returns: bool: True if FAN is operating properly, False if not """ status = False is_valid, state = self.state_sensor.get_reading() if is_valid: if state & 0b1: status = True return status def get_direction(self): """ Retrieves the fan airfow direction Returns: A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction Notes: In DellEMC platforms, - Forward/Exhaust : Air flows from Port side to Fan side. - Reverse/Intake : Air flows from Fan side to Port side. """ direction = [self.FAN_DIRECTION_EXHAUST, self.FAN_DIRECTION_INTAKE] fan_status = self.get_presence() if not fan_status: return None dir_res = get_ipmitool_raw_output(self.fan_dir_raw_cmd) if dir_res is not None and len(dir_res) == 1: return direction[dir_res[0]] else: return None def get_speed(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ if self.max_speed == 0: self.max_speed = 23500 is_valid, fan_speed = self.speed_sensor.get_reading() if not is_valid or self.max_speed == 0: return None else: speed = (100 * fan_speed) // self.max_speed return speed def get_speed_rpm(self): """ Retrieves the speed of the fan Returns: int: percentage of the max fan speed """ is_valid, fan_speed = self.speed_sensor.get_reading() return fan_speed if is_valid else None def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return self.fanindex def is_replaceable(self): """ Indicate whether Fan is replaceable. Returns: bool: True if it is replaceable. """ return False def get_speed_tolerance(self): """ Retrieves the speed tolerance of the fan Returns: An integer, the percentage of variance from target speed which is considered tolerable """ if self.get_presence(): # The tolerance value is fixed as 20% for all the DellEMC platforms tolerance = 20 else: tolerance = 0 return tolerance def set_status_led(self, color): """ Set led to expected color Args: color: A string representing the color with which to set the fan status LED Returns: bool: True if set success, False if fail. """ # Fan tray status LED controlled by HW # Return True to avoid thermalctld alarm return True
class Thermal(ThermalBase): """DellEMC Platform-specific Thermal class""" # [ Sensor-Name, Sensor-ID, high threshold, high critical_threshold ] # TBD : # high thershold/hich crit threshold # need to be modified as True in case if it is supported # SENSOR_MAPPING = [['CPU Temp', 0xd, True, True], ['FAN Right Temp', 0x0, True, True], ['NPU Front Temp', 0x1, True, True], ['NPU Rear Temp', 0x3, True, True], ['NPU Temp', 0x8, True, True], ['PSU1 AF Temp', 0x46, False, True], ['PSU1 Mid Temp', 0x47, False, True], ['PSU1 Rear Temp', 0x48, False, True], ['PSU2 AF Temp', 0x36, False, True], ['PSU2 Mid Temp', 0x37, False, True], ['PSU2 Rear Temp', 0x38, False, True], ['PT Left Temp', 0x2, True, True], ['PT Right Temp', 0x4, True, True]] def __init__(self, thermal_index=0): ThermalBase.__init__(self) self.index = thermal_index + 1 self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1]) self.has_high_threshold = self.SENSOR_MAPPING[self.index - 1][2] self.has_high_crit_threshold = self.SENSOR_MAPPING[self.index - 1][3] def get_name(self): """ Retrieves the name of the thermal Returns: string: The name of the thermal """ return self.SENSOR_MAPPING[self.index - 1][0] def get_presence(self): """ Retrieves the presence of the thermal Returns: bool: True if thermal is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the Thermal Returns: string: Model/part number of Thermal """ return 'NA' def get_serial(self): """ Retrieves the serial number of the Thermal Returns: string: Serial number of Thermal """ return 'NA' def get_status(self): """ Retrieves the operational status of the thermal Returns: A boolean value, True if thermal is operating properly, False if not """ return True def get_temperature(self): """ Retrieves current temperature reading from thermal Returns: A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ is_valid, temperature = self.sensor.get_reading() if not is_valid: temperature = 0 return float(temperature) def get_high_threshold(self): """ Retrieves the high threshold temperature of thermal Returns: A float number, the high threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ if self.has_high_threshold: is_valid, high_threshold = self.sensor.get_threshold( "UpperNonCritical") if is_valid: return float(high_threshold) return super(Thermal, self).get_high_threshold() def get_low_threshold(self): """ Retrieves the low threshold temperature of thermal Returns: A float number, the low threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ return 0.0 def get_high_critical_threshold(self): """ Retrieves the high critical threshold temperature of thermal Returns: A float number, the high critical threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ if self.has_high_crit_threshold: is_valid, high_crit_threshold = self.sensor.get_threshold( "UpperCritical") if is_valid: return float(high_crit_threshold) return super(Thermal, self).get_high_critical_threshold() def set_high_threshold(self, temperature): """ Sets the high threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ # Thermal threshold values are pre-defined based on HW. return False def set_low_threshold(self, temperature): """ Sets the low threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ # Thermal threshold values are pre-defined based on HW. return False def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return self.index def is_replaceable(self): """ Indicate whether this Thermal is replaceable. Returns: bool: True if it is replaceable. """ return False