写脚本的原因
之前每次开机都要进BMC把风扇转速调低,不然吵得要死。但是又不能调得太低,因为如果调的太低怕一不留神温度就飙上去了,导致硬件出问题。
正好前几天看到了一个别人用Python写的简易风扇一键调节脚本,但是只能设置固定转速,没办法根据温度动态调节。于是我重构了这个脚本,做到了根据温度动态调节风扇转速。
环境要求
- 系统要求:
Linux
(Windows不可用,因为没有sensors软件包) - 软件环境:
Python3
环境,sensors
软件包(用于获取CPU温度)
Python源代码
import subprocess
import re
import http.client
import time
# 全局变量用于存储会话连接和令牌
conn = None
session_cookie = None
def login(IP, User, Password):
global conn, session_cookie
if conn is not None:
conn.close() # 关闭旧连接
conn = http.client.HTTPConnection(IP)
payload = "WEBVAR_USERNAME=" + User + "&WEBVAR_PASSWORD=" + Password
headers = {
'Content-Type': "application/x-www-form-urlencoded",
'Origin': "http://{}".format(IP),
'Referer': "http://{}/index.html".format(IP),
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0",
}
conn.request("POST", "/rpc/WEBSES/create.asp", payload, headers)
response = conn.getresponse().read().decode("utf-8")
match = re.search(r"'SESSION_COOKIE' : '([^']*)'", response)
if match:
session_cookie = match.group(1)
else:
raise ValueError("SESSION_COOKIE not found in the string")
def set_fan_speed(IP, fan_speeds):
global conn, session_cookie
# 设置风扇为手动模式
payload1 = "MODE=1"
headers1 = {
'Content-Type': "application/x-www-form-urlencoded",
'Cookie': "BMC_IP_ADDR={}; SessionCookie=".format(IP) + session_cookie,
}
conn.request("POST", "/rpc/setfanmode.asp", payload1, headers1)
conn.getresponse()
# 调整风扇转速
headers2 = {
'Content-Type': "application/x-www-form-urlencoded",
'Cookie': "SessionCookie=" + session_cookie + "; BMC_IP_ADDR={}".format(IP),
}
for fan_ID, Speed_x in fan_speeds.items():
payload2 = "ID=" + fan_ID + "&PERCENT=" + Speed_x
conn.request("POST", "/rpc/setfanspeed.asp", payload2, headers2)
conn.getresponse()
print("调整风扇{}转速{}%".format(fan_ID, Speed_x))
def get_package_temperatures():
output = subprocess.check_output(['sensors']).decode('utf-8')
pattern = re.compile(
r'^Package id (\d+):\s+\+([\d.]+)\.?\s*°C',
re.MULTILINE
)
matches = pattern.findall(output)
result = {f"Package id {package_id}": int(float(temp_str)) for package_id, temp_str in matches}
return result
def compute_fan_speed(temp):
if temp <= 45:
return 10
elif temp >= 70:
return 100
else:
return int(10 + (temp - 45) * (90 / (70 - 45)))
last_temp = None
if __name__ == "__main__":
IP = "192.168.0.6" #服务器BMC内网IP地址
User = "admin" #服务器BMC管理员账号
Password = "admin" #服务器BMC管理员密码
# 首次登录
login(IP, User, Password)
while True:
try:
temperatures = get_package_temperatures()
max_temp = max(temperatures.values())
if last_temp is None or abs(max_temp - last_temp) >= 2:
fan_speed = str(compute_fan_speed(max_temp))
set_fan_speed(IP, {"0": fan_speed, "2": str(compute_fan_speed(max_temp)+3), "4": fan_speed, "6": fan_speed})
last_temp = max_temp
print(temperatures, max_temp)
else:
continue
#print(f"温度变化不足2度 ({last_temp}℃ -> {max_temp}℃),跳过风扇转速调整.")
except Exception as e:
print(f"遇到错误: {e}")
# 发生错误时重新登录
login(IP, User, Password)
time.sleep(2)
代码说明
- 风扇转速的策略是,45度以下风扇转速
10%
,超过45度开始线性增加,70度时风扇转速100%
。可以根据需要修改compute_fan_speed
函数的逻辑。 02
号风扇默认比其他风扇转速高3%
,因为这个风扇对应的是CPU1
,为了安装显卡换了散热器,并且阻挡较多温度较高,所以风扇转速设置偏高一点平衡两边温度。如果不需要安装显卡可以修改set_fan_speed(IP, {"0": fan_speed, "2": str(compute_fan_speed(max_temp)+3), "4": fan_speed, "6": fan_speed})
这部分,风扇速度传入的是一个字典,键值对是风扇ID:转速百分比
。- 如果你的服务器是其他有八个风扇的型号(例如SA5112M4),那只需要吧传入的字典部分改成八个对应的键值对即可。
希望这个风扇调节脚本可以帮到你。