updates for starting service and publish package
This commit is contained in:
@@ -1,21 +1,21 @@
|
|||||||
# Define the service name and path to the published service
|
# Define the service name and path to the published service
|
||||||
$ServiceName = "ESP32BackgroundService"
|
$ServiceName = "PCPalService"
|
||||||
$ServiceExePath = "$PSScriptRoot\ESP32BackgroundService.exe"
|
$ServiceExePath = "$PSScriptRoot\PCPalService\bin\Release\net8.0\publish\win-x64\PCPalService.exe"
|
||||||
|
|
||||||
# Function to check if the service exists
|
# Function to check if the service exists
|
||||||
function ServiceExists {
|
function ServiceExists {
|
||||||
return Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
return Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
# Install the service
|
|
||||||
function Install-Service {
|
function Install-Service {
|
||||||
if (ServiceExists) {
|
if (ServiceExists) {
|
||||||
Write-Host "Service '$ServiceName' already exists."
|
Write-Host "Service '$ServiceName' already exists."
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Write-Host "Installing service '$ServiceName'..."
|
Write-Host "Installing service '$ServiceName'..."
|
||||||
sc.exe create $ServiceName binPath= "`"$ServiceExePath`"" start= auto
|
sc.exe create $ServiceName binPath= "`"$ServiceExePath`"" start= auto obj= "LocalSystem"
|
||||||
sc.exe failure $ServiceName reset= 0 actions= restart/5000
|
sc.exe failure $ServiceName reset= 0 actions= restart/5000
|
||||||
|
sc.exe description $ServiceName "PCPal Background Monitoring Service"
|
||||||
Start-Service -Name $ServiceName
|
Start-Service -Name $ServiceName
|
||||||
Write-Host "Service installed and started successfully with auto-restart enabled."
|
Write-Host "Service installed and started successfully with auto-restart enabled."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace PCPalConfigurator
|
|||||||
|
|
||||||
private static string GetConfigPath()
|
private static string GetConfigPath()
|
||||||
{
|
{
|
||||||
string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "PCPal");
|
string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "PCPal");
|
||||||
Directory.CreateDirectory(folder);
|
Directory.CreateDirectory(folder);
|
||||||
return Path.Combine(folder, "config.json");
|
return Path.Combine(folder, "config.json");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="LibreHardwareMonitorLib" Version="0.9.4" />
|
<PackageReference Include="LibreHardwareMonitorLib" Version="0.9.4" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.IO.Ports" Version="9.0.3" />
|
<PackageReference Include="System.IO.Ports" Version="9.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
6
PCPalService/PCPalService.csproj.user
Normal file
6
PCPalService/PCPalService.csproj.user
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_LastSelectedProfileId>C:\Users\ckoch\OneDrive\Documents\GitHub\PCPal\PCPalService\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
using PCPalService;
|
using PCPalService;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
using Microsoft.Extensions.Hosting.WindowsServices;
|
||||||
|
|
||||||
|
|
||||||
namespace PCPalService
|
namespace PCPalService
|
||||||
{
|
{
|
||||||
@@ -14,6 +17,7 @@ namespace PCPalService
|
|||||||
|
|
||||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
Host.CreateDefaultBuilder(args)
|
Host.CreateDefaultBuilder(args)
|
||||||
|
.UseWindowsService()
|
||||||
.ConfigureServices((hostContext, services) =>
|
.ConfigureServices((hostContext, services) =>
|
||||||
{
|
{
|
||||||
services.AddHostedService<Worker>();
|
services.AddHostedService<Worker>();
|
||||||
|
|||||||
17
PCPalService/Properties/PublishProfiles/FolderProfile.pubxml
Normal file
17
PCPalService/Properties/PublishProfiles/FolderProfile.pubxml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Any CPU</Platform>
|
||||||
|
<PublishDir>bin\Release\net8.0\publish\win-x64\</PublishDir>
|
||||||
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
|
<_TargetId>Folder</_TargetId>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
<PublishReadyToRun>false</PublishReadyToRun>
|
||||||
|
<PublishTrimmed>false</PublishTrimmed>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<History>True|2025-03-29T16:38:44.4981820Z||;False|2025-03-29T12:38:09.2222007-04:00||;True|2025-03-29T12:24:00.0314544-04:00||;True|2025-03-29T12:02:53.1292190-04:00||;False|2025-03-29T11:58:39.8048030-04:00||;False|2025-03-29T11:58:17.4946697-04:00||;False|2025-03-29T11:57:29.9733195-04:00||;False|2025-03-29T11:56:43.0182350-04:00||;False|2025-03-29T11:56:07.6627870-04:00||;True|2025-03-28T17:00:47.0111533-04:00||;True|2025-03-28T16:59:59.8928039-04:00||;True|2025-03-28T16:58:17.3481844-04:00||;True|2025-03-28T16:57:41.5786839-04:00||;True|2025-03-28T16:55:58.0823642-04:00||;</History>
|
||||||
|
<LastFailureDetails />
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Ports;
|
using System.IO.Ports;
|
||||||
using System.ServiceProcess;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LibreHardwareMonitor.Hardware;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Microsoft.Extensions.Hosting;
|
using LibreHardwareMonitor.Hardware;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace PCPalService
|
namespace PCPalService
|
||||||
{
|
{
|
||||||
@@ -17,124 +16,129 @@ namespace PCPalService
|
|||||||
private readonly ILogger<Worker> _logger;
|
private readonly ILogger<Worker> _logger;
|
||||||
private SerialPort serialPort;
|
private SerialPort serialPort;
|
||||||
private Computer computer;
|
private Computer computer;
|
||||||
private readonly string ConfigFile = GetConfigPath();
|
|
||||||
private const string LogFile = "service_log.txt";
|
private const string AppDataFolder = "PCPal";
|
||||||
|
private const string ConfigFileName = "config.json";
|
||||||
|
|
||||||
public Worker(ILogger<Worker> logger)
|
public Worker(ILogger<Worker> logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
computer = new Computer { IsCpuEnabled = true, IsMemoryEnabled = true };
|
|
||||||
computer.Open();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetConfigPath()
|
|
||||||
{
|
|
||||||
string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "PCPal");
|
|
||||||
Directory.CreateDirectory(folder); // Ensure folder exists
|
|
||||||
return Path.Combine(folder, "config.json");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
Log("ESP32 Background Service Starting...");
|
_logger.LogInformation("Service starting...");
|
||||||
|
computer = new Computer
|
||||||
|
{
|
||||||
|
IsCpuEnabled = true,
|
||||||
|
IsMemoryEnabled = true,
|
||||||
|
IsGpuEnabled = true,
|
||||||
|
IsMotherboardEnabled = true
|
||||||
|
};
|
||||||
|
computer.Open();
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!File.Exists(ConfigFile))
|
string configPath = GetConfigPath();
|
||||||
|
if (!File.Exists(configPath))
|
||||||
{
|
{
|
||||||
Log("Config file not found. Retrying in 5 seconds...");
|
_logger.LogWarning("Config file not found. Retrying in 5 seconds...");
|
||||||
await Task.Delay(5000, stoppingToken);
|
await Task.Delay(5000, stoppingToken);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = LoadConfig();
|
var config = LoadConfig(configPath);
|
||||||
|
|
||||||
if (serialPort == null || !serialPort.IsOpen)
|
if (serialPort == null || !serialPort.IsOpen)
|
||||||
{
|
{
|
||||||
string portName = AutoDetectESP32();
|
string port = AutoDetectESP32();
|
||||||
if (portName != null)
|
if (port != null)
|
||||||
{
|
{
|
||||||
serialPort = new SerialPort(portName, 115200);
|
serialPort = new SerialPort(port, 115200);
|
||||||
serialPort.Open();
|
serialPort.Open();
|
||||||
Log($"Connected to ESP32-C3 on {portName}");
|
_logger.LogInformation($"Connected to ESP32 on {port}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log("ESP32-C3 not found. Retrying in 5 seconds...");
|
_logger.LogWarning("ESP32 not found. Retrying in 5 seconds...");
|
||||||
await Task.Delay(5000, stoppingToken);
|
await Task.Delay(5000, stoppingToken);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string line1 = GetLCDContent(config.Line1Selection, config.Line1CustomText, config.Line1PostText);
|
string line1 = GetSensorLine(config.Line1Selection, config.Line1CustomText, config.Line1PostText);
|
||||||
string line2 = GetLCDContent(config.Line2Selection, config.Line2CustomText, config.Line2PostText);
|
string line2 = GetSensorLine(config.Line2Selection, config.Line2CustomText, config.Line2PostText);
|
||||||
|
|
||||||
SendCommand($"CMD:LCD,0,{line1}");
|
serialPort.WriteLine($"CMD:LCD,0,{line1}");
|
||||||
SendCommand($"CMD:LCD,1,{line2}");
|
serialPort.WriteLine($"CMD:LCD,1,{line2}");
|
||||||
|
_logger.LogInformation("Data sent to LCD.");
|
||||||
|
|
||||||
|
await Task.Delay(5000, stoppingToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log($"Error in service loop: {ex.Message}");
|
_logger.LogError(ex, "Error in main loop");
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(5000, stoppingToken);
|
await Task.Delay(5000, stoppingToken);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
serialPort?.Close();
|
serialPort?.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetConfigPath()
|
||||||
|
{
|
||||||
|
string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), AppDataFolder);
|
||||||
|
Directory.CreateDirectory(folder);
|
||||||
|
return Path.Combine(folder, ConfigFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfigData LoadConfig(string path)
|
||||||
|
{
|
||||||
|
string json = File.ReadAllText(path);
|
||||||
|
return JsonConvert.DeserializeObject<ConfigData>(json) ?? new ConfigData();
|
||||||
|
}
|
||||||
|
|
||||||
private string AutoDetectESP32()
|
private string AutoDetectESP32()
|
||||||
{
|
{
|
||||||
foreach (string port in SerialPort.GetPortNames())
|
foreach (string port in SerialPort.GetPortNames())
|
||||||
{
|
{
|
||||||
if (IsESP32Device(port)) return port;
|
try
|
||||||
|
{
|
||||||
|
using (SerialPort test = new SerialPort(port, 115200))
|
||||||
|
{
|
||||||
|
test.Open();
|
||||||
|
test.WriteLine("CMD:GET_LCD_TYPE");
|
||||||
|
Thread.Sleep(500);
|
||||||
|
string response = test.ReadExisting();
|
||||||
|
if (response.Contains("LCD_TYPE:1602A"))
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsESP32Device(string portName)
|
private string GetSensorLine(string selection, string prefix, string suffix)
|
||||||
{
|
{
|
||||||
try
|
if (selection == "Custom Text")
|
||||||
{
|
return prefix;
|
||||||
using (SerialPort testPort = new SerialPort(portName, 115200))
|
|
||||||
{
|
|
||||||
testPort.Open();
|
|
||||||
testPort.WriteLine("CMD:GET_LCD_TYPE");
|
|
||||||
Thread.Sleep(500);
|
|
||||||
string response = testPort.ReadExisting();
|
|
||||||
testPort.Close();
|
|
||||||
return response.Contains("LCD_TYPE:1602A");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateLCD()
|
|
||||||
{
|
|
||||||
ConfigData config = LoadConfig();
|
|
||||||
string line1 = GetLCDContent(config.Line1Selection, config.Line1CustomText, config.Line1PostText);
|
|
||||||
string line2 = GetLCDContent(config.Line2Selection, config.Line2CustomText, config.Line2PostText);
|
|
||||||
|
|
||||||
|
|
||||||
SendCommand($"CMD:LCD,0,{line1}");
|
|
||||||
SendCommand($"CMD:LCD,1,{line2}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetLCDContent(string selection, string prefix, string postfix)
|
|
||||||
{
|
|
||||||
var parsed = ParseSensorSelection(selection);
|
var parsed = ParseSensorSelection(selection);
|
||||||
if (parsed == null)
|
if (parsed == null)
|
||||||
return "N/A";
|
return "N/A";
|
||||||
|
|
||||||
string value = GetSensorValue(parsed.Value.hardwareType, parsed.Value.sensorName, parsed.Value.sensorType);
|
string value = GetSensorValue(parsed.Value.hardwareType, parsed.Value.sensorName, parsed.Value.sensorType);
|
||||||
return $"{prefix}{value}{postfix}";
|
return $"{prefix}{value}{suffix}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private (HardwareType hardwareType, string sensorName, SensorType sensorType)? ParseSensorSelection(string input)
|
private (HardwareType hardwareType, string sensorName, SensorType sensorType)? ParseSensorSelection(string input)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var parts = input.Split(':', 2);
|
var parts = input.Split(':', 2);
|
||||||
@@ -142,7 +146,6 @@ namespace PCPalService
|
|||||||
|
|
||||||
var hardwareType = Enum.Parse<HardwareType>(parts[0].Trim());
|
var hardwareType = Enum.Parse<HardwareType>(parts[0].Trim());
|
||||||
var sensorInfo = parts[1].Trim();
|
var sensorInfo = parts[1].Trim();
|
||||||
|
|
||||||
int idx = sensorInfo.LastIndexOf('(');
|
int idx = sensorInfo.LastIndexOf('(');
|
||||||
if (idx == -1) return null;
|
if (idx == -1) return null;
|
||||||
|
|
||||||
@@ -157,14 +160,15 @@ namespace PCPalService
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetSensorValue(HardwareType type, string name, SensorType sensorType)
|
private string GetSensorValue(HardwareType type, string name, SensorType sensorType)
|
||||||
{
|
{
|
||||||
foreach (IHardware hardware in computer.Hardware)
|
foreach (var hardware in computer.Hardware)
|
||||||
{
|
{
|
||||||
if (hardware.HardwareType == type)
|
if (hardware.HardwareType == type)
|
||||||
{
|
{
|
||||||
hardware.Update();
|
hardware.Update();
|
||||||
foreach (ISensor sensor in hardware.Sensors)
|
foreach (var sensor in hardware.Sensors)
|
||||||
{
|
{
|
||||||
if (sensor.SensorType == sensorType && sensor.Name == name)
|
if (sensor.SensorType == sensorType && sensor.Name == name)
|
||||||
{
|
{
|
||||||
@@ -175,39 +179,16 @@ namespace PCPalService
|
|||||||
}
|
}
|
||||||
return "N/A";
|
return "N/A";
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConfigData LoadConfig()
|
|
||||||
{
|
|
||||||
if (File.Exists(ConfigFile))
|
|
||||||
{
|
|
||||||
string json = File.ReadAllText(ConfigFile);
|
|
||||||
return JsonConvert.DeserializeObject<ConfigData>(json) ?? new ConfigData();
|
|
||||||
}
|
|
||||||
return new ConfigData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendCommand(string command)
|
public class ConfigData
|
||||||
{
|
|
||||||
serialPort.WriteLine(command);
|
|
||||||
Log($"Sent: {command}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Log(string message)
|
|
||||||
{
|
|
||||||
string logEntry = $"{DateTime.Now}: {message}";
|
|
||||||
File.AppendAllText(LogFile, logEntry + Environment.NewLine);
|
|
||||||
_logger.LogInformation(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConfigData
|
|
||||||
{
|
{
|
||||||
public string Line1Selection { get; set; }
|
public string Line1Selection { get; set; }
|
||||||
public string Line1CustomText { get; set; }
|
public string Line1CustomText { get; set; }
|
||||||
|
public string Line1PostText { get; set; }
|
||||||
public string Line2Selection { get; set; }
|
public string Line2Selection { get; set; }
|
||||||
public string Line2CustomText { get; set; }
|
public string Line2CustomText { get; set; }
|
||||||
public string Line1PostText { get; set; }
|
|
||||||
public string Line2PostText { get; set; }
|
public string Line2PostText { get; set; }
|
||||||
|
public string ScreenType { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user