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;
}
}
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.
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;
}
}
}
}
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.
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.
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/
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.
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
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.
Related
It's a couple of days since I try to connect in any way with the Agora.io SDK in Unity.
I'm new to Agora and I just started to learn how to use it, I tried basically ALL tutorials to learn how to use the SDK and I cannot make it work in any way.
Here are the steps I did:
Created a new Agora account
Created new appID (tried both with and without the token)
Created a new empty project in unity
Imported from the asset store the SDK
Set the appID and if asked the token (depends if the project was the empty project or the example project on GitHub)
Tried to connect/join the channel
Get errors like:
Warning code:104 msg:lookup channel timed out (server no response)
Those are the tutorial I followed:
https://www.youtube.com/watch?v=uxIQOZr6RiU
https://www.agora.io/en/blog/agora-video-sdk-for-unity-quick-start-programming-guide/
https://docs.agora.io/en/Video/start_call_unity?platform=Unity
https://docs.agora.io/en/Video/run_demo_video_call_unity?platform=Unity
https://medium.com/agora-io/how-to-create-a-video-chat-app-in-unity-26780b479a78
https://www.agora.io/en/blog/how-to-embed-group-video-chat-in-your-unity-games/?utm_source=twitter&utm_medium=social&utm_campaign=embed-group-videochat-into-unity
This is really frustrating, I really don't know what else I can do. Also, I tried to open the firewall ports on my PC or disable the antivirus with no luck. (with the same version of Unity in another project I use Mirror and it works, nothing is blocking it)
Here the tutorial code I followed if it could be useful:
using agora_gaming_rtc;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace Agora_tutorial
{
public class AgoraChat : MonoBehaviour
{
public string AppID;
public string ChannelName;
VideoSurface myView;
VideoSurface remoteView;
IRtcEngine mRtcEngine;
void Awake()
{
SetupUI();
}
void Start()
{
SetupAgora();
}
void SetupUI()
{
GameObject go = GameObject.Find("MyView");
myView = go.AddComponent<VideoSurface>();
go = GameObject.Find("JoinButton");
if (go != null)
{
Button objectButton = go.GetComponent<Button>();
objectButton.onClick.AddListener(Join);
}
go = GameObject.Find("LeaveButton");
if (go != null)
{
Button objectButton = go.GetComponent<Button>();
objectButton.onClick.AddListener(Leave);
}
}
void SetupAgora()
{
mRtcEngine = IRtcEngine.GetEngine(AppID);
// Callbacks for the local user
mRtcEngine.OnJoinChannelSuccess = OnJoinChannelSuccessHandler; // When the local user joins the channel successfully
mRtcEngine.OnLeaveChannel = OnLeaveChannelHandler; // When the local user leaves the channel
// Callbacks for the remote users
mRtcEngine.OnUserJoined = OnUserJoined; // When the remote user joins the channel
mRtcEngine.OnUserOffline = OnUserOffline; // When the remote user leaves the channel
}
public void Join()
{
Debug.Log($"Joining");
mRtcEngine.EnableVideo();
mRtcEngine.EnableVideoObserver();
myView.SetEnable(true);
mRtcEngine.JoinChannel(ChannelName, "", 0);
}
public void Leave()
{
Debug.Log($"Leaving");
mRtcEngine.LeaveChannel();
mRtcEngine.DisableVideo();
mRtcEngine.DisableVideoObserver();
}
private void OnJoinChannelSuccessHandler(string channelName, uint uid, int elapsed)
{
// can add other logics here, for now just print to the log
Debug.LogFormat("Joined channel {0} successful, my uid = {1}", channelName, uid);
}
void OnLeaveChannelHandler(RtcStats stats)
{
// Turn off the rendering, otherwise, the last frame of the camera video will stay on the RawImage.
myView.SetEnable(false);
if (remoteView != null)
{
remoteView.SetEnable(false);
}
}
void OnUserJoined(uint uid, int elapsed)
{
GameObject go = GameObject.Find("RemoteView");
if (remoteView == null)
{
remoteView = go.AddComponent<VideoSurface>();
}
remoteView.SetForUser(uid);
remoteView.SetEnable(true);
remoteView.SetVideoSurfaceType(AgoraVideoSurfaceType.RawImage);
remoteView.SetGameFps(30);
}
void OnUserOffline(uint uid, USER_OFFLINE_REASON reason)
{
remoteView.SetEnable(false);
}
void OnApplicationQuit()
{
if (mRtcEngine != null)
{
IRtcEngine.Destroy();
mRtcEngine = null;
}
}
}
}
But when I press the join button there is only a call of the button(Join method) and the callback OnJoinChannelSuccessHandler is not called.
Thanks for reaching out.
First things first, let's get the basic demo running.
Create a new Unity project, downloading the Agora Video SDK, and starting with our base demo project.
Import the SDK to Unity, and navigate to Assets > AgoraEngine > Demo > SceneHome. You have everything you need to get started, you just need to add your AppID to the GameController object > TestHome script.
Select File > Build Settings... and add SceneHome(0) and SceneHelloVideo(1) to the Scenes In Build section (this is most likely where things went wrong).
Once you get that working:
Try checking out this Github Repo. It will take you to a multitude of projects that you can use to get started.
You'll be an Agora pro in no time!
I have usbasp programmer for AVR microcontrollers. This programmer uses libusb library. I've managed to connect it to pc, system detected new device and I managed to install driver for this device. It works well since I'm able to program AVR chips with it. So hardware part is 100% OK.
Now software part:
Using simple iterating over my libusb-win32 devices using LibUsbDotNet I find 2 devices. Both of them are named the same (and have same VID and PID) so I think this is composite device. Second one has some data in it. This is well shown on screenshots bellow.
And the code (it is just copy pasted from the examples)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LibUsbDotNet;
using LibUsbDotNet.Info;
using LibUsbDotNet.Main;
namespace USB_Test_CLI_CS {
class Program {
public static readonly int VendorID = 0x16C0;
public static readonly int ProductID = 0x05DC;
public static void Main(string[] args) {
UsbDevice usbDevice = null;
UsbRegDeviceList allDevices = UsbDevice.AllDevices;
Console.WriteLine("Found {0} devices", allDevices.Count);
foreach (UsbRegistry usbRegistry in allDevices) {
Console.WriteLine("Got device: {0}\r\n", usbRegistry.FullName);
if (usbRegistry.Open(out usbDevice)) {
Console.WriteLine("Device Information\r\n------------------");
Console.WriteLine("{0}", usbDevice.Info.ToString());
Console.WriteLine("VID & PID: {0} {1}", usbDevice.Info.Descriptor.VendorID, usbDevice.Info.Descriptor.ProductID);
Console.WriteLine("\r\nDevice configuration\r\n--------------------");
foreach (UsbConfigInfo usbConfigInfo in usbDevice.Configs) {
Console.WriteLine("{0}", usbConfigInfo.ToString());
Console.WriteLine("\r\nDevice interface list\r\n---------------------");
IReadOnlyCollection<UsbInterfaceInfo> interfaceList = usbConfigInfo.InterfaceInfoList;
foreach (UsbInterfaceInfo usbInterfaceInfo in interfaceList) {
Console.WriteLine("{0}", usbInterfaceInfo.ToString());
Console.WriteLine("\r\nDevice endpoint list\r\n--------------------");
IReadOnlyCollection<UsbEndpointInfo> endpointList = usbInterfaceInfo.EndpointInfoList;
foreach (UsbEndpointInfo usbEndpointInfo in endpointList) {
Console.WriteLine("{0}", usbEndpointInfo.ToString());
}
}
}
usbDevice.Close();
}
Console.WriteLine("\r\n----- Device information finished -----\r\n");
}
Console.WriteLine("Trying to find our device: {0} {1}", VendorID, ProductID);
UsbDeviceFinder usbDeviceFinder = new UsbDeviceFinder(VendorID, ProductID);
// This does not work !!! WHY ?
usbDevice = UsbDevice.OpenUsbDevice(usbDeviceFinder);
if (usbDevice != null) {
Console.WriteLine("OK");
} else {
Console.WriteLine("FAIL");
}
UsbDevice.Exit();
Console.Write("Press anything to close");
Console.ReadKey();
}
}
}
Here's output of this program
Found 2 devices
Got device: Van Ooijen Technische Informatica - USBasp
----- Device information finished -----
Got device: Van Ooijen Technische Informatica - USBasp
Device Information
------------------
Length:18
DescriptorType:Device
BcdUsb:0x0110
Class:VendorSpec
SubClass:0x00
Protocol:0x00
MaxPacketSize0:8
VendorID:0x16C0
ProductID:0x05DC
BcdDevice:0x0103
ManufacturerStringIndex:1
ProductStringIndex:2
SerialStringIndex:0
ConfigurationCount:1
ManufacturerString:www.fischl.de
ProductString:USBasp
SerialString:
VID & PID: 5824 1500
Device configuration
--------------------
Length:9
DescriptorType:Configuration
TotalLength:18
InterfaceCount:1
ConfigID:1
StringIndex:0
Attributes:0x80
MaxPower:25
ConfigString:
Device interface list
---------------------
Length:9
DescriptorType:Interface
InterfaceID:0
AlternateID:0
EndpointCount:0
Class:PerInterface
SubClass:0x00
Protocol:0x00
StringIndex:0
InterfaceString:
Device endpoint list
--------------------
----- Device information finished -----
Trying to find our device: 5824 1500
FAIL
Press anything to close
What I'd like to get is this simple code to detect this device which IS present (since simple iteration over all devices finds it and other tool "USB Cfg Interrogator" find it too).
This has been asked before but there were no constructive answer.
I also could use libusb-win32 c++ library and create some C# wrappers for it but if it is not needed and I can use LibUsbDotNet library I'd like to use it instead of creating wrappers myself.
What I'd like to get is this simple code to detect this device which IS present
You almost have that already. There is only one for which usbRegistry.Open() actually works.
There should be no other device - check that your use latest libusb-win32 version (1.2.6.0 at this time).
UsbDeviceFinder seems to have a problem with this phantom device.
You may try filter wizard to install device filter.
So I've been trying to get the temperature of my CPU using WMI for some time now. Of the two machines I've tested on, the one with an intel processor and Windows 7 runs just fine, where the one with an AMD processor and Windows 8.1 fails. I'm using a simple snippet that I found on another question, but the question was old and there was no discussion of Windows 8/8.1. Here is the snippet:
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 temp = Convert.ToDouble(obj["CurrentTemperature"].ToString());
temp = (temp - 2732) / 10.0;
result.Add(new Temperature { CurrentValue = temp, InstanceName = obj["InstanceName"].ToString() });
}
return result;
}
}
}
As soon as I call searcher.Get() though, it causes a ManagementException with the message "Not Supported."
I know that I have all the necessary hardware requirements, as other tools (Core temp and Speccy) will return the temperature just fine.
In addition to this, I've also started researching Win32_TemperatureProbe but that hasn't panned out. If anyone knows of good reference material for that, I would greatly appreciate it if you would share.
Edit: I'm trying this on Windows 8.1 x64 with .NET 3.5. The processor is an AMD FX8350 and it's hooked up to a Gigabyte GA-990FXA-UD3 Motherboard.
This is the code im calling the method in my Form1 constructor:
private void cpuFanSpeed()
{
SelectQuery query =
new SelectQuery("Win32_Fan");
// Instantiate an object searcher
// with this query
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(query);
// Call Get() to retrieve the collection
// of objects and loop through it
foreach (ManagementObject envVar in searcher.Get())
MessageBox.Show(envVar["DesiredSpeed"].ToString());
}
But it's never get to the MessageBox.
What is wrong here ? I tried to read and doing it by the document here: http://msdn.microsoft.com/en-us/library/aa394146(v=vs.85).aspx
And here: http://msdn.microsoft.com/en-us/library/ms257359.aspx
But it's not working.
I want to display my cpu fan speed every second on a label.
This is a screenshot of OpenHardwareMonitor display my cpu fan speed:
And this is the code the function im using in my application to get the CPU temperature:
In class:
public static float? cpuView(bool pause , CpuTemperature cpuTemp , Form1 f1 , List<string> myData , float? myCpuTemp , Button b1)
{
if (pause == true)
{
}
else
{
Computer myComputer = new Computer();
myComputer = new Computer(cpuTemp)
{
CPUEnabled =
true
};
myComputer.Open();
Trace.WriteLine("");
foreach (var hardwareItem in myComputer.Hardware)
{
if (hardwareItem.HardwareType == HardwareType.CPU)
{
hardwareItem.Update();
foreach (IHardware subHardware in hardwareItem.SubHardware)
subHardware.Update();
foreach (var sensor in hardwareItem.Sensors)
{
cpuTemp.SetValue("sensor", sensor.Value.ToString());
if (sensor.SensorType == SensorType.Temperature)
{
sensor.Hardware.Update();
cpuTemp.GetValue("sensor", sensor.Value.ToString());
f1.Invoke(new Action(() => myData.Add("Cpu Temeprature --- " + sensor.Value.ToString())));
myCpuTemp = sensor.Value;
if (sensor.Value > 60)
{
Logger.Write("The Current CPU Temperature Is ===> " + sensor.Value);
b1.Enabled = true;
}
break;
}
}
}
}
}
return myCpuTemp;
}
Not every machine provides this information through WMI. If your computer doesn't, you won't be able to access it. Just because WMI provides a property to access a particular piece of information doesn't mean that information will always be available.
Presumably, the collection you're iterating through in the foreach loop is empty, which is why no MessageBox ever gets displayed.
The only possible fix for this problem would be to obtain an updated driver from your motherboard manufacturer that provides WMI with this information (assuming, of course, that your hardware even includes the sensors required to measure this type of thing in the first place).
Edit: Open Hardware Monitor has apparently written its own drivers to interact directly with your hardware, querying its sensors. This suspicion is confirmed by perusing their web page, which documents specific pieces of hardware that it supports.
It's not using WMI to obtain its information, so this doesn't prove that you'll be able to obtain the information from WMI yourself.
However, the bottom of the above-linked page does contain this interesting remark:
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.
So it appears that you can piggyback on top of Open Hardware Monitor, using its drivers to retrieve information, and then retrieve that information from it inside of your app. That's probably the best solution, since I doubt your hardware manufacturer is going to come through with an updated driver that provides the fan speed to WMI.
My Friend asked me to write a program to limit the Internet usage to 40 Mb per day. If the 40 Mb of daily quota is reached no other programs in the system must be able to access the Internet.
You need to monitor the network activity. One can use IPGlobalProperties class for that.
Keep in mind that the statistics are reseted each time the connection is lost so you'll have to store them somewhere.
You need to disable internet connection, see Code to enable/disable internet connectivity
Tell him you wrote a program, but instead hire a guy to watch his internet usage, and pull out the plug when the limit is hit.
EDIT: Apparently my sense of humor is off.
Anyway I think this would be quite an undertaking, I could not find any code for it. But I did find this Net Limiter
Yes.
More of a proof of concept than a working solution.
using System;
using System.Linq;
using System.Threading;
using System.Net.NetworkInformation;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
const double ShutdownValue = 40960000D;
const string NetEnable = "interface set interface \u0022{0}\u0022 DISABLED";
const string NetDisable = "interface set interface \u0022{0}\u0022 ENABLED";
double Incoming = 0;
double Outgoing = 0;
double TotalInterface;
string SelectedInterface = "Local Area Connection";
NetworkInterface netInt = NetworkInterface.GetAllNetworkInterfaces().Single(n => n.Name.Equals(SelectedInterface));
for (; ; )
{
IPv4InterfaceStatistics ip4Stat = netInt.GetIPv4Statistics();
Incoming += (ip4Stat.BytesReceived - Incoming);
Outgoing += (ip4Stat.BytesSent - Outgoing);
TotalInterface = Incoming + Outgoing;
string Shutdown = ((TotalInterface > ShutdownValue) ? "YES" : "NO");
if (Shutdown == "YES")
{
System.Diagnostics.Process.Start("netsh", string.Format(NetDisable, SelectedInterface));
}
string output = string.Format("Shutdown: {0} | {1} KB/s", Shutdown, TotalInterface.ToString());
Console.WriteLine(output);
Thread.Sleep(3000);
}
}
}
}
This should be doable in a router or with cFosSpeed which also provides quotas, however I do now know any freeware/open-source applications that already do this.
For writing it yourself you'd have to somehow keep count of the amount of data sent so far, and if multiple computers are on the same network it's going to be even harder to keep track of.