Updating many thermal and status things

This commit is contained in:
Dan Buch 2023-12-31 16:44:44 -05:00
parent a500a63a53
commit dc30944a89
Signed by: meatballhat
GPG Key ID: A12F782281063434
4 changed files with 157 additions and 76 deletions

1
.python-version Normal file
View File

@ -0,0 +1 @@
3.12.0

View File

@ -1,16 +1,18 @@
#!/usr/bin/env python #!/usr/bin/env python
import json import json
import os import shutil
import subprocess
import sys import sys
import typing
__all__ = ["_mem", "_backlight", "_hwtemp"] __all__ = ["_mem", "_backlight", "_hwtemp"]
_BITS = [] _BITS: list[tuple[int, str, typing.Callable]] = []
def _bit(idx): def _bit(idx):
def wrapper(func): def wrapper(func):
_BITS.append([idx, func.__name__.replace("_", ""), func]) _BITS.append((idx, func.__name__.replace("_", ""), func))
return func return func
return wrapper return wrapper
@ -49,29 +51,39 @@ def _backlight(dev_dir="/sys/class/backlight/intel_backlight"):
return "☼:{}%".format(pct), color return "☼:{}%".format(pct), color
THINKFAN_CONF = "/etc/thinkfan.conf"
ACPI_IBM_FAN = "/proc/acpi/ibm/fan" ACPI_IBM_FAN = "/proc/acpi/ibm/fan"
@_bit(7) @_bit(7)
def _hwtemp(conf=THINKFAN_CONF, fan=ACPI_IBM_FAN): def _hwtemp(fan=ACPI_IBM_FAN):
if not os.path.exists(conf): acpi_exe = shutil.which("acpi")
if acpi_exe is None:
return None, None return None, None
temps = [] raw_temp = subprocess.run(
[acpi_exe, "-t"],
text=True,
capture_output=True,
check=False,
)
if raw_temp.returncode != 0 or raw_temp.stdout is None:
return None, None
with open("/etc/thinkfan.conf") as tfc_fp: temps_by_zone = {}
for line in tfc_fp.readlines(): for line in raw_temp.stdout.splitlines():
if not line.startswith("hwmon "): zone_id, value = line.split(":")
continue human_temp = value.split(",")[-1]
try: temps_by_zone[zone_id.lower().lstrip("thermal ")] = float(
with open(line.split(" ")[1].strip()) as temp_fp: human_temp.lower().strip().rstrip("degrees c")
temps.append(float(temp_fp.read())) )
except (OSError, IOError) as exc:
sys.stderr.write(str(exc) + "\n")
avg_temp = float(sum(temps)) / len(temps) / 1000.0 temps = list(temps_by_zone.values())
color = None avg_temp = float(sum(temps)) / len(temps)
color = "#5599ff"
if avg_temp > 75:
color = "#ff0000"
if avg_temp >= 50:
color = "#ffaa00"
fan_level = "unset" fan_level = "unset"
try: try:
@ -83,12 +95,6 @@ def _hwtemp(conf=THINKFAN_CONF, fan=ACPI_IBM_FAN):
except (OSError, IOError) as exc: except (OSError, IOError) as exc:
sys.stderr.write(str(exc) + "\n") sys.stderr.write(str(exc) + "\n")
if avg_temp > 75:
color = "#ff0000"
if avg_temp >= 50:
color = "#ffaa00"
if avg_temp <= 25:
color = "#5599ff"
return "T:{:.1f}°C L:{}".format(avg_temp, fan_level), color return "T:{:.1f}°C L:{}".format(avg_temp, fan_level), color

View File

@ -1,52 +0,0 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
main() {
if [[ -f "${1}" ]]; then
exec 1>"${1}"
shift
fi
if [[ -f /etc/default/thinkfan-confgen ]]; then
source /etc/default/thinkfan-confgen
fi
: "${THINKFAN_LOWER_BOUND:=30}"
: "${THINKFAN_STEP:=4}"
printf '# thinkfan-confgen created %s\n' "$(date -u)"
printf '# THINKFAN_LOWER_BOUND=%s\n' "${THINKFAN_LOWER_BOUND}"
printf '# THINKFAN_STEP=%s\n\n' "${THINKFAN_STEP}"
find /sys -type f -name 'temp*_input' | while read -r line; do
if [[ "${line}" =~ thinkpad_hwmon ]]; then
continue
fi
printf 'hwmon %s\n' "${line}"
done
printf '\ntp_fan /proc/acpi/ibm/fan\n\n'
local halfstep="$((THINKFAN_STEP / 2))"
local cur="${THINKFAN_LOWER_BOUND}"
for level in 0 1 2 3 4 5 6 7; do
if [[ "${level}" == 0 ]]; then
printf '(0, 0, %s)\n' "${cur}"
continue
fi
if [[ "${level}" == 7 ]]; then
printf '(7, %s, 32767)\n' "$((cur - halfstep))"
continue
fi
printf '(%s, %s, %s)\n' \
"${level}" "$((cur - halfstep))" "$((cur + THINKFAN_STEP))"
cur="$((cur + THINKFAN_STEP))"
done
}
main "${@}"

126
local/bin/thinkfan_confgen.py Executable file
View File

@ -0,0 +1,126 @@
#!/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())