Initial WIP commit
Some checks failed
Deploy to Gitea Releases / deploy-to-gitea-releases (push) Failing after 9s

This commit is contained in:
2026-01-27 18:58:09 -05:00
commit 853e8eab0d
45 changed files with 2920 additions and 0 deletions

41
Service/Hardware.cs Normal file
View File

@@ -0,0 +1,41 @@
namespace HardwareMonitorStatusWindow.Service;
public class Hardware
{
public required HardwareType Type { get; set; }
public required string Identifier { get; set; }
public required string Name { get; set; }
public required IEnumerable<Sensor> Sensors { get; set; }
internal static Hardware Create(LibreHardwareMonitor.Hardware.IHardware hardware)
{
return new Hardware
{
Type = MapHardwareType(hardware.HardwareType),
Name = hardware.Name,
Identifier = hardware.Identifier.ToString(),
Sensors = hardware.Sensors.Select(Sensor.Create)
};
}
private static HardwareType MapHardwareType(LibreHardwareMonitor.Hardware.HardwareType hardwareType)
{
return hardwareType switch
{
LibreHardwareMonitor.Hardware.HardwareType.Motherboard => HardwareType.Motherboard,
LibreHardwareMonitor.Hardware.HardwareType.SuperIO => HardwareType.SuperIo,
LibreHardwareMonitor.Hardware.HardwareType.Cpu => HardwareType.Cpu,
LibreHardwareMonitor.Hardware.HardwareType.Memory => HardwareType.Memory,
LibreHardwareMonitor.Hardware.HardwareType.GpuNvidia => HardwareType.GpuNvidia,
LibreHardwareMonitor.Hardware.HardwareType.GpuAmd => HardwareType.GpuAmd,
LibreHardwareMonitor.Hardware.HardwareType.GpuIntel => HardwareType.GpuIntel,
LibreHardwareMonitor.Hardware.HardwareType.Storage => HardwareType.Storage,
LibreHardwareMonitor.Hardware.HardwareType.Network => HardwareType.Network,
LibreHardwareMonitor.Hardware.HardwareType.Cooler => HardwareType.Cooler,
LibreHardwareMonitor.Hardware.HardwareType.EmbeddedController => HardwareType.EmbeddedController,
LibreHardwareMonitor.Hardware.HardwareType.Psu => HardwareType.Psu,
LibreHardwareMonitor.Hardware.HardwareType.Battery => HardwareType.Battery,
_ => throw new ArgumentOutOfRangeException(nameof(hardwareType), hardwareType, null)
};
}
}

View File

@@ -0,0 +1,41 @@
using LibreHardwareMonitor.Hardware;
namespace HardwareMonitorStatusWindow.Service;
public class HardwareMonitorService : IHardwareMonitorService
{
public const string ScheduledTaskName = "HardwareMonitorService";
public const string PipeName = "HardwareMonitorService";
private static readonly Computer Computer;
private static readonly HardwareUpdateVisitor HardwareUpdateVisitor;
static HardwareMonitorService()
{
Computer = new Computer
{
IsCpuEnabled = true,
IsGpuEnabled = true,
IsMemoryEnabled = true,
IsMotherboardEnabled = true,
IsControllerEnabled = true,
IsNetworkEnabled = true,
IsStorageEnabled = true,
IsBatteryEnabled = true,
IsPsuEnabled = true
};
Computer.Open();
HardwareUpdateVisitor = new HardwareUpdateVisitor();
}
public IEnumerable<Hardware> GetHardware()
{
Computer.Accept(HardwareUpdateVisitor);
var hardwareEntries = Computer.Hardware.Select(Hardware.Create);
return hardwareEntries;
}
}

View File

@@ -0,0 +1,26 @@
using PipeMethodCalls;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace HardwareMonitorStatusWindow.Service;
public class HardwarePipeSerializer : IPipeSerializer
{
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
{
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals
};
public object? Deserialize(byte[] data, Type type)
{
return JsonSerializer.Deserialize(data, type, JsonSerializerOptions);
}
public byte[] Serialize(object o)
{
using var memoryStream = new MemoryStream();
using var utf8JsonWriter = new Utf8JsonWriter(memoryStream);
JsonSerializer.Serialize(utf8JsonWriter, o, JsonSerializerOptions);
return memoryStream.ToArray();
}
}

18
Service/HardwareType.cs Normal file
View File

@@ -0,0 +1,18 @@
namespace HardwareMonitorStatusWindow.Service;
public enum HardwareType
{
Motherboard,
SuperIo,
Cpu,
Memory,
GpuNvidia,
GpuAmd,
GpuIntel,
Storage,
Network,
Cooler,
EmbeddedController,
Psu,
Battery,
}

View File

@@ -0,0 +1,25 @@
using LibreHardwareMonitor.Hardware;
namespace HardwareMonitorStatusWindow.Service;
internal class HardwareUpdateVisitor : IVisitor
{
public void VisitComputer(IComputer computer)
{
computer.Traverse(this);
}
public void VisitHardware(IHardware hardware)
{
hardware.Update();
foreach (var subHardware in hardware.SubHardware) subHardware.Accept(this);
}
public void VisitSensor(ISensor sensor)
{
}
public void VisitParameter(IParameter parameter)
{
}
}

View File

@@ -0,0 +1,6 @@
namespace HardwareMonitorStatusWindow.Service;
public interface IHardwareMonitorService
{
IEnumerable<Hardware> GetHardware();
}

111
Service/Program.cs Normal file
View File

@@ -0,0 +1,111 @@
using System.IO.Pipes;
using System.Security.AccessControl;
using System.Security.Principal;
using Microsoft.Win32.TaskScheduler;
using PipeMethodCalls;
using Serilog;
using Task = System.Threading.Tasks.Task;
namespace HardwareMonitorStatusWindow.Service;
internal class Program
{
private static async Task Main(string[] args)
{
Log.Logger = new LoggerConfiguration().WriteTo.File("log.txt").CreateLogger();
Log.Logger.Information("Start");
if (args.Contains("--install", StringComparer.InvariantCultureIgnoreCase))
{
Log.Logger.Information("Starting install...");
try
{
using var taskService = new TaskService();
var existingTask = taskService.FindTask(HardwareMonitorService.ScheduledTaskName);
if (existingTask == null)
{
var taskDefinition = taskService.NewTask();
taskDefinition.Principal.RunLevel = TaskRunLevel.Highest;
taskDefinition.Triggers.Add(new LogonTrigger { Delay = TimeSpan.FromSeconds(30) });
taskDefinition.Actions.Add(new ExecAction(Environment.ProcessPath!));
taskDefinition.Settings.RestartInterval = TimeSpan.FromMinutes(1);
taskDefinition.Settings.RestartCount = 3;
taskDefinition.Settings.StartWhenAvailable = true;
taskDefinition.Settings.ExecutionTimeLimit = TimeSpan.Zero;
taskDefinition.Settings.StopIfGoingOnBatteries = false;
taskDefinition.Settings.DisallowStartIfOnBatteries = false;
taskService.RootFolder.RegisterTaskDefinition(HardwareMonitorService.ScheduledTaskName, taskDefinition);
}
existingTask = taskService.FindTask(HardwareMonitorService.ScheduledTaskName);
existingTask.Run();
}
catch (Exception exception)
{
Log.Logger.Error(exception, "Install");
}
Log.Logger.Information("Install complete");
}
else if (args.Contains("--uninstall", StringComparer.InvariantCultureIgnoreCase))
{
Log.Logger.Information("Starting uninstall...");
try
{
using var taskService = new TaskService();
var existingTask = taskService.FindTask(HardwareMonitorService.ScheduledTaskName);
existingTask?.Stop();
taskService.RootFolder.DeleteTask(HardwareMonitorService.ScheduledTaskName, false);
}
catch (Exception exception)
{
Log.Logger.Error(exception, "Uninstall");
}
Log.Logger.Information("Uninstall complete");
}
else
{
Log.Logger.Information("Starting");
try
{
while (true)
{
var pipeSecurity = new PipeSecurity();
pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow));
var pipeWithSecurity = NamedPipeServerStreamAcl.Create(HardwareMonitorService.PipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 0, 0, pipeSecurity);
var pipeServer = new PipeServer<IHardwareMonitorService>(new HardwarePipeSerializer(), pipeWithSecurity, () => new HardwareMonitorService());
//var pipeServer = new PipeServer<IHardwareMonitorService>(
// new HardwarePipeSerializer(),
// HardwareMonitorService.PipeName,
// () => new HardwareMonitorService());
await pipeServer.WaitForConnectionAsync().ConfigureAwait(false);
await pipeServer.WaitForRemotePipeCloseAsync().ConfigureAwait(false);
pipeServer.Dispose();
}
}
catch (Exception exception)
{
Log.Logger.Error(exception, "");
}
}
Log.Logger.Information("Closing");
}
}

