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. + ![AsusFanControlGUI](https://github.com/Karmel0x/AsusFanControl/assets/25367564/fe197ad0-7079-4d51-ae78-177cb6369e96) ### 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.