Skip to content

Instantly share code, notes, and snippets.

@xlfe
Created March 2, 2020 10:19
Show Gist options
  • Save xlfe/eb2dba077c46ee009e2873d922d85002 to your computer and use it in GitHub Desktop.
Save xlfe/eb2dba077c46ee009e2873d922d85002 to your computer and use it in GitHub Desktop.
manage fans
from pySMART import Device, DeviceList
import subprocess, datetime, time, logging, sys
#below this triggers an alert and fans spin up
MIN_FAN = 10
MAX_FAN = 64
IPMI_SLEEP_DELAY = 2
SYS_FAN_THRESH = [55, 50, 45, 00]
SYS_FAN_SPEEDS = [64, 48, 30, MIN_FAN]
CPU_FAN_THRESH = [65, 60, 55, 00]
CPU_FAN_SPEEDS = [64, 48, 32, MIN_FAN]
summary_temps = lambda temps: '{:.0f}/{:.0f}'.format(sum(temps) / len(temps), max(temps))
def get_hdd_temps(devs):
"""SMART attribute 194 is temperature"""
return [int(d.attributes[194].raw) for d in devs]
def get_temp_from_sysctl(sl):
return [float(_.split(':')[1].strip().replace('C','')) for _ in sl]
def get_system_temps(sysctl_list):
return filter(lambda _:_.startswith('hw.acpi.thermal.') and 'temperature' in _, sysctl_list)
def get_cpu_temps(sysctl_list):
return filter(lambda _:_.startswith('dev.cpu.') and 'temperature' in _, sysctl_list)
#ipmitool raw 0x30 0x45 0x00
def ipmi(extra):
result = subprocess.check_output(['/usr/local/bin/ipmitool', 'raw', '0x30'] + extra)
time.sleep(IPMI_SLEEP_DELAY)
return result.decode('ascii')
def thresholds():
for fan in ['FAN1', 'FAN2', 'FAN3', 'FAN4', 'FANA']:
'ipmitool sensor thresh {} lower 100 100 100'
def setup_fans():
ipmi(['0x45','0x01', '0x01'])
def fans_fullspeed():
result = ipmi([
'0x45',
'0x00'
])
return result.strip() == '01'
def set_fan(fan, speed):
ipmi(['0x70','0x66', '0x01', fan, '0x{}'.format(int(min(MAX_FAN, speed)))])
def set_cpu_fan(speed):
set_fan('0x01', speed)
return speed
def set_system_fan(speed):
set_fan('0x00', speed)
return speed
def apply_temp_policy(TEMP, SPEEDS, THRESH, FAN, adj=0):
for i, temp in enumerate(THRESH):
if TEMP >= temp:
return FAN(SPEEDS[i]+adj)
return FAN(SPEEDS[-1]+adj)
def setup_logging(debug=False):
log = logging.getLogger('ipmitemp')
log.setLevel(logging.DEBUG if debug else logging.INFO)
formatter = logging.Formatter('%(asctime)s %(name)s - %(levelname)s - %(message)s')
sh = logging.StreamHandler(stream=sys.stdout)
sh.setFormatter(formatter)
log.addHandler(sh)
return log
import time
log = setup_logging(False)
def doit():
summary = []
hdd_temps = get_hdd_temps(DeviceList().devices)
sysctl_list = str(subprocess.check_output(['/sbin/sysctl', '-a'])).split('\\n')
sys_temps = [_ for _ in get_temp_from_sysctl(get_system_temps(sysctl_list))]
cpu_temps = [_ for _ in get_temp_from_sysctl(get_cpu_temps(sysctl_list))]
summary.append('HDD:{}'.format(summary_temps(hdd_temps)))
summary.append('SYS:{}'.format(summary_temps(sys_temps)))
summary.append('CPU:{}'.format(summary_temps(cpu_temps)))
if not fans_fullspeed():
summary.append('FANS-SETUP')
setup_fans()
SYS = max(sys_temps + hdd_temps)
CPU = int(sum(cpu_temps)/len(cpu_temps))
cpu_speed = apply_temp_policy(CPU, CPU_FAN_SPEEDS, CPU_FAN_THRESH, set_cpu_fan)
sys_speed = apply_temp_policy(SYS, SYS_FAN_SPEEDS, SYS_FAN_THRESH, set_system_fan, adj=max(0,float(cpu_speed-10)*0.50))
summary.append('FAN_CPU:{:.0f}'.format(cpu_speed))
summary.append('FAN_SYS:{:.0f}'.format(sys_speed))
log.info(' '.join(sorted(summary)))
if __name__ == '__main__':
while True:
doit()
time.sleep(30)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment