cpu-temp 0.1.0

An Intel CPU temperature monitoring library for Windows and Linux using MSR access
Documentation
// Hwmon temperature reader for Linux
// Reads temperatures from /sys/class/hwmon

use std::fs;
use std::path::PathBuf;

/// Represents a hwmon sensor path and its prefix
#[derive(Clone)]
pub struct HwmonSensor {
    /// Path to the hwmon directory (e.g., /sys/class/hwmon/hwmon0)
    pub path: PathBuf,
    /// Sensor name (from name file)
    pub name: String,
}

/// Find all hwmon devices that represent CPU temperature sensors
pub fn find_cpu_hwmon_sensors() -> anyhow::Result<Vec<HwmonSensor>> {
    let mut sensors = Vec::new();

    for entry in fs::read_dir("/sys/class/hwmon")? {
        let entry = entry?;
        let path = entry.path();

        if !path.is_dir() {
            continue;
        }

        let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");

        // Read the hwmon name
        let hwmon_name_path = path.join("name");
        let hwmon_name = fs::read_to_string(&hwmon_name_path).ok();

        // Check if this is an Intel CPU sensor (intel_ platform name or has temp files)
        if let Some(ref name_str) = hwmon_name {
            if name_str.contains("coretemp") || name_str.contains("cpu") {
                let sensor = HwmonSensor {
                    path: path.clone(),
                    name: name_str.clone(),
                };
                sensors.push(sensor);
                continue;
            }
        }

        // Also check if it has temp files as a fallback
        let temp_input_path = path.join("temp1_input");
        if temp_input_path.exists() {
            let sensor = HwmonSensor {
                path: path.clone(),
                name: hwmon_name.unwrap_or_else(|| name.to_string()),
            };
            sensors.push(sensor);
        }
    }

    // Sort by name to get consistent ordering, prioritize coretemp
    sensors.sort_by(|a, b| {
        if a.name.contains("coretemp") {
            std::cmp::Ordering::Less
        } else if b.name.contains("coretemp") {
            std::cmp::Ordering::Greater
        } else {
            a.name.cmp(&b.name)
        }
    });

    Ok(sensors)
}

/// Temperature data from hwmon sensor
#[derive(Debug, Clone)]
pub struct HwmonTempData {
    pub id: u32,
    pub name: String,
    pub temperature: f32,
}

/// Read all temperatures from a hwmon sensor
pub fn read_hwmon_temperatures(sensor: &HwmonSensor) -> anyhow::Result<Vec<HwmonTempData>> {
    let mut temps = Vec::new();
    let mut id = 1;

    loop {
        let temp_label = sensor.path.join(format!("temp{}_label", id));
        let temp_input = sensor.path.join(format!("temp{}_input", id));

        if !temp_input.exists() {
            break;
        }

        let temp_name = if temp_label.exists() {
            fs::read_to_string(&temp_label)
                .ok()
                .and_then(|s| {
                    let s = s.trim().to_string();
                    if s.is_empty() { None } else { Some(s) }
                })
                .unwrap_or(format!("temp{}", id))
        } else {
            format!("temp{}", id)
        };

        let value = fs::read_to_string(&temp_input)?;
        let temperature = value.trim().parse::<f32>()? / 1000.0;

        temps.push(HwmonTempData {
            id,
            name: temp_name,
            temperature,
        });

        id += 1;
    }

    Ok(temps)
}

/// Get TjMax for the CPU (typically 100°C for most Intel CPUs)
/// Try to read from cpuinfo or fallback to default
pub fn get_tj_max() -> f32 {
    // Try reading from cpuinfo
    let cpuinfo_path = "/proc/cpuinfo";
    if let Ok(content) = fs::read_to_string(cpuinfo_path) {
        for line in content.lines() {
            if line.starts_with("cpu M") && line.contains("TjMax") {
                if let Some(value_str) = line.split(':').nth(1) {
                    if let Ok(value) = value_str.trim().parse::<f32>() {
                        return value;
                    }
                }
            }
        }
    }

    // Fallback to common default values based on Intel architecture
    // Most modern Intel CPUs have TjMax of 100°C
    100.0
}