243 lines
6.4 KiB
C#
243 lines
6.4 KiB
C#
#nullable enable
|
|
|
|
using System;
|
|
using System.Globalization;
|
|
using LibreHardwareMonitor.Hardware;
|
|
|
|
public class Telemetry : IDisposable
|
|
{
|
|
private const int UpdateRateDefaultMs = 1000;
|
|
public int UpdateRateMs => UpdateRateDefaultMs;
|
|
|
|
private readonly SerialManager serial = new SerialManager();
|
|
private readonly Computer computer = new Computer();
|
|
|
|
// Cached hardware references
|
|
private IHardware? cpuHw;
|
|
private IHardware? gpuHw;
|
|
private IHardware? memHw;
|
|
|
|
// Cached sensors
|
|
private ISensor[] cpuLoadSensors = Array.Empty<ISensor>();
|
|
private ISensor? cpuTempSensor;
|
|
|
|
private ISensor? gpu3DLoadSensor;
|
|
private ISensor? gpuTempSensor;
|
|
private ISensor? gpuVramUsedSensor;
|
|
private ISensor? gpuVramTotalSensor;
|
|
|
|
private ISensor? memUsedSensor;
|
|
private ISensor? memAvailSensor;
|
|
|
|
private static readonly CultureInfo CI = CultureInfo.InvariantCulture;
|
|
|
|
public void Initialize()
|
|
{
|
|
serial.DiscoverDevice();
|
|
|
|
// Enable only what we need
|
|
computer.IsCpuEnabled = true;
|
|
computer.IsGpuEnabled = true;
|
|
computer.IsMemoryEnabled = true;
|
|
|
|
computer.IsMotherboardEnabled = false;
|
|
computer.IsControllerEnabled = false;
|
|
computer.IsNetworkEnabled = false;
|
|
computer.IsStorageEnabled = false;
|
|
computer.IsBatteryEnabled = false;
|
|
computer.IsPsuEnabled = false;
|
|
|
|
computer.Open();
|
|
|
|
CacheHardwareAndSensors();
|
|
}
|
|
|
|
private void CacheHardwareAndSensors()
|
|
{
|
|
foreach (var hw in computer.Hardware)
|
|
{
|
|
hw.Update();
|
|
|
|
switch (hw.HardwareType)
|
|
{
|
|
case HardwareType.Cpu:
|
|
cpuHw = hw;
|
|
CacheCpuSensors(hw);
|
|
break;
|
|
|
|
case HardwareType.GpuNvidia:
|
|
case HardwareType.GpuAmd:
|
|
case HardwareType.GpuIntel:
|
|
gpuHw = hw;
|
|
CacheGpuSensors(hw);
|
|
break;
|
|
|
|
case HardwareType.Memory:
|
|
memHw = hw;
|
|
CacheMemorySensors(hw);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CacheCpuSensors(IHardware hw)
|
|
{
|
|
var loads = new System.Collections.Generic.List<ISensor>();
|
|
|
|
foreach (var s in hw.Sensors)
|
|
{
|
|
if (s.SensorType == SensorType.Load &&
|
|
s.Name.Contains("CPU Core"))
|
|
loads.Add(s);
|
|
|
|
if (s.SensorType == SensorType.Temperature)
|
|
{
|
|
if (s.Name == "Core (Tctl/Tdie)")
|
|
cpuTempSensor = s;
|
|
else if (cpuTempSensor == null)
|
|
cpuTempSensor = s;
|
|
}
|
|
}
|
|
|
|
cpuLoadSensors = loads.ToArray();
|
|
}
|
|
|
|
private void CacheGpuSensors(IHardware hw)
|
|
{
|
|
foreach (var s in hw.Sensors)
|
|
{
|
|
if (s.SensorType == SensorType.Load)
|
|
{
|
|
if (s.Name == "D3D 3D")
|
|
gpu3DLoadSensor = s;
|
|
else if (gpu3DLoadSensor == null && s.Name == "GPU Core")
|
|
gpu3DLoadSensor = s;
|
|
}
|
|
|
|
if (s.SensorType == SensorType.Temperature)
|
|
{
|
|
if (s.Name == "GPU Core")
|
|
gpuTempSensor = s;
|
|
else if (gpuTempSensor == null)
|
|
gpuTempSensor = s;
|
|
}
|
|
|
|
if (s.SensorType == SensorType.SmallData)
|
|
{
|
|
if (s.Name == "GPU Memory Used")
|
|
gpuVramUsedSensor = s;
|
|
|
|
if (s.Name == "GPU Memory Total")
|
|
gpuVramTotalSensor = s;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CacheMemorySensors(IHardware hw)
|
|
{
|
|
foreach (var s in hw.Sensors)
|
|
{
|
|
if (s.SensorType == SensorType.Data && s.Name == "Memory Used")
|
|
memUsedSensor = s;
|
|
|
|
if (s.SensorType == SensorType.Data && s.Name == "Memory Available")
|
|
memAvailSensor = s;
|
|
}
|
|
}
|
|
|
|
private static string F(float v) => v.ToString("0.###", CI);
|
|
|
|
public void UpdateAndSend()
|
|
{
|
|
if (!serial.IsConnected)
|
|
{
|
|
serial.DiscoverDevice();
|
|
return;
|
|
}
|
|
|
|
if (serial.WatchdogExpired)
|
|
{
|
|
serial.DiscoverDevice();
|
|
return;
|
|
}
|
|
|
|
// Update only the hardware we need
|
|
cpuHw?.Update();
|
|
gpuHw?.Update();
|
|
memHw?.Update();
|
|
|
|
float cpu = GetCpuLoadPercent();
|
|
float cpuTemp = GetCpuTemperaturePercent();
|
|
float mem = GetMemoryUsagePercent();
|
|
float gpu3d = GetGpu3DLoad();
|
|
float gpuTemp = GetGpuTemperaturePercent();
|
|
float vram = GetGpuVramPercent();
|
|
|
|
string cmd =
|
|
$"SETALL: {F(cpu)},{F(cpuTemp)},{F(mem)},{F(gpu3d)},{F(gpuTemp)},{F(vram)},0,0";
|
|
|
|
serial.SendSetAll(cmd);
|
|
}
|
|
|
|
// ---------------- METRICS ----------------
|
|
|
|
private float GetCpuLoadPercent()
|
|
{
|
|
if (cpuLoadSensors.Length == 0) return 0;
|
|
|
|
float total = 0;
|
|
int count = 0;
|
|
|
|
foreach (var s in cpuLoadSensors)
|
|
{
|
|
total += s.Value ?? 0;
|
|
count++;
|
|
}
|
|
|
|
return count == 0 ? 0 : total / count;
|
|
}
|
|
|
|
private float GetCpuTemperaturePercent()
|
|
{
|
|
float t = cpuTempSensor?.Value ?? 0;
|
|
return Math.Clamp(t, 0, 100);
|
|
}
|
|
|
|
private float GetGpu3DLoad()
|
|
{
|
|
return gpu3DLoadSensor?.Value ?? 0;
|
|
}
|
|
|
|
private float GetGpuTemperaturePercent()
|
|
{
|
|
float t = gpuTempSensor?.Value ?? 0;
|
|
return Math.Clamp(t, 0, 100);
|
|
}
|
|
|
|
private float GetGpuVramPercent()
|
|
{
|
|
float used = gpuVramUsedSensor?.Value ?? 0;
|
|
float total = gpuVramTotalSensor?.Value ?? 0;
|
|
|
|
if (total <= 0) return 0;
|
|
return (used / total) * 100f;
|
|
}
|
|
|
|
private float GetMemoryUsagePercent()
|
|
{
|
|
float used = memUsedSensor?.Value ?? 0;
|
|
float avail = memAvailSensor?.Value ?? 0;
|
|
|
|
float total = used + avail;
|
|
if (total <= 0) return 0;
|
|
|
|
return (used / total) * 100f;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
serial.Dispose();
|
|
computer.Close();
|
|
}
|
|
}
|