You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
3.2 KiB
127 lines
3.2 KiB
10 months ago
|
#!/usr/bin/env python
|
||
|
import argparse
|
||
|
import datetime
|
||
|
import json
|
||
|
import os
|
||
|
import pathlib
|
||
|
import sys
|
||
|
import typing
|
||
|
|
||
|
|
||
|
class ThinkfanConfig(typing.TypedDict):
|
||
|
sensors: list[dict[str, str]]
|
||
|
fans: list[dict[str, str]]
|
||
|
levels: list[dict[str, int | list[int]]]
|
||
|
|
||
|
|
||
|
def main(sysargs=sys.argv[:]) -> int:
|
||
|
parser = argparse.ArgumentParser()
|
||
|
parser.add_argument(
|
||
|
"-l",
|
||
|
"--lower-bound",
|
||
|
default=int(os.environ.get("THINKFAN_LOWER_BOUND", "30")),
|
||
|
type=int,
|
||
|
help="lower bound of sensor value for min fan speed (THINKFAN_LOWER_BOUND)",
|
||
|
)
|
||
|
parser.add_argument(
|
||
|
"-u",
|
||
|
"--upper-bound",
|
||
|
default=int(os.environ.get("THINKFAN_UPPER_BOUND", "32767")),
|
||
|
type=int,
|
||
|
help="upper bound of sensor value for max fan speed (THINKFAN_UPPER_BOUND)",
|
||
|
)
|
||
|
parser.add_argument(
|
||
|
"-s",
|
||
|
"--step",
|
||
|
default=int(os.environ.get("THINKFAN_STEP", "4")),
|
||
|
type=int,
|
||
|
help="step size between fan speed levels (THINKFAN_STEP)",
|
||
|
)
|
||
|
args = parser.parse_args(sysargs[1:])
|
||
|
|
||
|
cfg: ThinkfanConfig = {
|
||
|
"sensors": [],
|
||
|
"fans": [],
|
||
|
"levels": [],
|
||
|
}
|
||
|
|
||
|
acpi_fan = pathlib.Path("/proc/acpi/ibm/fan")
|
||
|
if acpi_fan.exists():
|
||
|
cfg["fans"].append({"tpacpi": str(acpi_fan)})
|
||
|
|
||
|
acpi_thermal = pathlib.Path("/proc/acpi/ibm/thermal")
|
||
|
|
||
|
n_sensors: int = 0
|
||
|
|
||
|
if acpi_thermal.exists():
|
||
|
cfg["sensors"].append({"tpacpi": str(acpi_thermal)})
|
||
|
n_sensors = len(
|
||
|
[
|
||
|
l
|
||
|
for l in acpi_thermal.read_text().splitlines()
|
||
|
if l.startswith("temperatures:")
|
||
|
][0]
|
||
|
.split(":")[1]
|
||
|
.strip()
|
||
|
.split()
|
||
|
)
|
||
|
|
||
|
else:
|
||
|
for dirpath, dirnames, filenames in pathlib.Path("/sys/devices").walk(
|
||
|
on_error=print, follow_symlinks=False
|
||
|
):
|
||
|
if "thinkpad_hwmon" in dirnames:
|
||
|
dirnames.remove("thinkpad_hwmon")
|
||
|
|
||
|
for filename in filenames:
|
||
|
if filename.startswith("temp") and filename.endswith("_input"):
|
||
|
cfg["sensors"].append({"hwmon": str(dirpath.joinpath(filename))})
|
||
|
|
||
|
n_sensors += 1
|
||
|
|
||
|
cur: int = args.lower_bound
|
||
|
step: int = args.step
|
||
|
halfstep = step // 2
|
||
|
|
||
|
for level in range(8):
|
||
|
if level == 0:
|
||
|
cfg["levels"].append(
|
||
|
{
|
||
|
"speed": 0,
|
||
|
"lower_limit": [0] * n_sensors,
|
||
|
"upper_limit": [cur] * n_sensors,
|
||
|
}
|
||
|
)
|
||
|
|
||
|
continue
|
||
|
|
||
|
if level == 7:
|
||
|
cfg["levels"].append(
|
||
|
{
|
||
|
"speed": 7,
|
||
|
"upper_limit": [args.upper_bound] * n_sensors,
|
||
|
"lower_limit": [cur - halfstep] * n_sensors,
|
||
|
}
|
||
|
)
|
||
|
|
||
|
continue
|
||
|
|
||
|
cfg["levels"].append(
|
||
|
{
|
||
|
"speed": level,
|
||
|
"lower_limit": [cur - halfstep] * n_sensors,
|
||
|
"upper_limit": [cur + step] * n_sensors,
|
||
|
},
|
||
|
)
|
||
|
|
||
|
cur += step
|
||
|
|
||
|
print(f"# thinkfan_confgen.py created {datetime.datetime.now(datetime.UTC)}")
|
||
|
print(json.dumps(cfg))
|
||
|
|
||
|
return 0
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
sys.exit(main())
|