fixed resume reset better logging messages Signed-off-by: Giovanni Harting <539@idlegandalf.com>
125 lines
4.0 KiB
Python
125 lines
4.0 KiB
Python
#!/usr/bin/env python
|
|
|
|
import logging
|
|
import sys
|
|
from time import sleep
|
|
|
|
import yaml
|
|
from simple_pid import PID
|
|
|
|
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:
|
|
def __init__(self, temp_source, fans, p, i, d, target, factor, name) -> None:
|
|
self.fans = fans
|
|
self.temp_source = temp_source
|
|
self.pid = PID(p, i, d, setpoint=0)
|
|
self.pid.output_limits = (0, 255)
|
|
self.factor = 1 / factor
|
|
self.name = name
|
|
self.target = target
|
|
self.setup_pwm()
|
|
|
|
logging.getLogger("pyfan").info(
|
|
"[{zone}] Source={source} Fans={fans} Factor={factor} PID={pid}".format(zone=name,
|
|
source=temp_source,
|
|
fans=fans,
|
|
factor=factor,
|
|
pid=(
|
|
p, i, d)))
|
|
|
|
def eval(self):
|
|
diff = self.target - self.get_temp()
|
|
val = self.pid(diff)
|
|
|
|
try:
|
|
for target_fan in self.fans:
|
|
if type(target_fan) is dict:
|
|
write_sysfs(list(target_fan.keys())[0], min(int(val), list(target_fan.values())[0]))
|
|
else:
|
|
write_sysfs(target_fan, int(val))
|
|
except OSError as err:
|
|
logging.getLogger("pyfan").warning("Failed to set pwm, trying to reset it. (%s)" % err.strerror)
|
|
self.setup_pwm(1)
|
|
|
|
p, i, d = self.pid.components
|
|
|
|
logging.getLogger("pyfan").debug(
|
|
"[{name}] {val}% ({diff}C/{temp}C) ({p}|{i}|{d})".format(name=self.name, val=int(val / 255 * 100),
|
|
diff=diff,
|
|
temp=self.get_temp(), p=int(p), i=int(i),
|
|
d=int(d)))
|
|
|
|
def get_temp(self):
|
|
return float(read_sysfs(self.temp_source)) * self.factor
|
|
|
|
def restore(self):
|
|
self.setup_pwm(2)
|
|
|
|
def setup_pwm(self, value=1):
|
|
for target_fan in self.fans:
|
|
if type(target_fan) is dict:
|
|
set_pwm_mode(list(target_fan.keys())[0], value)
|
|
else:
|
|
set_pwm_mode(target_fan, value)
|
|
|
|
|
|
class PyFan:
|
|
def __init__(self, config="/etc/pyfan") -> None:
|
|
self.config = self.__load_config(config)
|
|
logging.basicConfig(level=logging.getLevelName(self.config["loglevel"]))
|
|
self.zones = []
|
|
|
|
for zone in self.config["thermalzones"]:
|
|
self.zones.append(
|
|
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))
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
for zone in self.zones:
|
|
zone.restore()
|
|
|
|
def eval(self):
|
|
for zone in self.zones:
|
|
zone.eval()
|
|
|
|
@staticmethod
|
|
def __load_config(path):
|
|
with open(path) as cfg_file:
|
|
return yaml.safe_load(cfg_file)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
with PyFan() as pyfan:
|
|
while True:
|
|
try:
|
|
pyfan.eval()
|
|
sleep(1)
|
|
except KeyboardInterrupt:
|
|
sys.exit(0)
|