YAML is a very powerful, yet concise notation for structured data.
Its full specification is available at https://yaml.org/spec/1.2/spec.html.
Thinkfan uses only a small subset of the full YAML syntax, so it may be
helpful, but not strictly necessary for users to take a look at the
spec.
The most important thing to note is that indentation is
syntactically relevant. In particular, tabs should not be mixed with spaces.
We recommend using two spaces for indentation, like it is shown below.
The thinkfan config has three main sections:
- sensors:
- Where temperatures should be read from. All hwmon-style drivers are
supported, as well as /proc/acpi/ibm/thermal, and, depending on the
compile-time options, libatasmart (to read temperatures directly
from hard disks) and NVML (via the proprietary nvidia driver).
- fans:
- Which fans should be used (currently only one allowed). Support for
multiple fans is currently in development and planned for a future
release. Both hwmon-style PWM controls and
/proc/acpi/ibm/fan can be used.
- levels:
- Maps temperatures to fan speeds. A “simple mapping” just
specifies one temperature as the lower and upper bound (respectively) for
a given fan speed. In a “detailed mapping”, the upper and
lower bounds are specified for each driver/sensor configured under
sensors:. This mode should be used when thinkfan is monitoring
multiple devices that can tolerate different amounts of heat.
Under each of these sections, there must be a list of key-value
maps, each of which configures a sensor driver, fan driver or fan speed
mapping.
For thinkfan to work, it first needs to know which temperature
sensor drivers and which fan drivers it should use. The mapping between
temperature readings and fan speeds is specified in a separate config
section (see the FAN SPEEDS section below).
The entries under the sensors: section can specify
sysfs/hwmon, lm_sensors, thinkpad_acpi, NVML or atasmart drivers. Support
for lm_sensors, NVML and atasmart requires the appropriate libraries and
must have been enabled at compile time. There can be any number (greater
than zero) and combination of hwmon, tpacpi, nvml and
atasmart entries. However there may be at most one instance of the
tpacpi entry.
The syntax for identifying each type of sensors looks as
follows:
########
sensors:
- hwmon: hwmon-path # A path to a sysfs/hwmon sensor
name: hwmon-name # Optional entry
model: hwmon-model # Optional entry for nvme
indices: index-list # Optional entry
- chip: chip-name # An lm_sensors/libsensors chip...
ids: id-list # ... with some feature IDs
- tpacpi: /proc/acpi/ibm/thermal # Provided by the thinkpad_acpi kernel module
indices: index-list # Optional entry
- nvml: nvml-bus-id # Uses the proprietary nVidia driver
- atasmart: disk-device-file # Requires libatasmart support
- ...
Additionally, each sensor entry can have a number of settings that
modify its behavior:
########
sensors:
- ...: ... # A sensor specification as shown above
correction: correction-list # Optional entry
optional: bool-ignore-errors # Optional entry
max_errors: num-max-errors # Optional entry
Since version 2.0, thinkfan can control multiple fans. So any
number of hwmon fan sections can be specified. Note however that the
thinkpad_acpi kernel module only supports one fan, so there can be at most
one tpacpi section:
# ...
fans:
- tpacpi: /proc/acpi/ibm/fan
- hwmon: hwmon-path
name: hwmon-name
indices: index-list
- ...
The behavior of any fan can optionally be controlled with the
optional and max_errors keywords, and by specifying a local
fan speed config under the levels: keyword:
# ...
fans:
- ...: ... # A fan specification as shown above
optional: bool-ignore-errors # Optional entry
max_errors: num-max-errors # Optional entry
levels: levels-section # Optional entry
- hwmon-path
- There are three ways of specifying hwmon fans or sensors:
- 1)
- A full path of a “temp*_input” or “pwm*” file,
like “/sys/class/hwmon/hwmon0/pwm1” or
“/sys/class/hwmon/hwmon0/temp1_input”. In this case, the
“indices: index-list” and
“name: hwmon-name” entries are
unnecessary since the path uniquely identifies a specific fan or sensor.
Note that this method may lead to problems when the load
order of the drivers changes across bootups, because in the
“hwmonX” folder name, the X actually corresponds
to the load order. Use method 2) or 3) to avoid this problem.
- 2)
- A directory that contains a specific hwmon driver, for example
“/sys/devices/platform/nct6775.2592”. Note that this path
does not contain the load-order dependent “hwmonX”
folder. As long as it contains only a single hwmon driver/interface it is
sufficient to specify the “indices:
index-list” entry to tell thinkfan which specific
sensors to use from that interface. The “name:
hwmon-name” entry is unnecessary.
- 3)
- A directory that contains multiple or all of the hwmon drivers, for
example “/sys/class/hwmon”. Here, both the
“name: hwmon-name” and
“indices: index-list” entries are
required to tell thinkfan which interface to select below that path, and
which sensors or which fan to use from that interface.
- hwmon-name
- The name of a hwmon interface, typically found in a file called
“name”. This has to be specified if hwmon-path is a
base path that contains multiple hwmons. This method of specifying sensors
is particularly useful if the full path to a particular hwmon keeps
changing between bootups, e.g. due to changing load order of the driver
modules.
- hwmon-model
- The model of a device in a hwmon interface usually found for NVME devices
in a file under “device” called “model”. For
example, you might have an NVME
“/sys/class/hwmon/hwmon3/device/model” and you might have an
external NVME over USB or Thunderbolt that you don't want to monitor or
you might have two NVME's.
- index-list
- A YAML list [ X1, X2, ...
] that specifies which sensors, resp. which fan to use from a
given interface. Both /proc/acpi/ibm/thermal and
also many hwmon interfaces contain multiple sensors, and not all of them
may be relevant for fan control.
- For hwmon entries, this is required if hwmon-path does not
refer directly to a single “tempXi_input” file, but
to a folder that contains one or more of them. In this case,
index-list specifies the Xi for the
“tempXi_input” files that should be used. A hwmon
interface may also contain multiple PWM controls for fans, so in that
case, index-list must contain exactly one entry.
- For tpacpi sensors, this entry is optional. If it is omitted, all
temperatures found in /proc/acpi/ibm/thermal will be used.
- chip-name
- The unique name of an lm-sensors hwmon chip. lm-sensors or libsensors is
the official client library to access the sysfs hwmon subsystem, and as
such it is the preferred way of specifying sensors. Available chips can be
listed by running the sensors command as root. The header above
each block will be the chip name.
- ids
- A list of lm-sensors feature IDs, for example “[ SYSTIN, CPUTIN,
"Sensor 2" ]”. In the sensors command
output, the name before the colon on each line will be the feature ID.
- nvml-bus-id
- NOTE: only available if thinkfan was compiled with USE_NVML enabled.
The PCI bus ID of an nVidia graphics card that is run with the
proprietary nVidia driver. Can be obtained with e.g. “lspci |
grep -i vga”. Usually, nVidia cards will use the open source
nouveau driver, which should support hwmon sensors instead.
- disk-device-file
- NOTE: only available if thinkfan was compiled with USE_ATASMART enabled.
Full path to a device file for a hard disk that supports
S.M.A.R.T. See also the -d option in thinkfan(1) that
prevents thinkfan from waking up sleeping (mechanical) disks to read
their temperature.
- correction-list
(optional, zeroes by default)
- A YAML list that specifies temperature offsets for each sensor in use by
the given driver. Use this if you want to use the “simple”
level syntax, but need to compensate for devices with a lower heat
tolerance. Note however that the detailed level syntax is usually the
better (i.e. more fine-grained) choice.
- bool-ignore-errors
(optional, false by default)
- A truth value (yes/no/true/false) that
specifies whether thinkfan should ignore all errors when using a given
sensor or fan. Normally, thinkfan will exit with an error message if it
fails reading temperatures from a sensor or writing to a fan.
An optional device will not delay startup. Instead, thinkfan
will commence normal operation with the remaining devices and re-try
initializing unavailable optional devices in every loop until all are
found.
Marking a sensor/fan as optional may be useful for removable
hardware or devices that may get switched off entirely to save
power.
- num-max-errors
(optional, 0 by default)
- A positive integer that specifies how often thinkfan is allowed to re-try
if if fails to initialize, read from or write to a given sensor or fan. On
startup, thinkfan will attempt to initialize the device
num-max-errors times before commencing normal operation. If the
device cannot be initialized after the given number of attempts, thinkfan
will fail.
When a device with a positive num-max-errors fails
during runtime, thinkfan will likewise attempt to re-initialize it the
given number of times before failing.
- levels-section
(optional, use global levels section by default)
- As of thinkfan 2.0, multiple fans can be configured. To this end, each fan
can now have its own levels: section (cf. FAN SPEEDS below). The
syntax of the global vs. the fan-specific levels: section are
identical, the only difference being that in a fan-specific one, the speed
value(s) refer only the fans configured in that particular fans:
entry.
NOTE: Global and fan-specific levels: are mutually
exclusive, i.e. there cannot be both a global one and fan-specific
sections.
The levels: section specifies a list of fan speeds with
associated lower and upper temperature bounds. If temperature(s) drop below
the lower bound, thinkfan switches to the previous level, and if the upper
bound is reached, thinkfan switches to the next level.
Since thinkfan 2.0, this section can appear either under an
individual fan (cf. levels: keyword under Fan Syntax), or
globally.
In the simplified form, only one temperature is specified as an
upper/lower limit for a given fan speed. In that case, the
lower-bound and upper-bound are compared only to the highest
temperature found among all configured sensors. All other temperatures are
ignored. This mode is suitable for small systems (like laptops) where there
is only one device (e.g. the CPU) whose temperature needs to be controlled,
or where the required fan behaviour is similar enough for all
heat-generating devices.
# ...
levels:
- [ fan-speed, lower-bound, upper-bound ]
- ...
This mode is suitable for more complex systems, with devices that
have different temperature ratings. For example, many modern CPUs and GPUs
can deal with temperatures above 80°C on a daily basis, whereas a
hard disk will die quickly if it reaches such temperatures. In detailed
mode, upper and lower temperature limits are specified for each sensor
individually:
# ...
levels:
- speed: [ fan1-speed, fan2-speed, ... ]
lower_limit: [ l1, l2, ... ]
upper_limit: [ u1, u2, ... ]
- ...
- fan1-speed,
fan2-speed, ...
- fan-speed
- When multiple fans are specified under the fans: section, value of
the speed: keyword must be a list of as many fanX-speed
values. They are applied to the fans by their order of appearance, i.e.
the first speed value applies to the fan that has been specified first,
the second value to the second fan, and so on. If there is just one fan,
instead of a list with just one element, the speed value can be given as a
scalar.
The possible speed values for fanX-speed are different
depending on which fan driver is used:
- For a hwmon fan, fanX-speed is a numeric value ranging from
0 to 255, corresponding to the PWM values accepted by the
various kernel drivers.
- For a tpacpi fan on Lenovo/IBM ThinkPads and some other Lenovo
laptops (see SENSORS & FAN DRIVERS above), numeric
values and strings can be used. The numeric values range from 0 to 7. The
string values take the form "level lvl-id",
where lvl-id may be a value from 0 to 7, auto,
full-speed or disengaged. The numeric values 0 to
7 correspond to the regular fan speeds used by the firmware,
although many firmwares don't even use level 7. The value
"level auto" gives control back to the firmware, which
may be useful if the fan behavior only needs to be changed for certain
specific temperature ranges (usually at the high and low end of the
range). The values "level full-speed" and "level
disengaged" take the fan speed control away from the firmware,
causing the fan to slowly ramp up to an absolute maximum that can be
achieved within electrical limits. Note that this will run the fan out of
specification and cause increased wear, though it may be helpful to combat
thermal throttling.
- l1, l2,
...
- u1, u2,
...
- The lower and upper temperature limits refer to the sensors in the same
order in which they were found when processing the sensors: section
(see SENSOR & FAN DRIVERS above). For the first level entry,
the lower_limit may be omitted, and for the last one, the
upper_limit may be omitted. For all levels in between, the lower
limits must overlap with the upper limits of the previous level, to make
sure the entire temperature range is covered and that there is some
hysteresis between speed levels.
Instead of a temperature, an underscore (_) can be
given. An underscore means that the temperature of that sensor should be
ignored at the given speed level.