added hwmon alias map
linux kernel does not guarantee order of hwmon devices, so use alias instead that gets replaced with teh correct hwmonX, based on hwmonX/name
This commit is contained in:
2
.idea/.gitignore
generated
vendored
Normal file
2
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/workspace.xml
|
@@ -1,26 +1,26 @@
|
|||||||
loglevel: DEBUG
|
loglevel: DEBUG
|
||||||
|
|
||||||
thermalzones:
|
thermalzones:
|
||||||
-
|
- name: GPU+SYSTEM
|
||||||
name: GPU+SYSTEM
|
hwmon: amdgpu
|
||||||
source: hwmon3/temp1_input
|
source: temp1_input
|
||||||
factor: 1000
|
factor: 1000
|
||||||
fan:
|
fan:
|
||||||
- hwmon2/pwm2
|
- it8686/pwm2
|
||||||
- hwmon3/pwm1: 170
|
- amdgpu/pwm1: 170
|
||||||
target: 60
|
target: 60
|
||||||
pid:
|
pid:
|
||||||
p: 1
|
p: 1
|
||||||
i: 1.5
|
i: 1
|
||||||
d: 2
|
d: 1.5
|
||||||
-
|
- name: CPU
|
||||||
name: CPU
|
hwmon: it8686
|
||||||
source: hwmon1/temp1_input
|
source: coretemp/temp1_input
|
||||||
factor: 1000
|
factor: 1000
|
||||||
fan:
|
fan:
|
||||||
- hwmon2/pwm1
|
- it8686/pwm1
|
||||||
target: 50
|
target: 50
|
||||||
pid:
|
pid:
|
||||||
p: 1
|
p: 1
|
||||||
i: 1.5
|
i: 1
|
||||||
d: 2
|
d: 1.5
|
98
pyfan.py
98
pyfan.py
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
import glob
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
@@ -10,42 +11,28 @@ from simple_pid import PID
|
|||||||
SYSFS_HWMON_BASE = "/sys/class/hwmon/"
|
SYSFS_HWMON_BASE = "/sys/class/hwmon/"
|
||||||
|
|
||||||
|
|
||||||
def build_pwm_path(specific):
|
|
||||||
return SYSFS_HWMON_BASE + specific
|
|
||||||
|
|
||||||
|
|
||||||
def write_sysfs(path, value):
|
|
||||||
with open(build_pwm_path(path), 'w') as sysfs_f:
|
|
||||||
sysfs_f.write(str(value))
|
|
||||||
|
|
||||||
|
|
||||||
def read_sysfs(path):
|
|
||||||
with open(build_pwm_path(path)) as sysfs_f:
|
|
||||||
return sysfs_f.readline()
|
|
||||||
|
|
||||||
|
|
||||||
def set_pwm_mode(path, value=1):
|
|
||||||
write_sysfs(path + "_enable", value)
|
|
||||||
|
|
||||||
|
|
||||||
class ThermalZone:
|
class ThermalZone:
|
||||||
def __init__(self, temp_source, fans, p, i, d, target, factor, name) -> None:
|
def __init__(self, config, hwmon_map) -> None:
|
||||||
self.fans = fans
|
self.fans = config["fan"]
|
||||||
self.temp_source = temp_source
|
self.temp_source = config["source"]
|
||||||
self.pid = PID(p, i, d, setpoint=0)
|
self.pid = PID(config["pid"]["p"], config["pid"]["i"], config["pid"]["d"], setpoint=0)
|
||||||
self.pid.output_limits = (0, 255)
|
self.pid.output_limits = (0, 255)
|
||||||
self.factor = 1 / factor
|
self.factor = 1 / config["factor"]
|
||||||
self.name = name
|
self.name = config["name"]
|
||||||
self.target = target
|
self.target = config["target"]
|
||||||
|
self.hwname = config["hwmon"]
|
||||||
|
self.hwmap = hwmon_map
|
||||||
|
self.alias_replace = re.compile(r'\b(' + '|'.join(re.escape(key) for key in self.hwmap.keys()) + r')\b')
|
||||||
self.setup_pwm()
|
self.setup_pwm()
|
||||||
|
|
||||||
logging.getLogger("pyfan").info(
|
logging.getLogger("pyfan").info(
|
||||||
"[{zone}] Source={source} Fans={fans} Factor={factor} PID={pid}".format(zone=name,
|
"[{zone}] Source={source} Fans={fans} Factor={factor} PID={pid}".format(zone=self.name,
|
||||||
source=temp_source,
|
source=self.temp_source,
|
||||||
fans=fans,
|
fans=self.fans,
|
||||||
factor=factor,
|
factor=self.factor,
|
||||||
pid=(
|
pid=(
|
||||||
p, i, d)))
|
self.pid.Kp, self.pid.Ki,
|
||||||
|
self.pid.Kd)))
|
||||||
|
|
||||||
def eval(self):
|
def eval(self):
|
||||||
diff = self.target - self.get_temp()
|
diff = self.target - self.get_temp()
|
||||||
@@ -54,9 +41,9 @@ class ThermalZone:
|
|||||||
try:
|
try:
|
||||||
for target_fan in self.fans:
|
for target_fan in self.fans:
|
||||||
if type(target_fan) is dict:
|
if type(target_fan) is dict:
|
||||||
write_sysfs(list(target_fan.keys())[0], min(int(val), list(target_fan.values())[0]))
|
self.write_sysfs(list(target_fan.keys())[0], min(int(val), list(target_fan.values())[0]))
|
||||||
else:
|
else:
|
||||||
write_sysfs(target_fan, int(val))
|
self.write_sysfs(target_fan, int(val))
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
logging.getLogger("pyfan").warning(
|
logging.getLogger("pyfan").warning(
|
||||||
"[%s] Failed to set pwm, trying to reset it. (%s)" % (self.name, err.strerror))
|
"[%s] Failed to set pwm, trying to reset it. (%s)" % (self.name, err.strerror))
|
||||||
@@ -71,7 +58,7 @@ class ThermalZone:
|
|||||||
d=int(d)))
|
d=int(d)))
|
||||||
|
|
||||||
def get_temp(self):
|
def get_temp(self):
|
||||||
return float(read_sysfs(self.temp_source)) * self.factor
|
return float(self.read_sysfs(self.temp_source)) * self.factor
|
||||||
|
|
||||||
def restore(self):
|
def restore(self):
|
||||||
self.setup_pwm(2)
|
self.setup_pwm(2)
|
||||||
@@ -80,12 +67,31 @@ class ThermalZone:
|
|||||||
for target_fan in self.fans:
|
for target_fan in self.fans:
|
||||||
try:
|
try:
|
||||||
if type(target_fan) is dict:
|
if type(target_fan) is dict:
|
||||||
set_pwm_mode(list(target_fan.keys())[0], value)
|
self.set_pwm_mode(list(target_fan.keys())[0], value)
|
||||||
else:
|
else:
|
||||||
set_pwm_mode(target_fan, value)
|
self.set_pwm_mode(target_fan, value)
|
||||||
except FileNotFoundError as err:
|
except FileNotFoundError as err:
|
||||||
logging.getLogger("pyfan").warning("[%s] pwm not found. Not ready yet or wrong path? (%s)" % self.name,
|
logging.getLogger("pyfan").warning("[%s] pwm not found. Not ready yet or wrong path? (%s)" % (self.name,
|
||||||
err.strerror)
|
err.strerror))
|
||||||
|
|
||||||
|
def replace_alias(self, path):
|
||||||
|
replaced = self.alias_replace.sub(lambda x: self.hwmap[x.group()], path)
|
||||||
|
logging.getLogger("pyfan").debug("[ALIAS] %s -> %s" % (path, replaced))
|
||||||
|
return replaced
|
||||||
|
|
||||||
|
def build_pwm_path(self, specific):
|
||||||
|
return self.replace_alias(SYSFS_HWMON_BASE + specific)
|
||||||
|
|
||||||
|
def write_sysfs(self, path, value):
|
||||||
|
with open(self.build_pwm_path(path), 'w') as sysfs_f:
|
||||||
|
sysfs_f.write(str(value))
|
||||||
|
|
||||||
|
def read_sysfs(self, path):
|
||||||
|
with open(self.build_pwm_path(path)) as sysfs_f:
|
||||||
|
return sysfs_f.readline()
|
||||||
|
|
||||||
|
def set_pwm_mode(self, path, value=1):
|
||||||
|
self.write_sysfs(path + "_enable", value)
|
||||||
|
|
||||||
|
|
||||||
class PyFan:
|
class PyFan:
|
||||||
@@ -93,12 +99,11 @@ class PyFan:
|
|||||||
self.config = self.__load_config(config)
|
self.config = self.__load_config(config)
|
||||||
logging.basicConfig(level=logging.getLevelName(self.config["loglevel"]))
|
logging.basicConfig(level=logging.getLevelName(self.config["loglevel"]))
|
||||||
self.zones = []
|
self.zones = []
|
||||||
|
self.hwmon_map = {}
|
||||||
|
self.gen_hwmon_map()
|
||||||
|
|
||||||
for zone in self.config["thermalzones"]:
|
for zone in self.config["thermalzones"]:
|
||||||
self.zones.append(
|
self.zones.append(ThermalZone(zone, self.hwmon_map))
|
||||||
ThermalZone(zone["source"], zone["fan"], zone["pid"]["p"], zone["pid"]["i"], zone["pid"]["d"],
|
|
||||||
zone["target"],
|
|
||||||
zone["factor"], zone["name"]))
|
|
||||||
|
|
||||||
logging.getLogger("pyfan").info("Finished creating %d thermal zones." % len(self.zones))
|
logging.getLogger("pyfan").info("Finished creating %d thermal zones." % len(self.zones))
|
||||||
|
|
||||||
@@ -118,6 +123,15 @@ class PyFan:
|
|||||||
with open(path) as cfg_file:
|
with open(path) as cfg_file:
|
||||||
return yaml.safe_load(cfg_file)
|
return yaml.safe_load(cfg_file)
|
||||||
|
|
||||||
|
def gen_hwmon_map(self):
|
||||||
|
names = glob.glob(SYSFS_HWMON_BASE + "hwmon*/name")
|
||||||
|
|
||||||
|
for name in names:
|
||||||
|
hwmon = name.split("/")[-2]
|
||||||
|
with open(name) as file:
|
||||||
|
hwname = file.read()
|
||||||
|
self.hwmon_map[hwname] = hwmon
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
with PyFan() as pyfan:
|
with PyFan() as pyfan:
|
||||||
|
Reference in New Issue
Block a user