Psutil: Hardware temperatures (sensors_temperatures())

Created on 23 May 2014  路  45Comments  路  Source: giampaolo/psutil

_From g.rodola on April 24, 2013 14:59:32_

Proposal

I borrowed this idea from glances: https://github.com/nicolargo/glances
...which internally uses pysensors: https://pypi.python.org/pypi/PySensors/
API may look like this:

>>> psutil.cpu_temperature()
[cputemp(name='cpu1', temp=35, high=70, critical=90), 
 cputemp(name='cpu2', temp=30, high=70, critical=90,
 ...]

psutil.cpu_temperature(celsius=False) could be used to express temperature in
fahrenheit. The order in which CPUs are returned should be the same as other cpu_*
functions and be consistent across calls so that:

>>> psutil.cpu_temperature()[0]

...and:

>>> psutil.cpu_times(percpu=True)[0]

...will refer to the same CPU.

FreeBSD: http://superuser.com/questions/344498/get-temperature-of-cpu-intel-core-i5-in-freebsd

_Original issue: http://code.google.com/p/psutil/issues/detail?id=371_

enhancement imported linux

Most helpful comment

I compiled a list of all the temperature sensors accessible via the SMC

| SMC Code | Name |
|----------|-------|
|TA0P|Ambient|
|TA0S|PCI Slot 1 Pos 1|
|TA1P|Ambient temperature|
|TA1S|PCI Slot 1 Pos 2|
|TA2S|PCI Slot 2 Pos 1|
|TA3S|PCI Slot 2 Pos 2|
|TB0P|BLC Proximity|
|TB0T|Battery TS_MAX|
|TB1T|Battery 1|
|TB2T|Battery 2|
|TB3T|Battery 3|
|TC_C|CPU Core _|
|TC_D|CPU _ Die|
|TC_E|CPU _ ??|
|TC_F|CPU _ ??|
|TC_G|CPU _ ??|
|TC_H|CPU _ Heatsink|
|TC_J|CPU _ ??|
|TC_P|CPU _ Proximity|
|TCGC|PECI GPU|
|TCSA|PECI SA|
|TCSC|PECI SA|
|TCXC|PECI CPU|
|TG_D|GPU _ Die|
|TG_H|GPU _ Heatsink|
|TG_P|GPU _ Proximity|
|TH_H|Heatsink _ Proximity|
|TH_P|HDD _ Proximity|
|TI_P|Thunderbolt _|
|TL_P|LCD _ Proximity|
|TL_P|LCD _|
|TM_P|Memory _ Proximity|
|TM_S|Memory Slot _|
|TMA_|DIMM A ?|
|TMB_|DIMM B ?|
|TN_D|Northbridge _ Die|
|TN_H|Northbridge _ Heatsink|
|TN_P|Northbridge _ Proximity|
|TO_P|Optical Drive _ Proximity|
|TP_C|Power Supply _|
|TP_P|Power Supply _ Proximity|
|TS_C|Expansion Slot _|
|TS_P|Palm Rest _|
|TS0C|Expansion slots|
|TS0S|Memory Bank Proximity|
|TW0P|AirPort Proximity|

Note the underscores indicating the possibility of multiple sensors. These values will need to be scanned in a smart manner.

All 45 comments

_From g.rodola on April 27, 2013 09:36:58_

Committed in revision 22a650567ba7 in a separate branch by parsing files in /sys/class/hwmon/hwmon_/temp1__.
It is probably incomplete compared to what we can get via lm-sensors though so care should be taken on whether adding this or not.

Status: Started

_From g.rodola on June 17, 2013 03:53:59_

OSX: https://jira.hyperic.com/browse/SIGAR-12

_From [email protected] on June 17, 2013 11:49:37_

Neither of these works on my macbook running 10.8.4:

[root@macbook ]# sysctl kern.cpu_temp_is_valid
second level name cpu_temp_is_valid in kern.cpu_temp_is_valid is invalid

[root@macbook ]$ sysctl kern.cpu_temp
second level name cpu_temp in kern.cpu_temp is invalid

I also don't see any reference to temp sensors in sysctlbyname docs:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/sysctlbyname.3.html

Would also like to see this feature. For RaspberryPi I'm now using:

def get_cpu_temperature():
    """
    Get CPU temperature.
    """
    with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
        temp = float(f.read()) / 1000.0

    return temp

But this doesn't work on OSX for example.

Here's some C-code that gets the OSX temperature: https://github.com/lavoiesl/osx-cpu-temp

Attaching a modified version of osx-cpu-temp C source code which I managed to compile (by modifying the Makefile). I get temperature == 0.0 but I suppose that's because I'm virtualizing OSX hence there are no sensors.
osx-cpu-temp.zip

I'm not gonna have a chance to implement this on OSX as I don't have the hardware.

@giampaolo if you can slap it in a branch, i can test it on osx

OK, I've just merged the Linux implementation into master. For now this functionality is Linux only as:

  • I don't have a physical OSX box to test against and VirtualBox does not emulated temperature sensors. @thijstriemstra I'm no sure what to put into a branch as I don't have anything working
  • FreeBSD: sensors exist in different approaches (see: https://forums.freebsd.org/threads/882/) but none of them work on my virtualized FreeBSD box
  • Windows: I spotted at least 3 different methods to obtain temperatures by using WMI but none of them worked (I also tried no a "real" physical Windows laptop). It seems this is strictly dependent on the hardware installed so it's not portable.

@giampaolo coincidentally I decided to test your osx-cpu-temp on my osx when it's been on an ice-cold floor in its' case but your smb scripts works:

$ ./smc 
22.1掳C

Tested on macOS 10.11.6;

uname -a
Darwin MacBook-Pro 15.6.0 Darwin Kernel Version 15.6.0: Mon Jan  9 23:07:29 PST 2017; root:xnu-3248.60.11.2.1~1/RELEASE_X86_64 x86_64

Now I need to find a place/app on this mac where I can verify this nr.

The iStats ruby package also provides CPU stats (sudo gem install iStats):

$ istats cpu
CPU temp: 22.13掳C 鈻佲杺鈻冣枀鈻嗏枃

$ ./smc
22.1掳C

If you can also provide more decimals, that would be great but this seems to work fine.

iStats also provides battery temperature:

$ istats battery temp
Battery temp: 13.19掳C

Also tested it on the latest Raspbian (on raspberrypi)

Linux raspberrypi 4.4.38-v7+ #938 SMP Thu Dec 15 15:22:21 GMT 2016 armv7l GNU/Linux

and both master and 5.1.2 return not much:

$ python
Python 3.5.3 (default, Jan 24 2017, 00:58:06) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import psutil
>>> psutil.sensors_temperatures()
{}

@thijstriemstra Can you show what $ ls -Al /sys/class/hwmon/hwmon0 returns?

$ ls -Al /sys/class/hwmon/hwmon0
ls: cannot access /sys/class/hwmon/hwmon0: No such file or directory
$ ls -Al /sys/class/hwmon/
ls: cannot access /sys/class/hwmon/: No such file or directory

Like I mentioned, on an RPi it seems to be /sys/class/thermal/thermal_zone0/temp we're after:

$ ls -l /sys/class/thermal/thermal_zone0/
total 0
-r--r--r-- 1 root root 4096 Feb  6 23:14 available_policies
-rw-r--r-- 1 root root 4096 Feb  6 23:14 integral_cutoff
-rw-r--r-- 1 root root 4096 Feb  6 23:14 k_d
-rw-r--r-- 1 root root 4096 Feb  6 23:14 k_i
-rw-r--r-- 1 root root 4096 Feb  6 23:14 k_po
-rw-r--r-- 1 root root 4096 Feb  6 23:14 k_pu
-rw-r--r-- 1 root root 4096 Feb  6 23:14 offset
-rw-r--r-- 1 root root 4096 Feb  6 23:14 passive
-rw-r--r-- 1 root root 4096 Feb  6 23:14 policy
drwxr-xr-x 2 root root    0 Feb  6 23:14 power
-rw-r--r-- 1 root root 4096 Feb  6 23:14 slope
lrwxrwxrwx 1 root root    0 Feb  6 23:14 subsystem -> ../../../../class/thermal
-rw-r--r-- 1 root root 4096 Feb  6 23:14 sustainable_power
-r--r--r-- 1 root root 4096 Feb  6 23:14 temp
-r--r--r-- 1 root root 4096 Feb  6 23:14 type
-rw-r--r-- 1 root root 4096 Feb  1 04:17 uevent
$ cat /sys/class/thermal/thermal_zone0/temp 
41698
$ ls -l /sys/class/thermal/
total 0
lrwxrwxrwx 1 root root 0 Feb  1 04:17 thermal_zone0 -> ../../devices/virtual/thermal/thermal_zone0

That would be the problem then. ;) There's a comment about this for Ubuntu as well in the code.

Should I open a new ticket? You mean it's also not working in regular Debian and Ubuntu? I haven't checked the code but I also dont remember it being in the changelog (other than 'linux support'). Seems to work fine on Ubuntu 16.04 here.

I believe it's working in those OSes but they provide more than one interface for CPU temperature (thermal_zone and hwmon) whereas Raspbian appears to only provide thermal_zone.

And opening a ticket would probably be helpful. :)

I see!

Right now psutil reads temperatures from /sys/class/hwmon/hwmon*/temp*_*. It would be nice to add /sys/class/thermal/ as it appears it would improve Linux support.

/sys/class/thermal/ does not provide the same names as /sys/class/hwmon/hwmon*/temp*_* plus it does not include max temperatures so it seems it's incompatible.

Closing out as fixed.

I see that the issue is closed as fixed, but there doesn't seem to be any support for any sensors on macOS. I'm curious: why didn't this get implemented for macOS? There seem to be two pretty good libraries (SMCKit and iStats) that provide the necessary functionality (temps, fans, and battery.) I understand bloat might be a concern, but this seems like a reasonable use.

I didn't implement this on OSX because I don't have the hardware. I virtualize OSX via VirtualBox but with that method it shows no temperatures (or battery). As such somebody else has to do it.

dqk6sjs42i8z

Go for it! ;)
You can take a look at https://github.com/lavoiesl/osx-cpu-temp for an inspiration.

On that note though, since as of now everything is self contained, what's the policy on using other libraries?

I am against that as I don't want to introduce any installation requirement other than the C compiler.
Actually I want to move away from that too (see #824). For this specific issue you should rely on native OSX syscalls.

I started working on this in branch: https://github.com/Infinidat/psutil/tree/osx_sensors.
I implemented sensors_temperatures, sensors_battery and sensors_fans functions. This is mostly working except for some error handling which I need to fix before submitting this as a pull request. The interface is a little different than Linux's because we don't have "label", "high" and "critical" for the temperatures and fans... I don't know if this looks good.

In [1]: import psutil

In [2]: psutil.sensors_fans()
Out[2]: {'Fan 0': sfan(current=1292.0)}

In [3]: psutil.sensors_temperatures()
Out[3]: {'Battery': shwtemp(current=29.59765625), 'CPU': shwtemp(current=53.625)}

In [4]: psutil.sensors_battery()
Out[4]: sbattery(percent=100, secsleft=-2, power_plugged=True)

Great work! Some considerations:

  • I marked sensors_ APIs as "experimental" so we have the flexibility to change them.
  • first thing I'd change (on Linux) is to move current field in position 0 because it's always supposed to be there. This should happen in a major release (I'll do that).
  • There's the question whether to return a a different namedtuple on OSX or the same one with null values. Hard to tell at this point. Adding support for Windows and seeing how things are down there would help clear things up. FWIW this shows there are min and max values on Windows, which is cool, but maybe min is different than high provided by psutil on Linux. Since we're not sure yet I think keeping the same nametuple and set None values is safer at this point.
  • We can drop "experimental" status for sensors_temperatures and sensors_fans once we have the Windows implementation. That will tell us how the final APIs should look like. Any chance you could do this on Windows as well? ;-)

I created a separate namedtuple for OSX for now, however the interface still doesn't look good. On Linux, every key in the returned dict returns a list of temperatures, while on OSX we only have one temperature per component.
Current return value, I think doesn't look very good: {'Battery': [shwtemp(current=34.09765625)], 'CPU': [shwtemp(current=61.75)]}
Maybe this will make more sense? [shwtemp(name='Battery', current=34.09765625), shwtemp(name='CPU', current=61.75)]
There is a similar issue with sensors_fans. This makes the temperatures.py/fans.py/sensors.py scripts return confusing outputs:

$ scripts/sensors.py
Battery
    Temperatures:
        Battery              34.19921875 掳C
Fan 0
    Fans:
        Fan 0                1309.0 RPM
CPU
    Temperatures:
        CPU                  56.875 掳C
Battery:
    charge:     100.0%
    status:     fully charged
    plugged in: yes

Any chance you could do this on Windows as well? ;-)

I used to really like Windows API, but I don't think I'll have time to get into that :wink:

Maybe this will make more sense? [shwtemp(name='Battery', current=34.09765625), shwtemp(name='CPU', current=61.75)]

No because sensors_temperatures on Linux returns a dict, not a list. We should keep returning a dict. The same structure will make sense on Windows (see the screenshots here: http://openhardwaremonitor.org/).

Information about sensors on OSX in general:
Apparently there are A LOT of sensors that Apple's SMC reports. This tool can list them:
https://github.com/theopolis/smc-fuzzer
Here is an output from a MacBook Pro:
https://gist.github.com/wiggin15/5b86bf1bfd1c175329c33c2da87049c7
Unfortunately the meanings are not publicly documented. There is a partial list of meanings here: https://stackoverflow.com/a/31033665/1739101 .
There is also a tool called iStat Menus that lists many of the sensor values. It looks like this: https://images.techhive.com/images/article/2013/05/istatmenus4_06-100039349-orig.png

The code in my branch decodes only a few of the values (battery temperature, cpu temperature, fan current speed) but maybe it can read more values (e.g. there are "min/max fan speed" values and more temperatures). There is also still the question about the interface(s). It doesn't look like the Linux interface matches here exactly.

@giampaolo the "sensors_battery" information uses a separate API that is documented and doesn't need the SMC. Would you be open to accepting a separate PR with this function implemented only?

@wiggin15 I'd recommend looking at SMCKit and iStats. They're both open source and pull from the SMC.

Thanks @JMY1000 . iStats only pulls a small subset of the codes (I already look at these codes in my branch - cpu temperature, battery temperature, fan speed). SMCKit pulls some more, but still far from all of the available list.
I'm wondering what temperatures are relevant to return from sensors_temperatures.

@wiggin15 The iStats that I linked is not the same as iStat Menus or iStat Pro鈥搃t's a Ruby gem that actually goes through every sensor AFAIK. Run istats scan to go through all the sensors.

@giampaolo the "sensors_battery" information uses a separate API that is documented and doesn't need the SMC. Would you be open to accepting a separate PR with this function implemented only?

Of course.

I'm wondering what temperatures are relevant to return from sensors_temperatures.

Most important ones are CPUs. I wouldn't mind other sensors for now. E.g. voltages don't exist at all in psutil. It would be nice to have CPU min / max limits though, because they are useful to implement apps which emit alarms. It sucks these APIs are so poorly documented.

@giampaolo, I have been looking for a solution to this issue. Is there any way to know the critical or high values of the CPU temperature? I have not seen any way to probe this information in any of the sources mentioned above. If not, should it be just left blank, or set to 105 C, which is usually the critical temperature for Intel CPUs

sensors_temperatures() currently is not implemented on OSX. I didn't implement it because my virtualized OSX box does not have any temperature. Pull requests are welcome though. =)

@amanusk Not sure how you'd define what high is, but it seems like critical should be when it starts throttling.

For Intel processors at least, you could pull the TJMAX from ARK, but there's got to be a better way of getting that info. I don't think it's baked into the CPUID info unfortunately.

sensors_temperatures() currently is not implemented on OSX. I didn't implement it because my
virtualized OSX box does not have any temperature. Pull requests are welcome though. =)

@giampaolo I have noticed it is not implemented ;), I might be able to work on it if I get access to hardware. My question is, whether you know of a method to get high and critical metrics in macOS (similar to lmsensors), and how would you want this handled if there is no way to obtain these.

@JMY1000

Not sure how you'd define what high is, but it seems like critical should be when it starts throttling.

In lmsensors, high is the temperature when throttling starts, and cirtical is when the system shuts down. I was hoping there is a way to obtain these metrics from software, similar to Linux, and not by cross referencing with ARK for each CPU model.

@amanusk Gotcha. If you'd be interested, I think I could set up access to hardware over ssh or something. Seems like @wiggin15 hasn't touched his stuff in a while. I'd also be happy to help.

Not sure how to obtain that info. The official Intel Power Gadget seems to rely on a kext, but I'm not sure how it's grabbing the info below that. sysctl hw.cpufrequency seems to be entirely static, just reporting whatever your CPU is manufactured to run at.

I compiled a list of all the temperature sensors accessible via the SMC

| SMC Code | Name |
|----------|-------|
|TA0P|Ambient|
|TA0S|PCI Slot 1 Pos 1|
|TA1P|Ambient temperature|
|TA1S|PCI Slot 1 Pos 2|
|TA2S|PCI Slot 2 Pos 1|
|TA3S|PCI Slot 2 Pos 2|
|TB0P|BLC Proximity|
|TB0T|Battery TS_MAX|
|TB1T|Battery 1|
|TB2T|Battery 2|
|TB3T|Battery 3|
|TC_C|CPU Core _|
|TC_D|CPU _ Die|
|TC_E|CPU _ ??|
|TC_F|CPU _ ??|
|TC_G|CPU _ ??|
|TC_H|CPU _ Heatsink|
|TC_J|CPU _ ??|
|TC_P|CPU _ Proximity|
|TCGC|PECI GPU|
|TCSA|PECI SA|
|TCSC|PECI SA|
|TCXC|PECI CPU|
|TG_D|GPU _ Die|
|TG_H|GPU _ Heatsink|
|TG_P|GPU _ Proximity|
|TH_H|Heatsink _ Proximity|
|TH_P|HDD _ Proximity|
|TI_P|Thunderbolt _|
|TL_P|LCD _ Proximity|
|TL_P|LCD _|
|TM_P|Memory _ Proximity|
|TM_S|Memory Slot _|
|TMA_|DIMM A ?|
|TMB_|DIMM B ?|
|TN_D|Northbridge _ Die|
|TN_H|Northbridge _ Heatsink|
|TN_P|Northbridge _ Proximity|
|TO_P|Optical Drive _ Proximity|
|TP_C|Power Supply _|
|TP_P|Power Supply _ Proximity|
|TS_C|Expansion Slot _|
|TS_P|Palm Rest _|
|TS0C|Expansion slots|
|TS0S|Memory Bank Proximity|
|TW0P|AirPort Proximity|

Note the underscores indicating the possibility of multiple sensors. These values will need to be scanned in a smart manner.

Hoping to work on that PR some time in the next few months :/

Was this page helpful?
0 / 5 - 0 ratings