Skip to content

Instantly share code, notes, and snippets.

@goophile
Last active March 17, 2024 02:16
Show Gist options
  • Save goophile/c721cf6791f0371b2e83f212af5332c5 to your computer and use it in GitHub Desktop.
Save goophile/c721cf6791f0371b2e83f212af5332c5 to your computer and use it in GitHub Desktop.
i8kmon/i8kfan for Dell Precision desktop
#!/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