Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
8d95e69048 | |||
772408fc6d | |||
e980293ab6 | |||
6e45b77aba | |||
6074353b95 | |||
3f96734d84 | |||
dd9084ef0d | |||
fe99608da6 | |||
89aa3516e1 | |||
30201163f9 | |||
69bac0b97b | |||
e4bda467bf | |||
f8b1d87a4e | |||
01cd1a1517 |
149
.gitignore
vendored
149
.gitignore
vendored
@@ -1,4 +1,109 @@
|
||||
# ---> Python
|
||||
|
||||
# Created by https://www.gitignore.io/api/linux,python,windows,pycharm+all
|
||||
# Edit at https://www.gitignore.io/?templates=linux,python,windows,pycharm+all
|
||||
|
||||
### Linux ###
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
### PyCharm+all ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### PyCharm+all Patch ###
|
||||
# Ignores the whole .idea folder and all .iml files
|
||||
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
|
||||
|
||||
.idea/
|
||||
|
||||
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||
|
||||
*.iml
|
||||
modules.xml
|
||||
.idea/misc.xml
|
||||
*.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/sonarlint
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
@@ -21,6 +126,8 @@ parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
@@ -57,6 +164,7 @@ coverage.xml
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
@@ -81,6 +189,13 @@ ipython_config.py
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
@@ -114,18 +229,30 @@ dmypy.json
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# ---> Linux
|
||||
*~
|
||||
### Windows ###
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
Thumbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# End of https://www.gitignore.io/api/linux,python,windows,pycharm+all
|
2
.idea/.gitignore
generated
vendored
2
.idea/.gitignore
generated
vendored
@@ -1,2 +0,0 @@
|
||||
# Default ignored files
|
||||
/workspace.xml
|
@@ -1,6 +1,6 @@
|
||||
## PyFAN
|
||||
|
||||
This python script utilizes linux's hwmon interface and a PID controller for fan controlling. No external dependencies besides simple_pid are needed.
|
||||
This python script utilizes linux's hwmon interface and a PID controller for fan controlling. No external dependencies besides simple_pid and PyYAML are needed.
|
||||
|
||||
# Usage
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
loglevel: DEBUG
|
||||
interval: 1
|
||||
|
||||
thermalzones:
|
||||
- name: GPU+SYSTEM
|
||||
hwmon: amdgpu
|
||||
source: amdgpu/temp1_input
|
||||
factor: 1000
|
||||
fan:
|
||||
@@ -14,11 +14,10 @@ thermalzones:
|
||||
i: 1
|
||||
d: 1.5
|
||||
- name: CPU
|
||||
hwmon: it8686
|
||||
source: coretemp/temp1_input
|
||||
factor: 1000
|
||||
fan:
|
||||
- it8686/pwm1
|
||||
- it8686/pwm1: [100, 200]
|
||||
target: 50
|
||||
pid:
|
||||
p: 1
|
||||
|
42
pyfan.py
42
pyfan.py
@@ -20,7 +20,6 @@ class ThermalZone:
|
||||
self.factor = 1 / config["factor"]
|
||||
self.name = config["name"]
|
||||
self.target = config["target"]
|
||||
self.hwname = config["hwmon"]
|
||||
self.hwmap = hwmon_map
|
||||
self.alias_replace = re.compile('|'.join(self.hwmap.keys()))
|
||||
self.setup_pwm()
|
||||
@@ -35,15 +34,30 @@ class ThermalZone:
|
||||
self.pid.Kd)))
|
||||
|
||||
def eval(self):
|
||||
if self.get_temp():
|
||||
diff = self.target - self.get_temp()
|
||||
val = self.pid(diff)
|
||||
val = int(self.pid(diff))
|
||||
|
||||
try:
|
||||
for target_fan in self.fans:
|
||||
if type(target_fan) is dict:
|
||||
self.write_sysfs(list(target_fan.keys())[0], min(int(val), list(target_fan.values())[0]))
|
||||
fan = list(target_fan.keys())[0]
|
||||
fan_val = list(target_fan.values())[0]
|
||||
|
||||
if type(fan_val) is list:
|
||||
if len(fan_val) < 2:
|
||||
logging.getLogger("pyfan").warning(
|
||||
"[%s] max/min for %s was not set correctly (%s)" % (self.name, fan, fan_val))
|
||||
|
||||
self.write_sysfs(fan, min(fan_val[1], max(val, fan_val[0])))
|
||||
else:
|
||||
self.write_sysfs(target_fan, int(val))
|
||||
self.write_sysfs(fan, min(val, fan_val))
|
||||
|
||||
logging.getLogger("pyfan").debug(
|
||||
"[{name}] {fan} is set at {val}%".format(name=self.name, fan=fan,
|
||||
val=int(int(self.read_sysfs(fan)) / 255 * 100)))
|
||||
else:
|
||||
self.write_sysfs(target_fan, val)
|
||||
except OSError as err:
|
||||
logging.getLogger("pyfan").warning(
|
||||
"[%s] Failed to set pwm, trying to reset it. (%s)" % (self.name, err.strerror))
|
||||
@@ -58,7 +72,10 @@ class ThermalZone:
|
||||
d=int(d)))
|
||||
|
||||
def get_temp(self):
|
||||
if self.read_sysfs(self.temp_source):
|
||||
return float(self.read_sysfs(self.temp_source)) * self.factor
|
||||
else:
|
||||
return None
|
||||
|
||||
def restore(self):
|
||||
self.setup_pwm(2)
|
||||
@@ -71,8 +88,8 @@ class ThermalZone:
|
||||
else:
|
||||
self.set_pwm_mode(target_fan, value)
|
||||
except FileNotFoundError as err:
|
||||
logging.getLogger("pyfan").warning("[%s] pwm not found. Not ready yet or wrong path? (%s)" % (self.name,
|
||||
err.strerror))
|
||||
logging.getLogger("pyfan").warning("[%s] pwm not found."
|
||||
" Not ready yet or wrong path? (%s)" % (self.name, err.strerror))
|
||||
|
||||
def replace_alias(self, path):
|
||||
replaced = self.alias_replace.sub(lambda x: self.hwmap[x.group()], path)
|
||||
@@ -87,8 +104,14 @@ class ThermalZone:
|
||||
sysfs_f.write(str(value))
|
||||
|
||||
def read_sysfs(self, path):
|
||||
try:
|
||||
with open(self.build_pwm_path(path)) as sysfs_f:
|
||||
return sysfs_f.readline()
|
||||
except FileNotFoundError as err:
|
||||
logging.getLogger("pyfan").warning(
|
||||
"[%s] temp source not found. Not ready yet or wrong path? (%s)" % (self.name,
|
||||
err.strerror))
|
||||
return None
|
||||
|
||||
def set_pwm_mode(self, path, value=1):
|
||||
self.write_sysfs(path + "_enable", value)
|
||||
@@ -102,6 +125,11 @@ class PyFan:
|
||||
self.hwmon_map = {}
|
||||
self.gen_hwmon_map()
|
||||
|
||||
if "interval" in self.config:
|
||||
self.interval = self.config["interval"]
|
||||
else:
|
||||
self.interval = 1
|
||||
|
||||
for zone in self.config["thermalzones"]:
|
||||
self.zones.append(ThermalZone(zone, self.hwmon_map))
|
||||
|
||||
@@ -138,6 +166,6 @@ if __name__ == "__main__":
|
||||
while True:
|
||||
try:
|
||||
pyfan.eval()
|
||||
sleep(1)
|
||||
sleep(pyfan.interval)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=Start PyFan fan control
|
||||
Description=PID based fan control
|
||||
ConditionFileNotEmpty=/etc/pyfan
|
||||
After=lm_sensors.service
|
||||
|
||||
|
Reference in New Issue
Block a user