#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 UdpSender udp = new UdpSender(); private readonly Computer computer = new Computer(); private IHardware? cpuHw; private IHardware? gpuHw; private IHardware? memHw; private ISensor[] cpuLoadSensors = Array.Empty(); 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() { computer.IsCpuEnabled = true; computer.IsGpuEnabled = true; computer.IsMemoryEnabled = true; 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(); 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; } } public void UpdateAndSend() { cpuHw?.Update(); gpuHw?.Update(); memHw?.Update(); float cpu = GetCpuLoadPercent(); float cpuTemp = GetCpuTemperaturePercent(); float mem = GetMemoryUsagePercent(); float gpu3d = GetGpu3DLoad(); float gpuTemp = GetGpuTemperaturePercent(); float vram = GetGpuVramPercent(); float[] packet = { cpu, cpuTemp, mem, gpu3d, gpuTemp, vram, 0f, 0f }; udp.SendFloats(packet); } 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() { udp.Dispose(); computer.Close(); } }