diff --git a/src/commands/cooling.rs b/src/commands/cooling.rs new file mode 100644 index 0000000..4968b3b --- /dev/null +++ b/src/commands/cooling.rs @@ -0,0 +1,69 @@ +use crate::cli::CoolingCommands; +use crate::utils::system::assert_root; +use log::{debug, info}; +use std::fs; +use std::path::Path; + +fn set_ideapad_fan_mode(mode: &str) -> bool { + let mut success = false; + if let Ok(entries) = fs::read_dir("/sys/bus/platform/drivers/ideapad_acpi") { + for entry in entries.flatten() { + let path = entry.path().join("fan_mode"); + if path.exists() { + match fs::write(&path, mode) { + Ok(_) => { + info!("Set Ideapad fan_mode to {}", mode); + success = true; + } + Err(e) => debug!("Failed to write to {}: {}", path.display(), e), + } + } + } + } + success +} + +fn set_asus_throttle_policy(mode: &str) -> bool { + let mut success = false; + let path = Path::new("/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy"); + if path.exists() { + match fs::write(path, mode) { + Ok(_) => { + info!("Set ASUS WMI thermal policy to {}", mode); + success = true; + } + Err(e) => debug!("Failed to write to {}: {}", path.display(), e), + } + } + success +} + + +pub fn execute(command: &CoolingCommands) { + assert_root(); + + let (ideapad_mode, asus_mode, desc) = match command { + CoolingCommands::Performance => ("1", "1", "Performance"), + CoolingCommands::Balanced => ("0", "0", "Balanced"), + CoolingCommands::Quiet => ("2", "2", "Quiet"), + }; + + println!("Setting thermal/cooling profile to {}", desc); + + let mut applied = false; + if set_ideapad_fan_mode(ideapad_mode) { + applied = true; + println!("Ideapad fan mode applied."); + } + + if set_asus_throttle_policy(asus_mode) { + applied = true; + println!("ASUS thermal policy applied."); + } + + if applied { + println!("Operation completed successfully."); + } else { + println!("Hardware does not respond to standard ACPI thermal overrides (Ideapad/ASUS)."); + } +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index a2de3c3..6da5d00 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,4 +1,5 @@ pub mod battery; +pub mod cooling; pub mod gpu; pub mod power; pub mod status; diff --git a/src/commands/status.rs b/src/commands/status.rs index 2ab6f4b..a6e592c 100644 --- a/src/commands/status.rs +++ b/src/commands/status.rs @@ -1,5 +1,6 @@ use crate::hardware::gpu; use std::fs; +use std::path::Path; pub fn execute() { println!("--- lapctl status ---"); @@ -54,4 +55,42 @@ pub fn execute() { } else { println!("Power Profile: Unknown"); } + + // Cooling / Thermal Status + let mut thermal_found = false; + if let Ok(ideapad_entries) = fs::read_dir("/sys/bus/platform/drivers/ideapad_acpi") { + for ideapad_entry in ideapad_entries.flatten() { + let fan_path = ideapad_entry.path().join("fan_mode"); + if fan_path.exists() { + if let Ok(mode) = fs::read_to_string(&fan_path) { + thermal_found = true; + let desc = match mode.trim() { + "1" => "Performance", + "0" => "Balanced", + "2" => "Quiet / Battery Saving", + _ => mode.trim() + }; + println!("Cooling Profile: {} (Ideapad)", desc); + } + } + } + } + + let asus_path = Path::new("/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy"); + if asus_path.exists() { + if let Ok(mode) = fs::read_to_string(asus_path) { + thermal_found = true; + let desc = match mode.trim() { + "1" => "Performance", + "0" => "Balanced", + "2" => "Quiet / Battery Saving", + _ => mode.trim() + }; + println!("Cooling Profile: {} (ASUS)", desc); + } + } + + if !thermal_found { + println!("Cooling Profile: Unknown / Firmware managed"); + } }