49
Service/Sensor.cs Normal file
View File

@@ -0,0 +1,49 @@
namespace HardwareMonitorStatusWindow.Service;
public class Sensor
{
public required SensorType Type { get; set; }
public required string Identifier { get; set; }
public required string Name { get; set; }
public required float? Value { get; set; }
internal static Sensor Create(LibreHardwareMonitor.Hardware.ISensor sensor)
{
return new Sensor
{
Type = MapSensorType(sensor.SensorType),
Name = sensor.Name,
Identifier = sensor.Identifier.ToString(),
Value = sensor.Value
};
}
private static SensorType MapSensorType(LibreHardwareMonitor.Hardware.SensorType sensorType)
{
return sensorType switch
{
LibreHardwareMonitor.Hardware.SensorType.Voltage => SensorType.Voltage,
LibreHardwareMonitor.Hardware.SensorType.Current => SensorType.Current,
LibreHardwareMonitor.Hardware.SensorType.Power => SensorType.Power,
LibreHardwareMonitor.Hardware.SensorType.Clock => SensorType.Clock,
LibreHardwareMonitor.Hardware.SensorType.Temperature => SensorType.Temperature,
LibreHardwareMonitor.Hardware.SensorType.Load => SensorType.Load,
LibreHardwareMonitor.Hardware.SensorType.Frequency => SensorType.Frequency,
LibreHardwareMonitor.Hardware.SensorType.Fan => SensorType.Fan,
LibreHardwareMonitor.Hardware.SensorType.Flow => SensorType.Flow,
LibreHardwareMonitor.Hardware.SensorType.Control => SensorType.Control,
LibreHardwareMonitor.Hardware.SensorType.Level => SensorType.Level,
LibreHardwareMonitor.Hardware.SensorType.Factor => SensorType.Factor,
LibreHardwareMonitor.Hardware.SensorType.Data => SensorType.Data,
LibreHardwareMonitor.Hardware.SensorType.SmallData => SensorType.SmallData,
LibreHardwareMonitor.Hardware.SensorType.Throughput => SensorType.Throughput,
LibreHardwareMonitor.Hardware.SensorType.TimeSpan => SensorType.TimeSpan,
LibreHardwareMonitor.Hardware.SensorType.Timing => SensorType.Timing,
LibreHardwareMonitor.Hardware.SensorType.Energy => SensorType.Energy,
LibreHardwareMonitor.Hardware.SensorType.Noise => SensorType.Noise,
LibreHardwareMonitor.Hardware.SensorType.Conductivity => SensorType.Conductivity,
LibreHardwareMonitor.Hardware.SensorType.Humidity => SensorType.Humidity,
_ => throw new ArgumentOutOfRangeException(nameof(sensorType), sensorType, null)
};
}
}

26
Service/SensorType.cs Normal file
View File

@@ -0,0 +1,26 @@
namespace HardwareMonitorStatusWindow.Service;
public enum SensorType
{
Voltage,
Current,
Power,
Clock,
Temperature,
Load,
Frequency,
Fan,
Flow,
Control,
Level,
Factor,
Data,
SmallData,
Throughput,
TimeSpan,
Timing,
Energy,
Noise,
Conductivity,
Humidity,
}

20
Service/Service.csproj Normal file
View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>HardwareMonitorStatusWindow.Service</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LibreHardwareMonitorLib" Version="0.9.5" />
<PackageReference Include="PipeMethodCalls" Version="4.0.3" />
<PackageReference Include="Serilog" Version="4.3.0" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="TaskScheduler" Version="2.12.2" />
</ItemGroup>
</Project>

17
Service/app.manifest Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
</application>
</compatibility>
</assembly>