Merge pull request #111624 from rnhmjoj/thinkfan
nixos/thinkfan: rewrite for 1.2 update
This commit is contained in:
commit
c9f6a7f349
|
@ -466,6 +466,19 @@ self: super:
|
||||||
ALSA OSS emulation (<varname>sound.enableOSSEmulation</varname>) is now disabled by default.
|
ALSA OSS emulation (<varname>sound.enableOSSEmulation</varname>) is now disabled by default.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Thinkfan as been updated to <literal>1.2.x</literal>, which comes with a
|
||||||
|
new YAML based configuration format. For this reason, several NixOS options
|
||||||
|
of the thinkfan module have been changed to non-backward compatible types.
|
||||||
|
In addition, a new <xref linkend="opt-services.thinkfan.settings"/> option has
|
||||||
|
been added.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Please read the <link xlink:href="https://github.com/vmatare/thinkfan#readme">
|
||||||
|
thinkfan documentation</link> before updating.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -5,49 +5,95 @@ with lib;
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.services.thinkfan;
|
cfg = config.services.thinkfan;
|
||||||
configFile = pkgs.writeText "thinkfan.conf" ''
|
settingsFormat = pkgs.formats.yaml { };
|
||||||
# ATTENTION: There is only very basic sanity checking on the configuration.
|
configFile = settingsFormat.generate "thinkfan.yaml" cfg.settings;
|
||||||
# That means you can set your temperature limits as insane as you like. You
|
thinkfan = pkgs.thinkfan.override { inherit (cfg) smartSupport; };
|
||||||
# can do anything stupid, e.g. turn off your fan when your CPU reaches 70°C.
|
|
||||||
#
|
|
||||||
# That's why this program is called THINKfan: You gotta think for yourself.
|
|
||||||
#
|
|
||||||
######################################################################
|
|
||||||
#
|
|
||||||
# IBM/Lenovo Thinkpads (thinkpad_acpi, /proc/acpi/ibm)
|
|
||||||
# ====================================================
|
|
||||||
#
|
|
||||||
# IMPORTANT:
|
|
||||||
#
|
|
||||||
# To keep your HD from overheating, you have to specify a correction value for
|
|
||||||
# the sensor that has the HD's temperature. You need to do this because
|
|
||||||
# thinkfan uses only the highest temperature it can find in the system, and
|
|
||||||
# that'll most likely never be your HD, as most HDs are already out of spec
|
|
||||||
# when they reach 55 °C.
|
|
||||||
# Correction values are applied from left to right in the same order as the
|
|
||||||
# temperatures are read from the file.
|
|
||||||
#
|
|
||||||
# For example:
|
|
||||||
# tp_thermal /proc/acpi/ibm/thermal (0, 0, 10)
|
|
||||||
# will add a fixed value of 10 °C the 3rd value read from that file. Check out
|
|
||||||
# http://www.thinkwiki.org/wiki/Thermal_Sensors to find out how much you may
|
|
||||||
# want to add to certain temperatures.
|
|
||||||
|
|
||||||
${cfg.fan}
|
# fan-speed and temperature levels
|
||||||
${cfg.sensors}
|
levelType = with types;
|
||||||
|
let
|
||||||
|
tuple = ts: mkOptionType {
|
||||||
|
name = "tuple";
|
||||||
|
merge = mergeOneOption;
|
||||||
|
check = xs: all id (zipListsWith (t: x: t.check x) ts xs);
|
||||||
|
description = "tuple of" + concatMapStrings (t: " (${t.description})") ts;
|
||||||
|
};
|
||||||
|
level = ints.unsigned;
|
||||||
|
special = enum [ "level auto" "level full-speed" "level disengage" ];
|
||||||
|
in
|
||||||
|
tuple [ (either level special) level level ];
|
||||||
|
|
||||||
# Syntax:
|
# sensor or fan config
|
||||||
# (LEVEL, LOW, HIGH)
|
sensorType = name: types.submodule {
|
||||||
# LEVEL is the fan level to use (0-7 with thinkpad_acpi)
|
freeformType = types.attrsOf settingsFormat.type;
|
||||||
# LOW is the temperature at which to step down to the previous level
|
options = {
|
||||||
# HIGH is the temperature at which to step up to the next level
|
type = mkOption {
|
||||||
# All numbers are integers.
|
type = types.enum [ "hwmon" "atasmart" "tpacpi" "nvml" ];
|
||||||
#
|
description = ''
|
||||||
|
The ${name} type, can be
|
||||||
|
<literal>hwmon</literal> for standard ${name}s,
|
||||||
|
|
||||||
${cfg.levels}
|
<literal>atasmart</literal> to read the temperature via
|
||||||
|
S.M.A.R.T (requires smartSupport to be enabled),
|
||||||
|
|
||||||
|
<literal>tpacpi</literal> for the legacy thinkpac_acpi driver, or
|
||||||
|
|
||||||
|
<literal>nvml</literal> for the (proprietary) nVidia driver.
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
|
query = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
The query string used to match one or more ${name}s: can be
|
||||||
|
a fullpath to the temperature file (single ${name}) or a fullpath
|
||||||
|
to a driver directory (multiple ${name}s).
|
||||||
|
|
||||||
thinkfan = pkgs.thinkfan.override { smartSupport = cfg.smartSupport; };
|
<note><para>
|
||||||
|
When multiple ${name}s match, the query can be restricted using the
|
||||||
|
<option>name</option> or <option>indices</option> options.
|
||||||
|
</para></note>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
indices = mkOption {
|
||||||
|
type = with types; nullOr (listOf ints.unsigned);
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
A list of ${name}s to pick in case multiple ${name}s match the query.
|
||||||
|
|
||||||
|
<note><para>Indices start from 0.</para></note>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
} // optionalAttrs (name == "sensor") {
|
||||||
|
correction = mkOption {
|
||||||
|
type = with types; nullOr (listOf int);
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
A list of values to be added to the temperature of each sensor,
|
||||||
|
can be used to equalize small discrepancies in temperature ratings.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# removes NixOS special and unused attributes
|
||||||
|
sensorToConf = { type, query, ... }@args:
|
||||||
|
(filterAttrs (k: v: v != null && !(elem k ["type" "query"])) args)
|
||||||
|
// { "${type}" = query; };
|
||||||
|
|
||||||
|
syntaxNote = name: ''
|
||||||
|
<note><para>
|
||||||
|
This section slightly departs from the thinkfan.conf syntax.
|
||||||
|
The type and path must be specified like this:
|
||||||
|
<literal>
|
||||||
|
type = "tpacpi";
|
||||||
|
query = "/proc/acpi/ibm/${name}";
|
||||||
|
</literal>
|
||||||
|
instead of a single declaration like:
|
||||||
|
<literal>
|
||||||
|
- tpacpi: /proc/acpi/ibm/${name}
|
||||||
|
</literal>
|
||||||
|
</para></note>
|
||||||
|
'';
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
|
@ -59,76 +105,93 @@ in {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Whether to enable thinkfan, fan controller for IBM/Lenovo ThinkPads.
|
Whether to enable thinkfan, a fan control program.
|
||||||
|
|
||||||
|
<note><para>
|
||||||
|
This module targets IBM/Lenovo thinkpads by default, for
|
||||||
|
other hardware you will have configure it more carefully.
|
||||||
|
</para></note>
|
||||||
'';
|
'';
|
||||||
|
relatedPackages = [ "thinkfan" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
smartSupport = mkOption {
|
smartSupport = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Whether to build thinkfan with SMART support to read temperatures
|
Whether to build thinkfan with S.M.A.R.T. support to read temperatures
|
||||||
directly from hard disks.
|
directly from hard disks.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
sensors = mkOption {
|
sensors = mkOption {
|
||||||
type = types.lines;
|
type = types.listOf (sensorType "sensor");
|
||||||
default = ''
|
default = [
|
||||||
tp_thermal /proc/acpi/ibm/thermal (0,0,10)
|
{ type = "tpacpi";
|
||||||
'';
|
query = "/proc/acpi/ibm/thermal";
|
||||||
description =''
|
}
|
||||||
thinkfan can read temperatures from three possible sources:
|
];
|
||||||
|
description = ''
|
||||||
/proc/acpi/ibm/thermal
|
List of temperature sensors thinkfan will monitor.
|
||||||
Which is provided by the thinkpad_acpi kernel
|
'' + syntaxNote "thermal";
|
||||||
module (keyword tp_thermal)
|
|
||||||
|
|
||||||
/sys/class/hwmon/*/temp*_input
|
|
||||||
Which may be provided by any hwmon drivers (keyword
|
|
||||||
hwmon)
|
|
||||||
|
|
||||||
S.M.A.R.T. (requires smartSupport to be enabled)
|
|
||||||
Which reads the temperature directly from the hard
|
|
||||||
disk using libatasmart (keyword atasmart)
|
|
||||||
|
|
||||||
Multiple sensors may be added, in which case they will be
|
|
||||||
numbered in their order of appearance.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fan = mkOption {
|
fans = mkOption {
|
||||||
type = types.str;
|
type = types.listOf (sensorType "fan");
|
||||||
default = "tp_fan /proc/acpi/ibm/fan";
|
default = [
|
||||||
description =''
|
{ type = "tpacpi";
|
||||||
Specifies the fan we want to use.
|
query = "/proc/acpi/ibm/fan";
|
||||||
On anything other than a Thinkpad you'll probably
|
}
|
||||||
use some PWM control file in /sys/class/hwmon.
|
];
|
||||||
A sysfs fan would be specified like this:
|
description = ''
|
||||||
pwm_fan /sys/class/hwmon/hwmon2/device/pwm1
|
List of fans thinkfan will control.
|
||||||
'';
|
'' + syntaxNote "fan";
|
||||||
};
|
};
|
||||||
|
|
||||||
levels = mkOption {
|
levels = mkOption {
|
||||||
type = types.lines;
|
type = types.listOf levelType;
|
||||||
default = ''
|
default = [
|
||||||
(0, 0, 55)
|
[0 0 55]
|
||||||
(1, 48, 60)
|
[1 48 60]
|
||||||
(2, 50, 61)
|
[2 50 61]
|
||||||
(3, 52, 63)
|
[3 52 63]
|
||||||
(6, 56, 65)
|
[6 56 65]
|
||||||
(7, 60, 85)
|
[7 60 85]
|
||||||
(127, 80, 32767)
|
["level auto" 80 32767]
|
||||||
'';
|
];
|
||||||
description = ''
|
description = ''
|
||||||
(LEVEL, LOW, HIGH)
|
[LEVEL LOW HIGH]
|
||||||
LEVEL is the fan level to use (0-7 with thinkpad_acpi).
|
|
||||||
|
LEVEL is the fan level to use: it can be an integer (0-7 with thinkpad_acpi),
|
||||||
|
"level auto" (to keep the default firmware behavior), "level full-speed" or
|
||||||
|
"level disengage" (to run the fan as fast as possible).
|
||||||
LOW is the temperature at which to step down to the previous level.
|
LOW is the temperature at which to step down to the previous level.
|
||||||
HIGH is the temperature at which to step up to the next level.
|
HIGH is the temperature at which to step up to the next level.
|
||||||
All numbers are integers.
|
All numbers are integers.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extraArgs = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
example = [ "-b" "0" ];
|
||||||
|
description = ''
|
||||||
|
A list of extra command line arguments to pass to thinkfan.
|
||||||
|
Check the thinkfan(1) manpage for available arguments.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = mkOption {
|
||||||
|
type = types.attrsOf settingsFormat.type;
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Thinkfan settings. Use this option to configure thinkfan
|
||||||
|
settings not exposed in a NixOS option or to bypass one.
|
||||||
|
Before changing this, read the <literal>thinkfan.conf(5)</literal>
|
||||||
|
manpage and take a look at the example config file at
|
||||||
|
<link xlink:href="https://github.com/vmatare/thinkfan/blob/master/examples/thinkfan.yaml"/>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -138,12 +201,21 @@ in {
|
||||||
|
|
||||||
environment.systemPackages = [ thinkfan ];
|
environment.systemPackages = [ thinkfan ];
|
||||||
|
|
||||||
systemd.services.thinkfan = {
|
services.thinkfan.settings = mapAttrs (k: v: mkDefault v) {
|
||||||
description = "Thinkfan";
|
sensors = map sensorToConf cfg.sensors;
|
||||||
after = [ "basic.target" ];
|
fans = map sensorToConf cfg.fans;
|
||||||
wantedBy = [ "multi-user.target" ];
|
levels = cfg.levels;
|
||||||
path = [ thinkfan ];
|
};
|
||||||
serviceConfig.ExecStart = "${thinkfan}/bin/thinkfan -n -c ${configFile}";
|
|
||||||
|
systemd.packages = [ thinkfan ];
|
||||||
|
|
||||||
|
systemd.services = {
|
||||||
|
thinkfan.environment.THINKFAN_ARGS = escapeShellArgs ([ "-c" configFile ] ++ cfg.extraArgs);
|
||||||
|
|
||||||
|
# must be added manually, see issue #81138
|
||||||
|
thinkfan.wantedBy = [ "multi-user.target" ];
|
||||||
|
thinkfan-wakeup.wantedBy = [ "sleep.target" ];
|
||||||
|
thinkfan-sleep.wantedBy = [ "sleep.target" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
boot.extraModprobeConfig = "options thinkpad_acpi experimental=1 fan_control=1";
|
boot.extraModprobeConfig = "options thinkpad_acpi experimental=1 fan_control=1";
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
{ lib, stdenv, fetchFromGitHub, cmake, libyamlcpp, pkg-config
|
{ lib
|
||||||
, smartSupport ? false, libatasmart }:
|
, stdenv
|
||||||
|
, fetchFromGitHub
|
||||||
|
, cmake
|
||||||
|
, libyamlcpp
|
||||||
|
, pkg-config
|
||||||
|
, procps
|
||||||
|
, coreutils
|
||||||
|
, smartSupport ? false, libatasmart
|
||||||
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "thinkfan";
|
pname = "thinkfan";
|
||||||
|
@ -12,36 +20,40 @@ stdenv.mkDerivation rec {
|
||||||
sha256 = "18vgm5w5pjnpipa34j4x87q10695w2jnqwvc2f027afy7mnzw7kz";
|
sha256 = "18vgm5w5pjnpipa34j4x87q10695w2jnqwvc2f027afy7mnzw7kz";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
# fix hardcoded install path
|
||||||
|
substituteInPlace CMakeLists.txt --replace /etc $out/etc
|
||||||
|
|
||||||
|
# fix command paths in unit files
|
||||||
|
for unit in rcscripts/systemd/*; do
|
||||||
|
substituteInPlace "$unit" \
|
||||||
|
--replace /bin/kill ${procps}/bin/kill \
|
||||||
|
--replace /usr/bin/pkill ${procps}/bin/pkill \
|
||||||
|
--replace /usr/bin/sleep ${coreutils}/bin/sleep
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
cmakeFlags = [
|
cmakeFlags = [
|
||||||
"-DCMAKE_INSTALL_DOCDIR=share/doc/${pname}"
|
"-DCMAKE_INSTALL_DOCDIR=share/doc/${pname}"
|
||||||
"-DUSE_NVML=OFF"
|
"-DUSE_NVML=OFF"
|
||||||
|
# force install unit files
|
||||||
|
"-DSYSTEMD_FOUND=ON"
|
||||||
] ++ lib.optional smartSupport "-DUSE_ATASMART=ON";
|
] ++ lib.optional smartSupport "-DUSE_ATASMART=ON";
|
||||||
|
|
||||||
nativeBuildInputs = [ cmake pkg-config ];
|
nativeBuildInputs = [ cmake pkg-config ];
|
||||||
|
|
||||||
buildInputs = [ libyamlcpp ] ++ lib.optional smartSupport libatasmart;
|
buildInputs = [ libyamlcpp ] ++ lib.optional smartSupport libatasmart;
|
||||||
|
|
||||||
installPhase = ''
|
meta = {
|
||||||
runHook preInstall
|
description = "A simple, lightweight fan control program";
|
||||||
|
longDescription = ''
|
||||||
install -Dm755 {.,$out/bin}/thinkfan
|
Thinkfan is a minimalist fan control program. Originally designed
|
||||||
|
specifically for IBM/Lenovo Thinkpads, it now supports any kind of
|
||||||
cd "$NIX_BUILD_TOP"; cd "$sourceRoot" # attempt to be a bit robust
|
system via the sysfs hwmon interface (/sys/class/hwmon).
|
||||||
install -Dm644 {.,$out/share/doc/thinkfan}/README.md
|
|
||||||
cp -R examples $out/share/doc/thinkfan
|
|
||||||
install -Dm644 {src,$out/share/man/man1}/thinkfan.1
|
|
||||||
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
'';
|
||||||
|
license = lib.licenses.gpl3Plus;
|
||||||
meta = with lib; {
|
|
||||||
description = "A minimalist fan control program";
|
|
||||||
longDescription = "A minimalist fan control program. Originally designed
|
|
||||||
specifically for IBM/Lenovo Thinkpads, it now supports any kind of system via
|
|
||||||
the sysfs hwmon interface (/sys/class/hwmon).";
|
|
||||||
license = licenses.gpl3;
|
|
||||||
homepage = "https://github.com/vmatare/thinkfan";
|
homepage = "https://github.com/vmatare/thinkfan";
|
||||||
maintainers = with maintainers; [ domenkozar ];
|
maintainers = with lib.maintainers; [ domenkozar rnhmjoj ];
|
||||||
platforms = platforms.linux;
|
platforms = lib.platforms.linux;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue