Last active
March 17, 2024 02:16
-
-
Save goophile/c721cf6791f0371b2e83f212af5332c5 to your computer and use it in GitHub Desktop.
i8kmon/i8kfan for Dell Precision desktop
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
#!/usr/bin/python3 | |
import re, subprocess, time | |
# On my Dell Precision desktop, the `i8kmon` controls the fan level according to the ambient temperature, not the CPU temperature. | |
# Maybe the i8kutils only works for laptop? I don't know. Luckly, the `i8kfan` CAN control the motherboard fan and CPU fan. | |
# It's usage is `i8kfan - -`, the first number is for motherboard, the second for CPU. You should test the sequence first. | |
# What this scirpt do is simple: get temperatures from `sensors`, and change the fan levels with `i8kfan`. | |
# It's similar to the original TCL version i8kmon. | |
# I'd suggest to run it with `daemon`, in /etc/rc.local, add this: | |
# daemon --respawn --output=/tmp/i8kmon_py.log -- python3 -u /usr/bin/i8kmon.py & | |
# CPU temperature threshold, level 1 and level 2 | |
# ------------ 50 -------------- 65 ---------- | |
# ---- 45 ------------ 55 ------------ | |
# motherboard temperature threshold, level 1 and level 2 | |
# ------------ 43 -------------- 50 ---------- | |
# ---- 41 ------------ 45 ------------ | |
# if temp is below L1_LOW, turn fan off. | |
# if temp is higher than L1_HIGH, turn fan on level 1, and last until temp drop to L1_LOW. | |
# same for L2. | |
CPU_L1_LOW = 45 | |
CPU_L1_HIGH = 50 | |
CPU_L2_LOW = 55 | |
CPU_L2_HIGH = 65 | |
BOARD_L1_LOW = 41 | |
BOARD_L1_HIGH = 43 | |
BOARD_L2_LOW = 45 | |
BOARD_L2_HIGH = 50 | |
CHECK_INTERVAL = 5 | |
DEBUG = True | |
BOARD_L1_LAST = False | |
BOARD_L2_LAST = False | |
CPU_L1_LAST = False | |
CPU_L2_LAST = False | |
def log(Msg='none'): | |
global DEBUG | |
if DEBUG: | |
print('-------->>>', time.strftime("%Y-%m-%d %H:%M:%S"), Msg, '<<<------------') | |
def get_temp(): | |
temp_cmd = 'sensors' | |
try: | |
temp_output = subprocess.check_output(temp_cmd, stderr=subprocess.STDOUT, shell=True, universal_newlines=True) | |
except: | |
log(temp_cmd + " error") | |
return None | |
temp_output = str(temp_output) | |
log(temp_output) | |
matchObj = re.match(r'.*Ambient:\s+\+(\d+).*CPU:\s+\+(\d+).*', temp_output, re.MULTILINE|re.DOTALL) | |
if matchObj: | |
AmbientTemp = matchObj.group(1) | |
CPUTemp = matchObj.group(2) | |
return (int(AmbientTemp), int(CPUTemp)) | |
else: | |
return None | |
def set_fan(BoardLevel=2, CPULevel=2): | |
i8kfan_cmd = ['i8kfan', str(BoardLevel), str(CPULevel)] | |
log(i8kfan_cmd) | |
try: | |
subprocess.call(i8kfan_cmd) | |
except Exception as e: | |
log(e) | |
return None | |
else: | |
return True | |
def get_level(AmbientTemp=50, CPUTemp=80): | |
global BOARD_L1_LAST | |
global BOARD_L2_LAST | |
global CPU_L1_LAST | |
global CPU_L2_LAST | |
global CPU_L1_LOW | |
global CPU_L1_HIGH | |
global CPU_L2_LOW | |
global CPU_L2_HIGH | |
global BOARD_L1_LOW | |
global BOARD_L1_HIGH | |
global BOARD_L2_LOW | |
global BOARD_L2_HIGH | |
BoardLevel = 2 | |
CPULevel = 2 | |
# for motherboard, fan flag | |
if AmbientTemp < BOARD_L1_LOW: | |
BOARD_L1_LAST = False | |
elif AmbientTemp > BOARD_L1_HIGH: | |
BOARD_L1_LAST = True | |
if AmbientTemp < BOARD_L2_LOW: | |
BOARD_L2_LAST = False | |
elif AmbientTemp > BOARD_L2_HIGH: | |
BOARD_L2_LAST = True | |
# for motherboard, fan level | |
if AmbientTemp < BOARD_L1_LOW: | |
BoardLevel = 0 | |
elif AmbientTemp < BOARD_L1_HIGH: | |
if BOARD_L1_LAST == True: | |
BoardLevel = 1 | |
else: | |
BoardLevel = 0 | |
elif AmbientTemp < BOARD_L2_LOW: | |
BoardLevel = 1 | |
elif AmbientTemp < BOARD_L2_HIGH: | |
if BOARD_L2_LAST == True: | |
BoardLevel = 2 | |
else: | |
BoardLevel = 1 | |
else: | |
BoardLevel = 2 | |
# for CPU, fan flag | |
if CPUTemp < CPU_L1_LOW: | |
CPU_L1_LAST = False | |
elif CPUTemp > CPU_L1_HIGH: | |
CPU_L1_LAST = True | |
if CPUTemp < CPU_L2_LOW: | |
CPU_L2_LAST = False | |
elif CPUTemp > CPU_L2_HIGH: | |
CPU_L2_LAST = True | |
# for CPU, fan level | |
if CPUTemp < CPU_L1_LOW: | |
CPULevel = 0 | |
elif CPUTemp < CPU_L1_HIGH: | |
if CPU_L1_LAST == True: | |
CPULevel = 1 | |
else: | |
CPULevel = 0 | |
elif CPUTemp < CPU_L2_LOW: | |
CPULevel = 1 | |
elif CPUTemp < CPU_L2_HIGH: | |
if CPU_L2_LAST == True: | |
CPULevel = 2 | |
else: | |
CPULevel = 1 | |
else: | |
CPULevel = 2 | |
# if CPU is too hot, set two fans to level 2 | |
if CPULevel == 2: | |
BoardLevel = 2 | |
return (BoardLevel, CPULevel) | |
LastLevel = (2, 2) | |
while True: | |
time.sleep(CHECK_INTERVAL) | |
AllTemp = get_temp() | |
if AllTemp: | |
(AmbientTemp, CPUTemp) = AllTemp | |
AllLevel = get_level(AmbientTemp, CPUTemp) | |
if AllLevel: | |
(BoardLevel, CPULevel) = AllLevel | |
if AllLevel != LastLevel: | |
r1 = set_fan(BoardLevel, CPULevel) | |
if not r1: | |
log('set fan error') | |
break | |
else: | |
log('fan level not change') | |
LastLevel = AllLevel | |
else: | |
continue | |
else: | |
log('error get_temp()') | |
continue | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment