70

I need to gather some system information for the application I'm developing. The memory available and the CPU load are easy to get using C#. Unfortunately, the CPU temperature it's not that easy. I have tried using WMI, but I couldn't get anything using

Win32_TemperatureProbe

or

MSAcpi_ThermalZoneTemperature

How can I do this? I'm wondering how monitoring programs, as SiSoftware Sandra, can get that information...

Here is the code of the class:

public class SystemInformation
{
    private System.Diagnostics.PerformanceCounter m_memoryCounter;
    private System.Diagnostics.PerformanceCounter m_CPUCounter;

    public SystemInformation()
    {
        m_memoryCounter = new System.Diagnostics.PerformanceCounter();
        m_memoryCounter.CategoryName = "Memory";
        m_memoryCounter.CounterName = "Available MBytes";

        m_CPUCounter = new System.Diagnostics.PerformanceCounter();
        m_CPUCounter.CategoryName = "Processor";
        m_CPUCounter.CounterName = "% Processor Time";
        m_CPUCounter.InstanceName = "_Total";
    }

    public float GetAvailableMemory()
    {
        return m_memoryCounter.NextValue();
    }

    public float GetCPULoad()
    {
        return m_CPUCounter.NextValue();
    }

    public float GetCPUTemperature()
    {
        //...
        return 0;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
yeyeyerman
  • 7,751
  • 7
  • 43
  • 52
  • If you are willing to pay i would look into http://www.cpuid-pro.com if i remember correctly its the same library that `z-cpu` uses.. – Peter Jan 15 '15 at 07:49

9 Answers9

78

For others who may come by here, maybe take a look at : http://openhardwaremonitor.org/

Follow that link and at first you might think, "Hey, that's an application, and that is why it was removed. The question was how to do this from C# code, not to find an application that can tell me the temperature..." This is where it shows you are not willing to invest enough time in reading what "Open Hardware Monitor" also is.

They also include a data interface. Here is the description:

Data Interface The Open Hardware Monitor publishes all sensor data to WMI (Windows Management Instrumentation). This allows other applications to read and use the sensor information as well. A preliminary documentation of the interface can be found here (click).

When you download it, it contains the OpenHardwareMonitor.exe application, and you're not looking for that one. It also contains the OpenHardwareMonitorLib.dll, and you're looking for that one.

It is mostly, if not 100%, just a wrapper around the WinRing0 API, which you could choose to wrap yourself if you feel like it.

I have tried this out from a C# application myself, and it works. Although it was still in beta, it seemed rather stable. It is also open source, so it could be a good starting point instead.


Update as of 2023-06-26

As noted in the comments, it looks like the project is no longer maintained, but that there is a maintained fork here:

https://github.com/LibreHardwareMonitor/LibreHardwareMonitor

Jens
  • 3,353
  • 1
  • 23
  • 27
  • 1
    Can you link any documentation about usage of the OpenHardware Lib? I can't seem to find out how to use this in my project. – Chris Watts Mar 24 '12 at 10:41
  • Unfortunetly not, I used plain old "discovery" to find the things I needed... But what do you have problems with?... At it's very basic it is instantiating the "Computer" class and then just work on from there... (e.g. Computer -> IHardware -> ISensors) Alternatively download the source from their SVN repository and try to figure their own GUI out, personally I didn't have that big of an issue to just discover things, but if your missing something specific it could maybe be? – Jens Mar 26 '12 at 11:02
  • And with figuring out their GUI, i mean as a source for inspiration to how you get access the the various different sensors and so on... And then replicate that usage in your own project. – Jens Mar 26 '12 at 11:10
  • This really helped. Found here much more than I was even looking for. Thank you. – Ivan Peric Jan 17 '14 at 17:39
  • That project is dead. LibreHardwareMonitor is the living fork of that. – Carsten Jun 24 '23 at 18:24
  • @Carsten Cheers, I added a link to LibreHardwareMonitor now – Jens Jun 28 '23 at 11:55
39

You can indeed read the CPU temperature very easily in C# by using a WMI approach.

To get the temperature in Celsius, I have created a wrapper that converts the value returned by WMI and wraps it into an easy-to-use object.

Please remember to add a reference to the System.Management.dll in Visual Studio.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;

namespace RCoding.Common.Diagnostics.SystemInfo
{
    public class Temperature
    {
        public double CurrentValue { get; set; }
        public string InstanceName { get; set; }
        public static List<Temperature> Temperatures
        {
            get
            {
                List<Temperature> result = new List<Temperature>();
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"root\WMI", "SELECT * FROM MSAcpi_ThermalZoneTemperature");
                foreach (ManagementObject obj in searcher.Get())
                {
                    Double temperature = Convert.ToDouble(obj["CurrentTemperature"].ToString());
                    temperature = (temperature - 2732) / 10.0;
                    result.Add(new Temperature { CurrentValue = temperature, InstanceName = obj["InstanceName"].ToString() });
                }
                return result;
            }
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lasse Rasch
  • 423
  • 4
  • 2
22

I'm pretty sure it's manufacturer dependent, since they will be accessed through an I/O port. If you have a specific board you're trying to work with, try looking through the manuals and/or contacting the manufacturer.

If you want to do this for a lot of different boards, I'd recommend contacting someone at something like SiSoftware or be prepared to read a lot of motherboard manuals.

As another note, not all boards have temperature monitors.

You also might run into problems getting privileged access from the kernel.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
samoz
  • 56,849
  • 55
  • 141
  • 195
12

You can give the Open Hardware Monitor a go, although it lacks support for the latest processors.

internal sealed class CpuTemperatureReader : IDisposable
{
    private readonly Computer _computer;

    public CpuTemperatureReader()
    {
        _computer = new Computer { CPUEnabled = true };
        _computer.Open();
    }

    public IReadOnlyDictionary<string, float> GetTemperaturesInCelsius()
    {
        var coreAndTemperature = new Dictionary<string, float>();

        foreach (var hardware in _computer.Hardware)
        {
            hardware.Update(); //use hardware.Name to get CPU model
            foreach (var sensor in hardware.Sensors)
            {
                if (sensor.SensorType == SensorType.Temperature && sensor.Value.HasValue)
                    coreAndTemperature.Add(sensor.Name, sensor.Value.Value);
            }
        }

        return coreAndTemperature;
    }

    public void Dispose()
    {
        try
        {
            _computer.Close();
        }
        catch (Exception)
        {
            //ignore closing errors
        }
    }
}

Download the ZIP file from the official source, extract and add a reference to file OpenHardwareMonitorLib.dll in your project.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ali Zahid
  • 1,329
  • 2
  • 17
  • 23
6

I extracted the CPU part from Open Hardware Monitor into a separate library, exposing sensors and members normally hidden into OHM.

It also includes many updates (like the support for Ryzen and Xeon) because on Open Hardware Monitor (OHM) they haven't accepted pull requests since 2015.

https://www.nuget.org/packages/HardwareProviders.CPU.Standard/

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
TheQult
  • 364
  • 1
  • 3
  • 14
  • On the project site displayed on the page :) https://github.com/matteofabbri/HardwareProviders – TheQult Jun 07 '18 at 06:17
  • 1
    unfortunately this lib has a lot of compatibility issues, for instance on a i7-9700k which has no HT, it throws an exception when trying to discover CPU's – Wobbles Jun 13 '19 at 12:34
  • There is a more up to date version of OpenHardwareMonitorLib.dll here: https://github.com/BrsVgl/PerformanceEfficiencySuite This really helped me with a Jasper Lake CPU which wouldn't show CPU temp on the original 0.9.6.0 version of the .dll – sergeantKK Jan 27 '22 at 10:05
4

It's depends on if your computer supports WMI. My computer can't run this WMI demo either.

But I successfully get the CPU temperature via Open Hardware Monitor. Add the Openhardwaremonitor reference in Visual Studio. It's easier. Try this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenHardwareMonitor.Hardware;

namespace Get_CPU_Temp5
{
   class Program
   {
       public class UpdateVisitor : IVisitor
       {
           public void VisitComputer(IComputer computer)
           {
               computer.Traverse(this);
           }

           public void VisitHardware(IHardware hardware)
           {
               hardware.Update();
               foreach (IHardware subHardware in hardware.SubHardware) subHardware.Accept(this);
           }

           public void VisitSensor(ISensor sensor) { }
           public void VisitParameter(IParameter parameter) { }
       }

       static void GetSystemInfo()
       {
           UpdateVisitor updateVisitor = new UpdateVisitor();
           Computer computer = new Computer();
           computer.Open();
           computer.CPUEnabled = true;
           computer.Accept(updateVisitor);
           for (int i = 0; i < computer.Hardware.Length; i++)
           {
               if (computer.Hardware[i].HardwareType == HardwareType.CPU)
               {
                   for (int j = 0; j < computer.Hardware[i].Sensors.Length; j++)
                   {
                       if (computer.Hardware[i].Sensors[j].SensorType == SensorType.Temperature)
                               Console.WriteLine(computer.Hardware[i].Sensors[j].Name + ":" + computer.Hardware[i].Sensors[j].Value.ToString() + "\r");
                   }
               }
           }
           computer.Close();
       }

       static void Main(string[] args)
       {
           while (true)
           {
               GetSystemInfo();
           }
       }
   }
}

You need to run this demo as an administrator.

You can see the tutorial in Using Open Hardware Monitor to get CPU temperature in C# and make a fan cooling system.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
haoming weng
  • 129
  • 1
  • 2
4

The mentioned WMI classes were not working for me in the latest version of Windows 10.

On my Dell laptop I could get the CPU temperature in Celsius like this via PowerShell:

$data = Get-WMIObject -Query "SELECT * FROM Win32_PerfFormattedData_Counters_ThermalZoneInformation" -Namespace "root/CIMV2"
@($data)[0].HighPrecisionTemperature
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Carsten
  • 1,612
  • 14
  • 21
  • What is the underlying interface? [COM](https://en.wikipedia.org/wiki/Component_Object_Model)? [.NET](https://en.wikipedia.org/wiki/.NET_Framework)? I *imagine* it would possible in many other languages than just PowerShell. – Peter Mortensen Jun 11 '21 at 17:09
3

It can be done in your code via WMI. I've found a tool (WMI Code Creator v1.0) from Microsoft that creates code for it.

The WMI Code Creator tool allows you to generate VBScript, C#, and VB .NET code that uses WMI to complete a management task such as querying for management data, executing a method from a WMI class, or receiving event notifications using WMI.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jet
  • 528
  • 6
  • 17
1

Since there are more and more CPU/Chip combinations it needs a clever matrix to check all possible combinations to identify the temperature data. You really need an external DLL like "LibreHardwareMonitorLib.dll" to get this solved. The project files are availabe here

Based on this, a Powershell-solution could look like this:

#Requires -RunAsAdministrator

cls
$dll = "LibreHardwareMonitorLib.dll"

Unblock-File -LiteralPath $dll
Add-Type -LiteralPath $dll
$monitor = [LibreHardwareMonitor.Hardware.Computer]::new()
$monitor.IsCPUEnabled = $true

$monitor.Open()
[int]$temp = foreach ($sensor in $monitor.Hardware.Sensors) {
    if ($sensor.SensorType -eq 'Temperature' -and $sensor.Name -eq 'Core Average'){
        $sensor.Value
        break
    }
}
$monitor.Close()
write-host "CPU-Package Temperature = $temp°C" -f y 
Carsten
  • 1,612
  • 14
  • 21