Packages like "xsensors" and "lm_sensors" can show you the temperature of your processor's core(s). And that's great - right up until you want to write a program to retrieve the temperature yourself. A direct look at the processor core temperatures is available in /sys/devices/platform/coretemp.0/hwmon/hwmon?/ with the temp?_input files ... at least, this seems to be true on an Intel-based system. I can't speak to AMD-based systems, but I know those directories don't exist on a Raspberry Pi 4. So I looked for a more generalized solution.
This can be found in /sys/class/thermal/, which contains one or several thermal_zone? directory links. Each of these contain ... more stuff. I say this because what's in those varies considerably. The most obvious, and important to this conversation, is the temp file which includes the current temperature. But since there are several "thermal zones," you should be asking yourself "temperature of what?" Let's look at thermal_zone0 on my main laptop:
$ cd /sys/class/thermal/
$ ls
cooling_device0@ cooling_device3@ cooling_device7@ thermal_zone1@ thermal_zone5@
cooling_device1@ cooling_device4@ cooling_device8@ thermal_zone2@ thermal_zone6@
cooling_device10@ cooling_device5@ cooling_device9@ thermal_zone3@
cooling_device2@ cooling_device6@ thermal_zone0@ thermal_zone4@
$ cd thermal_zone0/
$ ls
available_policies k_d mode slope trip_point_0_temp
device@ k_i offset subsystem@ trip_point_0_type
hwmon1/ k_po policy sustainable_power type
integral_cutoff k_pu power/ temp uevent
$ cat temp
44000
$ cat type
acpitz
The temperature is in Celsius ... or is that milliCelsius given that it needs to be divided by 1000 to get a proper value? temp and type seem to always be present in these thermal_zone? folders? Let's try to look at all of them.
$ cd /sys/class/thermal/
$ for folder in thermal_zone* ; do cat ${folder}/type ; cat ${folder}/temp ; echo ; done
acpitz
44000
INT3400 Thermal
20000
SEN1
50
pch_skylake
37000
B0D4
43000
x86_pkg_temp
43000
iwlwifi_1
cat: thermal_zone6/temp: No data available
That last partially blows my idea that these two items are always present: thermal_zone6 has a temp file, but ... nothing in it? And notice that whatever "SEN1" is, it isn't following the "multiplied-by-1000" rule. Not only that, checking these values multiple times has told me that the SEN1 and "INT3400 Thermal" values are both fixed: they never change.
Results are quite different on a Raspberry Pi (4):
$ cd /sys/class/thermal/
$ for folder in thermal_zone* ; do cat ${folder}/type ; cat ${folder}/temp ; echo ; done
cpu-thermal
45277
There's only one thermal_zone? folder, and the type is different.
The best explanation I've found of what all these "types" mean comes from https://askubuntu.com/questions/1110943/what-do-the-different-thermal-zones-actually-correspond-to - and it's less helpful than one might hope:
The exact definition of what a given thermal zone represents is defined by the driver for the given zone. Different processors and motherboards make different thermometers available to linux, and so every one has it's own name. Each of the different zones is a different thermometer on the system: the "acpitz" one is the one made available through ACPI, and the x86_pkg_temp is the temperature exported by the core x86 spec. The ACPI one is a motherboard sensor that is near the CPU socket, and the x86_pkg_temp is within the CPU itself. Based on a git grep through the kernel source tree, the 2nd one (pch_cannonlake) specifies the thermomemter output of an intel-specific thermocouple, used for thermal throttling. However, determining it's exact location (as with the others) is at best an educated guess: it will vary by chipset and manufacturer, so you would need to consult the detailed specification and layout of your chip.
In practical terms, what this means for a weekend coder like myself is that I'm going to parse the type files looking for "cpu-thermal" or "x86_pkg_temp" and use only values that match one of those. And it appears that the /sys/class/thermal/ folder doesn't exist on VMs, so that's something to test before proceeding to look for temperatures.
[As a further compatibility note: WSL2 has the /sys/class/thermal/ folder, but there are no thermal_zone files in there - so no compatibility layer, and this stuff doesn't work.]
Here's the Python version I have so far, somewhat fancier than the Bash version:
#!/usr/bin/env python3
import os
import glob
globThermalDirs = '/sys/class/thermal/thermal_zone*'
maxTemp = 0
try:
zoneDirs = glob.glob(globThermalDirs)
for tdir in zoneDirs:
filenameE = tdir + "/temp"
filenameY = tdir + "/type"
with open(filenameE) as fe, open(filenameY) as fy:
try:
tempType = fy.read().splitlines()[0]
rawTemp = float(fe.read().splitlines()[0])
if rawTemp > 1000 :
zoneTemp = float(rawTemp)/1000
else:
zoneTemp = rawTemp
if tempType == "cpu-thermal" or tempType == "x86_pkg_temp" :
notification = " ***"
else:
notification = ""
print(filenameE + "(" + tempType + "): " + str(zoneTemp) + notification)
except OSError:
print("OSError on " + filenameE);
if (zoneTemp > maxTemp):
maxTemp = zoneTemp
print("Max temp found: " + str(maxTemp))
except:
print("Failed to find '" + globThermalDirs + "'")
The next step is to trim the output down to a single number. When I started working on this, I thought the best thing would be to export the highest temperature. You can see this in the maxTemp variable. But now I think it's better to go with "cpu-thermal" or "x86_pkg_temp" and drop the rest. Here's the current output (from my main laptop, which is Intel-based):
/sys/class/thermal/thermal_zone2/temp(SEN1): 50.0 /sys/class/thermal/thermal_zone0/temp(acpitz): 41.0 /sys/class/thermal/thermal_zone5/temp(x86_pkg_temp): 43.0 *** /sys/class/thermal/thermal_zone3/temp(pch_skylake): 36.5 /sys/class/thermal/thermal_zone1/temp(INT3400 Thermal): 20.0 OSError on /sys/class/thermal/thermal_zone6/temp /sys/class/thermal/thermal_zone4/temp(B0D4): 43.0 Max temp found: 50.0