Files
chromebox-fan-control-win/ChromeboxFanControl/AppConfig.cs
2026-03-21 05:47:58 +08:00

127 lines
5.1 KiB
C#

using System.Text.Json;
using System.Text.Json.Serialization;
namespace ChromeboxFanControl;
public sealed class AppConfig
{
public string EctoolPath { get; set; } = @"C:\Program Files\crosec\ectool.exe";
public int PollIntervalMs { get; set; } = 1500;
/// <summary>Call ectool for RPM every N control cycles (1 = every cycle).</summary>
public int FanRpmPollEveryNCycles { get; set; } = 1;
public string[] FanRpmArgs { get; set; } = ["pwmgetfanrpm", "0"];
/// <summary>Ectool args to read fan duty (0-100). Empty = skip, use commanded duty.</summary>
public string[]? FanDutyArgs { get; set; }
public string[] AutoFanCtrlArgs { get; set; } = ["autofanctrl"];
public string TempSource { get; set; } = "AverageCore";
public int FailSafeAfterConsecutiveErrors { get; set; } = 5;
public int FailSafeFanPercent { get; set; } = 100;
public bool FailSafeRestoreAutoFan { get; set; }
public int ChartHistoryMinutes { get; set; } = 15;
public int ChartMaxPoints { get; set; } = 900;
public int[] CurvePoints { get; set; } =
[
0, 0, 10, 25, 40, 55, 70, 80, 90, 95, 97, 98, 99, 100
];
public static JsonSerializerOptions JsonOptions { get; } = new()
{
WriteIndented = true,
PropertyNameCaseInsensitive = true,
Converters = { new JsonStringEnumConverter() }
};
public static string UserConfigPath =>
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"ChromeboxFanControl",
"config.json");
public static AppConfig LoadMerged()
{
var cfg = new AppConfig();
var baseDir = AppContext.BaseDirectory;
var appSettings = Path.Combine(baseDir, "appsettings.json");
if (File.Exists(appSettings))
ApplyJson(File.ReadAllText(appSettings), cfg);
if (File.Exists(UserConfigPath))
{
try
{
ApplyJson(File.ReadAllText(UserConfigPath), cfg);
}
catch
{
/* keep base */
}
}
return cfg;
}
private static void ApplyJson(string json, AppConfig dst)
{
var src = JsonSerializer.Deserialize<AppConfig>(json, JsonOptions);
if (src == null)
return;
dst.EctoolPath = src.EctoolPath;
dst.PollIntervalMs = Math.Clamp(src.PollIntervalMs, 250, 60_000);
dst.FanRpmPollEveryNCycles = Math.Max(1, src.FanRpmPollEveryNCycles);
if (src.FanRpmArgs is { Length: > 0 })
dst.FanRpmArgs = src.FanRpmArgs;
dst.FanDutyArgs = src.FanDutyArgs;
if (src.AutoFanCtrlArgs is { Length: > 0 })
dst.AutoFanCtrlArgs = src.AutoFanCtrlArgs;
dst.TempSource = string.Equals(src.TempSource, "MaxCore", StringComparison.OrdinalIgnoreCase) ? "MaxCore" : "AverageCore";
dst.FailSafeAfterConsecutiveErrors = Math.Max(1, src.FailSafeAfterConsecutiveErrors);
dst.FailSafeFanPercent = Math.Clamp(src.FailSafeFanPercent, 0, 100);
dst.FailSafeRestoreAutoFan = src.FailSafeRestoreAutoFan;
dst.ChartHistoryMinutes = Math.Clamp(src.ChartHistoryMinutes, 1, 120);
dst.ChartMaxPoints = src.ChartMaxPoints > 0 ? src.ChartMaxPoints : 900;
if (src.CurvePoints is { Length: 14 })
dst.CurvePoints = (int[])src.CurvePoints.Clone();
else if (src.CurvePoints is { Length: 13 } old13)
dst.CurvePoints = MigrateCurveTo14(old13);
else if (src.CurvePoints is { Length: 20 } old20)
dst.CurvePoints = MigrateCurveTo14(old20, new[] { 0, 5, 11, 16, 21, 26, 32, 37, 42, 47, 53, 58, 63, 68, 74, 79, 84, 90, 95, 100 });
}
private static int[] MigrateCurveTo14(int[] oldCurve, int[]? oldTemps = null)
{
var temps = oldTemps ?? (oldCurve.Length == 13 ? new[] { 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100 } : new[] { 0, 5, 11, 16, 21, 26, 32, 37, 42, 47, 53, 58, 63, 68, 74, 79, 84, 90, 95, 100 });
var newTemps = FanCurve.TempBreakpoints;
var result = new int[14];
for (var i = 0; i < 14; i++)
{
var t = newTemps[i];
if (t <= temps[0])
result[i] = Math.Clamp(oldCurve[0], 0, 100);
else if (t >= temps[^1])
result[i] = Math.Clamp(oldCurve[^1], 0, 100);
else
{
for (var j = 0; j < temps.Length - 1; j++)
{
if (t < temps[j + 1])
{
var frac = (t - temps[j]) / (double)(temps[j + 1] - temps[j]);
result[i] = (int)Math.Round(Math.Clamp(oldCurve[j], 0, 100) + (Math.Clamp(oldCurve[j + 1], 0, 100) - Math.Clamp(oldCurve[j], 0, 100)) * frac);
break;
}
}
}
}
return result;
}
public void SaveUser()
{
var dir = Path.GetDirectoryName(UserConfigPath);
if (!string.IsNullOrEmpty(dir))
Directory.CreateDirectory(dir);
File.WriteAllText(UserConfigPath, JsonSerializer.Serialize(this, JsonOptions));
}
}