13 Commits
1.0 ... master

5 changed files with 82 additions and 31 deletions

View File

@ -3,7 +3,7 @@
This is a script to control 4-pin PWM fans on ASRock Rack motherboards with IPMI. The BMC does not properly expose fan control, so they must be controlled using raw IPMI commands. This script is a user-friendly way to do that. This is a script to control 4-pin PWM fans on ASRock Rack motherboards with IPMI. The BMC does not properly expose fan control, so they must be controlled using raw IPMI commands. This script is a user-friendly way to do that.
usage: asrock-pwm-ipmi [-h] [-i] [FAN:SPEED [FAN:SPEED ...]] usage: asrock-pwm-ipmi [-h] [-i] [-a] [-q] [FAN:SPEED [FAN:SPEED ...]]
Read information about and control fans on ASRock boards with IPMI. Read information about and control fans on ASRock boards with IPMI.
@ -12,5 +12,8 @@ This is a script to control 4-pin PWM fans on ASRock Rack motherboards with IPMI
to 0 for auto. to 0 for auto.
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
-i, --info Read fan information -i, --info Read fan information
-a, --auto Service to control fans based on temperature
-q, --quiet Hide output

Binary file not shown.

10
autofan.service Normal file
View File

@ -0,0 +1,10 @@
[Unit]
Description=ASRock IPMI automatic fan control
[Service]
WorkingDirectory=/root/asrock-pwm-ipmi/
ExecStart=/root/asrock-pwm-ipmi/asrock-pwm-ipmi -aq
Restart=always
[Install]
WantedBy=multi-user.target

84
pwm.py
View File

@ -1,37 +1,67 @@
#!/usr/bin/python3 #!/usr/bin/python3
import run_cmd import run_cmd
import argparse import argparse
import time
# Variables to determine bounds
MAXFAN = 6 MAXFAN = 6
MINSPEED = 35
MAXSPEED = 100
MINTEMP = 30
MAXTEMP = 65
parser = argparse.ArgumentParser(description='Read information about and control fans on ASRock boards with IPMI.', prog='asrock-pwm-ipmi') parser = argparse.ArgumentParser(description='Read information about and control fans on ASRock boards with IPMI.', prog='asrock-pwm-ipmi')
parser.add_argument('fanplusspeed', nargs='*', metavar='FAN:SPEED', parser.add_argument('fanplusspeed', nargs='*', metavar='FAN:SPEED', help='Fan to change the speed of, and the speed, separated by \':\'. Set to 0 for auto.')
help='Fan to change the speed of, and the speed, separated by \':\'. Set to 0 for auto.') parser.add_argument('-i', '--info', action="store_true", default=False, help='Read fan information')
#parser.add_argument('SPEED', type=int, nargs='+', parser.add_argument('-a', '--auto', action="store_true", default=False, help='Service to control fans based on temperature')
# help='Speed to set FAN to') parser.add_argument('-q', '--quiet', action="store_true", default=False, help='Hide output')
parser.add_argument('-i', '--info', action="store_true", default=False,
help='Read fan information')
args = parser.parse_args() args = parser.parse_args()
#print(args.info)
#print(args) #print(args)
#print(args.fanplusspeed)
if args.info is False and args.fanplusspeed == []: fanChanged = False
print("Nothing to do! See --help for usage.")
quit def iterateFans(info):
if args.fanplusspeed != []: for fanopt in info:
for fanopt in args.fanplusspeed: if str(fanopt.split(":"))[2:-2] == fanopt or int(fanopt.split(":")[0]) < 1 or int(fanopt.split(":")[0]) > MAXFAN:
if str(fanopt.split(":"))[2:-2] == fanopt or int(fanopt.split(":")[0]) < 1 or int(fanopt.split(":")[0]) > MAXFAN: print("Improper format!")
print("Improper format!") continue
continue fan, speed = fanopt.split(":")
fan, speed = fanopt.split(":") run_cmd.setSpeed(int(fan), int(speed))
run_cmd.setSpeed(int(fan), int(speed)) fanChanged = True
if int(speed) == 0: if args.quiet is False:
print("Set speed of FAN" + fan + " to Auto.") if int(speed) == 0:
else: print("Set speed of FAN" + fan + " to Auto.")
print("Set speed of FAN" + fan + " to " + speed + "%.") else:
print("Set speed of FAN" + fan + " to " + speed + "%.")
while args.auto is True:
temp = run_cmd.getTemp()
speeds = []
if temp < MINTEMP:
for i in range(2, 7):
speeds.append(str(i) + ":1")
elif temp > MAXTEMP:
for i in range(2, 7):
speeds.append(str(i) + ":100")
else:
base = temp - MINTEMP
max = MAXTEMP - MINTEMP
scaled = base / max
speed = int(scaled * (MAXSPEED - MINSPEED) + MINSPEED)
for i in range(2, 7):
speeds.append(str(i) + ":" + str(speed))
iterateFans(speeds)
if args.info is False and len(args.fanplusspeed) == 0:
print("Nothing to do! See --help for usage.")
quit
if len(args.fanplusspeed) != 0:
iterateFans(args.fanplusspeed)
if args.info is True: if args.info is True:
print("\nRetrieving fan speeds...\n") if fanChanged is True:
for line in run_cmd.getFanInfo(): print("\nWaiting for fans to adjust...")
print(line) time.sleep(5)
print("\nRetrieving fan speeds...\n")
for line in run_cmd.getFanInfo():
print(line)

View File

@ -1,5 +1,6 @@
#!/usr/bin/python3 #!/usr/bin/python3
import subprocess as sp import subprocess as sp
import json
def setSpeed(fan, setspeed): def setSpeed(fan, setspeed):
speeds, speedsRaw = getAllSpeeds() speeds, speedsRaw = getAllSpeeds()
@ -32,7 +33,7 @@ def getFanInfo():
sensorinfo, err = cmdoutput.communicate() sensorinfo, err = cmdoutput.communicate()
#print(sensorinfo.splitlines()) #print(sensorinfo.splitlines())
faninfo = [] faninfo = []
speeds, speedsRaw= getAllSpeeds() speeds, speedsRaw = getAllSpeeds()
for line in sensorinfo.splitlines(): for line in sensorinfo.splitlines():
if "FAN" in str(line): if "FAN" in str(line):
faninfo.append(str(line)) faninfo.append(str(line))
@ -46,3 +47,10 @@ def getFanInfo():
faninfo[index] += "%" faninfo[index] += "%"
#print(faninfo[index]) #print(faninfo[index])
return faninfo return faninfo
def getTemp():
cmdoutput = sp.Popen(["sensors", "-Aj", "zenpower-*"], stdout=sp.PIPE)
sensorjson, err = cmdoutput.communicate()
sensordata = json.loads(sensorjson)
temp = sensordata["zenpower-pci-00c3"]["Tdie"]["temp1_input"]
return temp