Created
March 2, 2020 10:19
-
-
Save xlfe/eb2dba077c46ee009e2873d922d85002 to your computer and use it in GitHub Desktop.
manage fans
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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