Merge pull request #111624 from rnhmjoj/thinkfan

nixos/thinkfan: rewrite for 1.2 update

Changed files
+211 -114
nixos
doc
manual
release-notes
modules
services
hardware
pkgs
tools
system
thinkfan
+13
nixos/doc/manual/release-notes/rl-2103.xml
···
ALSA OSS emulation (<varname>sound.enableOSSEmulation</varname>) is now disabled by default.
</para>
</listitem>
</itemizedlist>
</section>
···
ALSA OSS emulation (<varname>sound.enableOSSEmulation</varname>) is now disabled by default.
</para>
</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>
</section>
+163 -91
nixos/modules/services/hardware/thinkfan.nix
···
let
cfg = config.services.thinkfan;
-
configFile = pkgs.writeText "thinkfan.conf" ''
-
# ATTENTION: There is only very basic sanity checking on the configuration.
-
# That means you can set your temperature limits as insane as you like. You
-
# 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}
-
${cfg.sensors}
-
# Syntax:
-
# (LEVEL, LOW, HIGH)
-
# LEVEL is the fan level to use (0-7 with thinkpad_acpi)
-
# 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
-
# All numbers are integers.
-
#
-
${cfg.levels}
'';
-
-
thinkfan = pkgs.thinkfan.override { smartSupport = cfg.smartSupport; };
in {
···
type = types.bool;
default = false;
description = ''
-
Whether to enable thinkfan, fan controller for IBM/Lenovo ThinkPads.
'';
};
smartSupport = mkOption {
type = types.bool;
default = false;
description = ''
-
Whether to build thinkfan with SMART support to read temperatures
directly from hard disks.
'';
};
sensors = mkOption {
-
type = types.lines;
-
default = ''
-
tp_thermal /proc/acpi/ibm/thermal (0,0,10)
-
'';
-
description =''
-
thinkfan can read temperatures from three possible sources:
-
-
/proc/acpi/ibm/thermal
-
Which is provided by the thinkpad_acpi kernel
-
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 {
-
type = types.str;
-
default = "tp_fan /proc/acpi/ibm/fan";
-
description =''
-
Specifies the fan we want to use.
-
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:
-
pwm_fan /sys/class/hwmon/hwmon2/device/pwm1
'';
};
-
levels = mkOption {
-
type = types.lines;
-
default = ''
-
(0, 0, 55)
-
(1, 48, 60)
-
(2, 50, 61)
-
(3, 52, 63)
-
(6, 56, 65)
-
(7, 60, 85)
-
(127, 80, 32767)
-
'';
description = ''
-
(LEVEL, LOW, HIGH)
-
LEVEL is the fan level to use (0-7 with thinkpad_acpi).
-
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.
-
All numbers are integers.
'';
};
-
};
···
environment.systemPackages = [ thinkfan ];
-
systemd.services.thinkfan = {
-
description = "Thinkfan";
-
after = [ "basic.target" ];
-
wantedBy = [ "multi-user.target" ];
-
path = [ thinkfan ];
-
serviceConfig.ExecStart = "${thinkfan}/bin/thinkfan -n -c ${configFile}";
};
boot.extraModprobeConfig = "options thinkpad_acpi experimental=1 fan_control=1";
···
let
cfg = config.services.thinkfan;
+
settingsFormat = pkgs.formats.yaml { };
+
configFile = settingsFormat.generate "thinkfan.yaml" cfg.settings;
+
thinkfan = pkgs.thinkfan.override { inherit (cfg) smartSupport; };
+
+
# fan-speed and temperature levels
+
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 ];
+
+
# sensor or fan config
+
sensorType = name: types.submodule {
+
freeformType = types.attrsOf settingsFormat.type;
+
options = {
+
type = mkOption {
+
type = types.enum [ "hwmon" "atasmart" "tpacpi" "nvml" ];
+
description = ''
+
The ${name} type, can be
+
<literal>hwmon</literal> for standard ${name}s,
+
+
<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).
+
+
<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 {
···
type = types.bool;
default = false;
description = ''
+
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 {
type = types.bool;
default = false;
description = ''
+
Whether to build thinkfan with S.M.A.R.T. support to read temperatures
directly from hard disks.
'';
};
sensors = mkOption {
+
type = types.listOf (sensorType "sensor");
+
default = [
+
{ type = "tpacpi";
+
query = "/proc/acpi/ibm/thermal";
+
}
+
];
+
description = ''
+
List of temperature sensors thinkfan will monitor.
+
'' + syntaxNote "thermal";
+
};
+
fans = mkOption {
+
type = types.listOf (sensorType "fan");
+
default = [
+
{ type = "tpacpi";
+
query = "/proc/acpi/ibm/fan";
+
}
+
];
+
description = ''
+
List of fans thinkfan will control.
+
'' + syntaxNote "fan";
+
};
+
levels = mkOption {
+
type = types.listOf levelType;
+
default = [
+
[0 0 55]
+
[1 48 60]
+
[2 50 61]
+
[3 52 63]
+
[6 56 65]
+
[7 60 85]
+
["level auto" 80 32767]
+
];
+
description = ''
+
[LEVEL LOW HIGH]
+
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.
+
HIGH is the temperature at which to step up to the next level.
+
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"/>
'';
};
};
···
environment.systemPackages = [ thinkfan ];
+
services.thinkfan.settings = mapAttrs (k: v: mkDefault v) {
+
sensors = map sensorToConf cfg.sensors;
+
fans = map sensorToConf cfg.fans;
+
levels = cfg.levels;
+
};
+
+
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";
+35 -23
pkgs/tools/system/thinkfan/default.nix
···
-
{ lib, stdenv, fetchFromGitHub, cmake, libyamlcpp, pkg-config
-
, smartSupport ? false, libatasmart }:
stdenv.mkDerivation rec {
pname = "thinkfan";
···
sha256 = "18vgm5w5pjnpipa34j4x87q10695w2jnqwvc2f027afy7mnzw7kz";
};
cmakeFlags = [
"-DCMAKE_INSTALL_DOCDIR=share/doc/${pname}"
"-DUSE_NVML=OFF"
] ++ lib.optional smartSupport "-DUSE_ATASMART=ON";
nativeBuildInputs = [ cmake pkg-config ];
buildInputs = [ libyamlcpp ] ++ lib.optional smartSupport libatasmart;
-
installPhase = ''
-
runHook preInstall
-
-
install -Dm755 {.,$out/bin}/thinkfan
-
-
cd "$NIX_BUILD_TOP"; cd "$sourceRoot" # attempt to be a bit robust
-
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
-
'';
-
-
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";
-
maintainers = with maintainers; [ domenkozar ];
-
platforms = platforms.linux;
};
}
···
+
{ lib
+
, stdenv
+
, fetchFromGitHub
+
, cmake
+
, libyamlcpp
+
, pkg-config
+
, procps
+
, coreutils
+
, smartSupport ? false, libatasmart
+
}:
stdenv.mkDerivation rec {
pname = "thinkfan";
···
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 = [
"-DCMAKE_INSTALL_DOCDIR=share/doc/${pname}"
"-DUSE_NVML=OFF"
+
# force install unit files
+
"-DSYSTEMD_FOUND=ON"
] ++ lib.optional smartSupport "-DUSE_ATASMART=ON";
nativeBuildInputs = [ cmake pkg-config ];
buildInputs = [ libyamlcpp ] ++ lib.optional smartSupport libatasmart;
+
meta = {
+
description = "A simple, lightweight fan control program";
+
longDescription = ''
+
Thinkfan is 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 = lib.licenses.gpl3Plus;
homepage = "https://github.com/vmatare/thinkfan";
+
maintainers = with lib.maintainers; [ domenkozar rnhmjoj ];
+
platforms = lib.platforms.linux;
};
}