diff --git a/AsusFanControl/AsusControl.cs b/AsusFanControl/AsusControl.cs
index 69ccd9a..e8195f4 100644
--- a/AsusFanControl/AsusControl.cs
+++ b/AsusFanControl/AsusControl.cs
@@ -1,4 +1,4 @@
-using AsusSystemAnalysis;
+using AsusSystemAnalysis;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -78,5 +78,18 @@ public ulong Thermal_Read_Cpu_Temperature()
{
return AsusWinIO64.Thermal_Read_Cpu_Temperature();
}
+
+ ///
+ /// Returns CPU temperature in Celsius, or -1 if invalid/unavailable.
+ ///
+ public int GetCpuTemperatureCelsius()
+ {
+ ulong raw = Thermal_Read_Cpu_Temperature();
+ if (raw > 100000 || raw == 0x7FFFFFFF) return -1;
+ if (raw < 200) return (int)Math.Min(raw, 150);
+ int celsius = (int)Math.Round((raw / 10.0) - 273.15);
+ if (celsius < -50 || celsius > 150) return -1;
+ return celsius;
+ }
}
}
diff --git a/AsusFanControlGUI/AsusFanControlGUI.csproj b/AsusFanControlGUI/AsusFanControlGUI.csproj
index d1527a6..b9c3efe 100644
--- a/AsusFanControlGUI/AsusFanControlGUI.csproj
+++ b/AsusFanControlGUI/AsusFanControlGUI.csproj
@@ -1,4 +1,4 @@
-
+
@@ -54,6 +54,8 @@
propeller.ico
+ app.manifest
+ true
@@ -67,8 +69,15 @@
+
+ $(UserProfile)\.nuget\packages\system.resources.extensions\4.6.0\lib\netstandard2.0\System.Resources.Extensions.dll
+
+
+
+
+
Form
@@ -102,6 +111,7 @@
+
@@ -111,6 +121,12 @@
+
+ PreserveNewest
+
+
+ PreserveNewest
+
\ No newline at end of file
diff --git a/AsusFanControlGUI/FanCurve.cs b/AsusFanControlGUI/FanCurve.cs
new file mode 100644
index 0000000..2821772
--- /dev/null
+++ b/AsusFanControlGUI/FanCurve.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace AsusFanControlGUI
+{
+ ///
+ /// Fixed temperature ranges: < 35°C → 0%, 35–55°C → 45%, 55–75°C → 80%, ≥ 75°C → 100%.
+ ///
+ public static class FanCurve
+ {
+ public static int GetFanPercentForTemperature(int temp, bool clampUnsafe = false)
+ {
+ int percent;
+ if (temp < 35) percent = 0;
+ else if (temp < 55) percent = 45;
+ else if (temp < 75) percent = 80;
+ else percent = 100;
+ return clampUnsafe ? ClampUnsafe(percent) : percent;
+ }
+
+ private static int ClampUnsafe(int percent)
+ {
+ if (percent <= 0) return 0;
+ return Math.Max(40, Math.Min(99, percent));
+ }
+ }
+}
diff --git a/AsusFanControlGUI/Form1.Designer.cs b/AsusFanControlGUI/Form1.Designer.cs
index e1b5de3..03d4433 100644
--- a/AsusFanControlGUI/Form1.Designer.cs
+++ b/AsusFanControlGUI/Form1.Designer.cs
@@ -1,4 +1,4 @@
-namespace AsusFanControlGUI
+namespace AsusFanControlGUI
{
partial class Form1
{
@@ -46,13 +46,21 @@ private void InitializeComponent()
this.toolStripMenuItemMinimizeToTrayOnClose = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItemAutoRefreshStats = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItemCheckForUpdates = new System.Windows.Forms.ToolStripMenuItem();
+ this.radioManual = new System.Windows.Forms.RadioButton();
+ this.radioFanCurve = new System.Windows.Forms.RadioButton();
+ this.panelManual = new System.Windows.Forms.Panel();
+ this.panelFanCurve = new System.Windows.Forms.Panel();
+ this.labelTempRanges = new System.Windows.Forms.Label();
+ this.labelCurveStatus = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.trackBarFanSpeed)).BeginInit();
this.menuStrip1.SuspendLayout();
+ this.panelManual.SuspendLayout();
+ this.panelFanCurve.SuspendLayout();
this.SuspendLayout();
//
// trackBarFanSpeed
//
- this.trackBarFanSpeed.Location = new System.Drawing.Point(12, 62);
+ this.trackBarFanSpeed.Location = new System.Drawing.Point(3, 8);
this.trackBarFanSpeed.Maximum = 100;
this.trackBarFanSpeed.Name = "trackBarFanSpeed";
this.trackBarFanSpeed.Size = new System.Drawing.Size(300, 45);
@@ -64,7 +72,7 @@ private void InitializeComponent()
// label1
//
this.label1.AutoSize = true;
- this.label1.Location = new System.Drawing.Point(12, 110);
+ this.label1.Location = new System.Drawing.Point(3, 56);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(73, 13);
this.label1.TabIndex = 1;
@@ -73,7 +81,7 @@ private void InitializeComponent()
// labelValue
//
this.labelValue.AutoSize = true;
- this.labelValue.Location = new System.Drawing.Point(91, 110);
+ this.labelValue.Location = new System.Drawing.Point(82, 56);
this.labelValue.Name = "labelValue";
this.labelValue.Size = new System.Drawing.Size(10, 13);
this.labelValue.TabIndex = 2;
@@ -82,7 +90,7 @@ private void InitializeComponent()
// label2
//
this.label2.AutoSize = true;
- this.label2.Location = new System.Drawing.Point(40, 139);
+ this.label2.Location = new System.Drawing.Point(40, 182);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(71, 13);
this.label2.TabIndex = 3;
@@ -90,7 +98,7 @@ private void InitializeComponent()
//
// buttonRefreshRPM
//
- this.buttonRefreshRPM.Location = new System.Drawing.Point(12, 134);
+ this.buttonRefreshRPM.Location = new System.Drawing.Point(12, 177);
this.buttonRefreshRPM.Name = "buttonRefreshRPM";
this.buttonRefreshRPM.Size = new System.Drawing.Size(22, 23);
this.buttonRefreshRPM.TabIndex = 4;
@@ -101,7 +109,7 @@ private void InitializeComponent()
// labelRPM
//
this.labelRPM.AutoSize = true;
- this.labelRPM.Location = new System.Drawing.Point(117, 139);
+ this.labelRPM.Location = new System.Drawing.Point(117, 182);
this.labelRPM.Name = "labelRPM";
this.labelRPM.Size = new System.Drawing.Size(10, 13);
this.labelRPM.TabIndex = 5;
@@ -121,7 +129,7 @@ private void InitializeComponent()
// labelCPUTemp
//
this.labelCPUTemp.AutoSize = true;
- this.labelCPUTemp.Location = new System.Drawing.Point(141, 168);
+ this.labelCPUTemp.Location = new System.Drawing.Point(141, 211);
this.labelCPUTemp.Name = "labelCPUTemp";
this.labelCPUTemp.Size = new System.Drawing.Size(10, 13);
this.labelCPUTemp.TabIndex = 9;
@@ -129,7 +137,7 @@ private void InitializeComponent()
//
// buttonRefreshCPUTemp
//
- this.buttonRefreshCPUTemp.Location = new System.Drawing.Point(12, 163);
+ this.buttonRefreshCPUTemp.Location = new System.Drawing.Point(12, 206);
this.buttonRefreshCPUTemp.Name = "buttonRefreshCPUTemp";
this.buttonRefreshCPUTemp.Size = new System.Drawing.Size(22, 23);
this.buttonRefreshCPUTemp.TabIndex = 8;
@@ -140,7 +148,7 @@ private void InitializeComponent()
// label4
//
this.label4.AutoSize = true;
- this.label4.Location = new System.Drawing.Point(40, 168);
+ this.label4.Location = new System.Drawing.Point(40, 211);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(95, 13);
this.label4.TabIndex = 7;
@@ -153,7 +161,7 @@ private void InitializeComponent()
this.toolStripMenuItemCheckForUpdates});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
- this.menuStrip1.Size = new System.Drawing.Size(324, 24);
+ this.menuStrip1.Size = new System.Drawing.Size(364, 24);
this.menuStrip1.TabIndex = 10;
this.menuStrip1.Text = "menuStrip1";
//
@@ -207,31 +215,103 @@ private void InitializeComponent()
this.toolStripMenuItemCheckForUpdates.Text = "Check for updates";
this.toolStripMenuItemCheckForUpdates.Click += new System.EventHandler(this.toolStripMenuItemCheckForUpdates_Click);
//
+ // radioManual
+ //
+ this.radioManual.AutoSize = true;
+ this.radioManual.Location = new System.Drawing.Point(12, 58);
+ this.radioManual.Name = "radioManual";
+ this.radioManual.Size = new System.Drawing.Size(60, 17);
+ this.radioManual.TabIndex = 11;
+ this.radioManual.TabStop = true;
+ this.radioManual.Text = "Manual";
+ this.radioManual.UseVisualStyleBackColor = true;
+ this.radioManual.CheckedChanged += new System.EventHandler(this.radioMode_CheckedChanged);
+ //
+ // radioFanCurve
+ //
+ this.radioFanCurve.AutoSize = true;
+ this.radioFanCurve.Location = new System.Drawing.Point(90, 58);
+ this.radioFanCurve.Name = "radioFanCurve";
+ this.radioFanCurve.Size = new System.Drawing.Size(43, 17);
+ this.radioFanCurve.TabIndex = 12;
+ this.radioFanCurve.TabStop = true;
+ this.radioFanCurve.Text = "Auto";
+ this.radioFanCurve.UseVisualStyleBackColor = true;
+ this.radioFanCurve.CheckedChanged += new System.EventHandler(this.radioMode_CheckedChanged);
+ //
+ // panelManual
+ //
+ this.panelManual.Controls.Add(this.trackBarFanSpeed);
+ this.panelManual.Controls.Add(this.label1);
+ this.panelManual.Controls.Add(this.labelValue);
+ this.panelManual.Location = new System.Drawing.Point(12, 82);
+ this.panelManual.Name = "panelManual";
+ this.panelManual.Size = new System.Drawing.Size(340, 85);
+ this.panelManual.TabIndex = 13;
+ //
+ // panelFanCurve
+ //
+ this.panelFanCurve.Controls.Add(this.labelTempRanges);
+ this.panelFanCurve.Controls.Add(this.labelCurveStatus);
+ this.panelFanCurve.Location = new System.Drawing.Point(12, 82);
+ this.panelFanCurve.Name = "panelFanCurve";
+ this.panelFanCurve.Padding = new System.Windows.Forms.Padding(8, 8, 8, 4);
+ this.panelFanCurve.Size = new System.Drawing.Size(340, 92);
+ this.panelFanCurve.TabIndex = 14;
+ this.panelFanCurve.Visible = false;
+ //
+ // labelTempRanges
+ //
+ this.labelTempRanges.AutoSize = true;
+ this.labelTempRanges.Location = new System.Drawing.Point(5, 8);
+ this.labelTempRanges.Name = "labelTempRanges";
+ this.labelTempRanges.Size = new System.Drawing.Size(200, 65);
+ this.labelTempRanges.TabIndex = 0;
+ this.labelTempRanges.Text = "< 35°C → 0% (off)\r\n35–55°C → 45%\r\n55–75°C → 80%\r\n≥ 75°C → 100%";
+ //
+ // labelCurveStatus
+ //
+ this.labelCurveStatus.AutoSize = true;
+ this.labelCurveStatus.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold);
+ this.labelCurveStatus.Location = new System.Drawing.Point(5, 78);
+ this.labelCurveStatus.Name = "labelCurveStatus";
+ this.labelCurveStatus.Size = new System.Drawing.Size(130, 13);
+ this.labelCurveStatus.TabIndex = 1;
+ this.labelCurveStatus.Text = "Current: -- °C → Fan: --%";
+ //
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(324, 198);
+ this.ClientSize = new System.Drawing.Size(364, 268);
this.Controls.Add(this.labelCPUTemp);
this.Controls.Add(this.buttonRefreshCPUTemp);
this.Controls.Add(this.label4);
- this.Controls.Add(this.checkBoxTurnOn);
this.Controls.Add(this.labelRPM);
this.Controls.Add(this.buttonRefreshRPM);
this.Controls.Add(this.label2);
- this.Controls.Add(this.labelValue);
- this.Controls.Add(this.label1);
- this.Controls.Add(this.trackBarFanSpeed);
+ this.Controls.Add(this.panelFanCurve);
+ this.Controls.Add(this.panelManual);
+ this.Controls.Add(this.radioFanCurve);
+ this.Controls.Add(this.radioManual);
+ this.Controls.Add(this.checkBoxTurnOn);
this.Controls.Add(this.menuStrip1);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MainMenuStrip = this.menuStrip1;
+ this.MaximizeBox = false;
this.Name = "Form1";
+ this.Padding = new System.Windows.Forms.Padding(0, 0, 0, 8);
this.Text = "Asus Fan Control";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.trackBarFanSpeed)).EndInit();
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
+ this.panelManual.ResumeLayout(false);
+ this.panelManual.PerformLayout();
+ this.panelFanCurve.ResumeLayout(false);
+ this.panelFanCurve.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@@ -256,6 +336,12 @@ private void InitializeComponent()
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemCheckForUpdates;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemMinimizeToTrayOnClose;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemAutoRefreshStats;
+ private System.Windows.Forms.RadioButton radioManual;
+ private System.Windows.Forms.RadioButton radioFanCurve;
+ private System.Windows.Forms.Panel panelManual;
+ private System.Windows.Forms.Panel panelFanCurve;
+ private System.Windows.Forms.Label labelTempRanges;
+ private System.Windows.Forms.Label labelCurveStatus;
}
}
diff --git a/AsusFanControlGUI/Form1.cs b/AsusFanControlGUI/Form1.cs
index 1678305..6b67260 100644
--- a/AsusFanControlGUI/Form1.cs
+++ b/AsusFanControlGUI/Form1.cs
@@ -1,5 +1,6 @@
-using AsusFanControl;
+using AsusFanControl;
using System;
+using System.Threading.Tasks;
using System.Windows.Forms;
namespace AsusFanControlGUI
@@ -11,6 +12,10 @@ public partial class Form1 : Form
Timer timer;
NotifyIcon trayIcon;
+ int? _pendingFanPercent;
+ DateTime _pendingSinceUtc;
+ const int DebounceSeconds = 5;
+
public Form1()
{
InitializeComponent();
@@ -21,6 +26,11 @@ public Form1()
toolStripMenuItemMinimizeToTrayOnClose.Checked = Properties.Settings.Default.minimizeToTrayOnClose;
toolStripMenuItemAutoRefreshStats.Checked = Properties.Settings.Default.autoRefreshStats;
trackBarFanSpeed.Value = Properties.Settings.Default.fanSpeed;
+
+ radioManual.Checked = !Properties.Settings.Default.useFanCurve;
+ radioFanCurve.Checked = Properties.Settings.Default.useFanCurve;
+ panelManual.Visible = radioManual.Checked;
+ panelFanCurve.Visible = radioFanCurve.Checked;
}
private void OnProcessExit(object sender, EventArgs e)
@@ -32,13 +42,15 @@ private void OnProcessExit(object sender, EventArgs e)
private void Form1_Load(object sender, EventArgs e)
{
timerRefreshStats();
+ // Show current temp and fan % in Auto mode immediately
+ buttonRefreshCPUTemp_Click(sender, e);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (Properties.Settings.Default.minimizeToTrayOnClose && Visible)
{
- if(trayIcon == null)
+ if (trayIcon == null)
{
trayIcon = new NotifyIcon()
{
@@ -62,18 +74,18 @@ private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e1.Button != MouseButtons.Left)
return;
-
trayIcon.Visible = false;
Show();
};
}
-
trayIcon.Visible = true;
e.Cancel = true;
Hide();
}
}
+ private const int TimerIntervalMs = 5000; // 5 seconds - reduces hardware polling and UI blocking
+
private void timerRefreshStats()
{
if (timer != null)
@@ -81,20 +93,69 @@ private void timerRefreshStats()
timer.Stop();
timer = null;
}
-
- if (!Properties.Settings.Default.autoRefreshStats)
+ if (!Properties.Settings.Default.autoRefreshStats &&
+ !(radioFanCurve.Checked && checkBoxTurnOn.Checked))
return;
timer = new Timer();
- timer.Interval = 2000;
- timer.Tick += new EventHandler(TimerEventProcessor);
+ timer.Interval = TimerIntervalMs;
+ timer.Tick += TimerEventProcessor;
timer.Start();
}
private void TimerEventProcessor(object sender, EventArgs e)
{
- buttonRefreshRPM_Click(sender, e);
- buttonRefreshCPUTemp_Click(sender, e);
+ // Run hardware reads on a background thread so the UI stays responsive
+ Task.Run(() =>
+ {
+ int temp = asusControl.GetCpuTemperatureCelsius();
+ string rpmText = string.Join(" ", asusControl.GetFanSpeeds());
+
+ int newPercent = -1;
+ if (radioFanCurve.Checked && temp >= 0 && checkBoxTurnOn.Checked)
+ {
+ bool clampUnsafe = Properties.Settings.Default.forbidUnsafeSettings;
+ newPercent = FanCurve.GetFanPercentForTemperature(temp, clampUnsafe);
+ }
+
+ int tempForCapture = temp;
+ bool inAuto = radioFanCurve.Checked;
+ string curveStatus = temp >= 0
+ ? $"Current: {temp} °C → Fan: {FanCurve.GetFanPercentForTemperature(temp, Properties.Settings.Default.forbidUnsafeSettings)}%"
+ : "Current: N/A (temp sensor unavailable)";
+
+ BeginInvoke(new Action(() =>
+ {
+ labelCPUTemp.Text = tempForCapture >= 0 ? $"{tempForCapture}" : "N/A";
+ labelRPM.Text = rpmText;
+ if (inAuto)
+ {
+ labelCurveStatus.Text = curveStatus;
+ if (newPercent >= 0 && checkBoxTurnOn.Checked)
+ {
+ if (newPercent == fanSpeed)
+ {
+ _pendingFanPercent = null;
+ }
+ else
+ {
+ DateTime now = DateTime.UtcNow;
+ if (newPercent != _pendingFanPercent)
+ {
+ _pendingFanPercent = newPercent;
+ _pendingSinceUtc = now;
+ }
+ else if ((now - _pendingSinceUtc).TotalSeconds >= DebounceSeconds)
+ {
+ fanSpeed = newPercent;
+ asusControl.SetFanSpeeds(newPercent);
+ _pendingFanPercent = null;
+ }
+ }
+ }
+ }
+ }));
+ });
}
private void toolStripMenuItemTurnOffControlOnExit_CheckedChanged(object sender, EventArgs e)
@@ -119,7 +180,6 @@ private void toolStripMenuItemAutoRefreshStats_Click(object sender, EventArgs e)
{
Properties.Settings.Default.autoRefreshStats = toolStripMenuItemAutoRefreshStats.Checked;
Properties.Settings.Default.Save();
-
timerRefreshStats();
}
@@ -130,29 +190,53 @@ private void toolStripMenuItemCheckForUpdates_Click(object sender, EventArgs e)
private void setFanSpeed()
{
- var value = trackBarFanSpeed.Value;
- Properties.Settings.Default.fanSpeed = value;
- Properties.Settings.Default.Save();
-
if (!checkBoxTurnOn.Checked)
- value = 0;
-
- if (value == 0)
+ {
+ if (fanSpeed != 0)
+ {
+ fanSpeed = 0;
+ asusControl.SetFanSpeeds(0);
+ }
+ _pendingFanPercent = null;
labelValue.Text = "turned off";
- else
- labelValue.Text = value.ToString();
-
- if (fanSpeed == value)
return;
+ }
- fanSpeed = value;
-
- asusControl.SetFanSpeeds(value);
+ if (radioManual.Checked)
+ {
+ var value = trackBarFanSpeed.Value;
+ Properties.Settings.Default.fanSpeed = value;
+ Properties.Settings.Default.Save();
+ if (value == 0)
+ labelValue.Text = "turned off";
+ else
+ labelValue.Text = value.ToString();
+ if (fanSpeed == value) return;
+ fanSpeed = value;
+ asusControl.SetFanSpeeds(value);
+ }
+ else if (radioFanCurve.Checked)
+ {
+ int temp = asusControl.GetCpuTemperatureCelsius();
+ if (temp >= 0)
+ {
+ bool clampUnsafe = Properties.Settings.Default.forbidUnsafeSettings;
+ int percent = FanCurve.GetFanPercentForTemperature(temp, clampUnsafe);
+ fanSpeed = percent;
+ asusControl.SetFanSpeeds(percent);
+ labelCurveStatus.Text = $"Current: {temp} °C → Fan: {percent}%";
+ }
+ else
+ {
+ labelCurveStatus.Text = "Current: N/A (temp sensor unavailable)";
+ }
+ }
}
private void checkBoxTurnOn_CheckedChanged(object sender, EventArgs e)
{
setFanSpeed();
+ timerRefreshStats();
}
private void trackBarFanSpeed_MouseCaptureChanged(object sender, EventArgs e)
@@ -164,15 +248,12 @@ private void trackBarFanSpeed_MouseCaptureChanged(object sender, EventArgs e)
else if (trackBarFanSpeed.Value > 99)
trackBarFanSpeed.Value = 99;
}
-
setFanSpeed();
}
private void trackBarFanSpeed_KeyUp(object sender, KeyEventArgs e)
{
- if (e.KeyCode != Keys.Left && e.KeyCode != Keys.Right)
- return;
-
+ if (e.KeyCode != Keys.Left && e.KeyCode != Keys.Right) return;
trackBarFanSpeed_MouseCaptureChanged(sender, e);
}
@@ -183,8 +264,60 @@ private void buttonRefreshRPM_Click(object sender, EventArgs e)
private void buttonRefreshCPUTemp_Click(object sender, EventArgs e)
{
- labelCPUTemp.Text = $"{asusControl.Thermal_Read_Cpu_Temperature()}";
+ int tempC = asusControl.GetCpuTemperatureCelsius();
+ labelCPUTemp.Text = tempC >= 0 ? $"{tempC}" : "N/A";
+ if (radioFanCurve.Checked && tempC >= 0)
+ {
+ bool clampUnsafe = Properties.Settings.Default.forbidUnsafeSettings;
+ int percent = FanCurve.GetFanPercentForTemperature(tempC, clampUnsafe);
+ labelCurveStatus.Text = $"Current: {tempC} °C → Fan: {percent}%";
+ if (checkBoxTurnOn.Checked && fanSpeed != percent)
+ {
+ fanSpeed = percent;
+ asusControl.SetFanSpeeds(percent);
+ }
+ }
+ else if (radioFanCurve.Checked)
+ {
+ if (tempC < 0)
+ labelCurveStatus.Text = "Current: N/A (temp sensor unavailable)";
+ }
}
+ private void radioMode_CheckedChanged(object sender, EventArgs e)
+ {
+ if (radioManual.Checked)
+ {
+ panelManual.Visible = true;
+ panelFanCurve.Visible = false;
+ Properties.Settings.Default.useFanCurve = false;
+ _pendingFanPercent = null;
+ }
+ else
+ {
+ panelManual.Visible = false;
+ panelFanCurve.Visible = true;
+ Properties.Settings.Default.useFanCurve = true;
+ int temp = asusControl.GetCpuTemperatureCelsius();
+ if (temp >= 0)
+ {
+ bool clampUnsafe = Properties.Settings.Default.forbidUnsafeSettings;
+ int percent = FanCurve.GetFanPercentForTemperature(temp, clampUnsafe);
+ labelCurveStatus.Text = $"Current: {temp} °C → Fan: {percent}%";
+ if (checkBoxTurnOn.Checked)
+ {
+ fanSpeed = percent;
+ asusControl.SetFanSpeeds(percent);
+ }
+ }
+ else
+ {
+ labelCurveStatus.Text = "Current: N/A (temp sensor unavailable)";
+ }
+ }
+ Properties.Settings.Default.Save();
+ timerRefreshStats();
+ setFanSpeed();
+ }
}
}
diff --git a/AsusFanControlGUI/Properties/Settings.Designer.cs b/AsusFanControlGUI/Properties/Settings.Designer.cs
index c660e19..b82a420 100644
--- a/AsusFanControlGUI/Properties/Settings.Designer.cs
+++ b/AsusFanControlGUI/Properties/Settings.Designer.cs
@@ -1,4 +1,4 @@
-//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
@@ -82,5 +82,18 @@ public bool autoRefreshStats {
this["autoRefreshStats"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool useFanCurve {
+ get {
+ return ((bool)(this["useFanCurve"]));
+ }
+ set {
+ this["useFanCurve"] = value;
+ }
+ }
+
}
}
diff --git a/AsusFanControlGUI/Properties/Settings.settings b/AsusFanControlGUI/Properties/Settings.settings
index 9d5489c..ec620fd 100644
--- a/AsusFanControlGUI/Properties/Settings.settings
+++ b/AsusFanControlGUI/Properties/Settings.settings
@@ -1,4 +1,4 @@
-
+
@@ -17,5 +17,8 @@
False
+
+ False
+
\ No newline at end of file
diff --git a/AsusFanControlGUI/app.manifest b/AsusFanControlGUI/app.manifest
new file mode 100644
index 0000000..3632940
--- /dev/null
+++ b/AsusFanControlGUI/app.manifest
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AsusFanControlGUI/run.bat b/AsusFanControlGUI/run.bat
new file mode 100644
index 0000000..292fe7e
--- /dev/null
+++ b/AsusFanControlGUI/run.bat
@@ -0,0 +1,9 @@
+@echo off
+net session >nul 2>&1
+if %ERRORLEVEL% NEQ 0 (
+ echo Requesting administrative privileges...
+ powershell -Command "Start-Process -FilePath 'cmd.exe' -ArgumentList '/c \"\"%~f0\"\"' -Verb RunAs"
+ exit /b
+)
+
+"%~dp0PsExec" -i -s -d "%~dp0AsusFanControlGUI.exe"
diff --git a/README.md b/README.md
index c132c78..9ee14e4 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,8 @@ Go to [releases](../../releases)
GUI: `AsusFanControlGUI.exe`
+After building (e.g. Release | x64), the output folder `bin\x64\Release\` contains the exes and `run.bat`. Double‑click `run.bat` to launch the GUI with admin rights (it uses PsExec if present). To have PsExec copied automatically, place `PsExec.exe` in the `AsusFanControlGUI` project folder once; then every build will copy it to the output folder.
+

### Why need it?
@@ -29,7 +31,37 @@ This program should work on any laptop with x64 windows where [Fan Diagnosis](ht
[ASUS System Control Interface](https://www.asus.com/support/faq/1047338/) is necessary for this software to work - `ASUS System Analysis` service [must be running](../../issues/16). It's automatically installed with `MyASUS` app.
+**If fan control has no effect:** Run the app **as Administrator** (right‑click → Run as administrator). The GUI is built to request admin elevation. Also ensure the ASUS System Analysis service is running (Services → "ASUS System Analysis" or "AsusSystemAnalysis") and that your model supports [Fan Diagnosis](https://github.com/Karmel0x/AsusFanControl/assets/25367564/7129833b-97af-4da8-9148-b71e49552ea4) in MyASUS. You can test from command line (as admin): `AsusFanControl.exe --get-fan-count` then `AsusFanControl.exe --set-fan-speeds=80`.
+
Included `AsusWinIO64.dll` is licenced to `(c) ASUSTek COMPUTER INC.` which can be found in `C:\Windows\System32\DriverStore\FileRepository\asussci2.inf_amd64_-\ASUSSystemAnalysis\` if you have MyASUS installed.
[Works on](../../issues/13):
- ASUS: VivoBook, ZenBook, TUF Gaming, ROG Strix, ROG Zephyrus, ROG Flow
+
+---
+
+### Modifications
+
+This fork adds temperature-based fan control and UI improvements on top of the original Asus Fan Control:
+
+- **Manual vs Auto mode**
+ - **Manual:** Fan speed is set by the trackbar (unchanged).
+ - **Auto:** Fan speed is chosen from fixed temperature ranges; the current CPU temp and resulting fan % are shown in the UI.
+
+- **Fixed temperature ranges (Auto mode)**
+ - < 35°C → 0% (fans off)
+ - 35–55°C → 45%
+ - 55–75°C → 80%
+ - ≥ 75°C → 100%
+ "Forbid unsafe settings" (Advanced menu) still applies a 40–99% clamp when enabled.
+
+- **5-second debounce**
+ In Auto mode, when temperature moves to a new range, the new fan speed is applied only after it has stayed in that range for 5 seconds, to avoid reacting to short spikes.
+
+- **Performance**
+ Hardware reads (CPU temp, fan RPM) run on a background thread and the refresh timer runs every 5 seconds to reduce system load and keep the UI responsive.
+
+- **UI**
+ - Temp ranges are shown on separate lines (no truncation).
+ - Window size is reduced to fit content with less empty space.
+ - Fixed single-window layout; form does not maximize.