mtemp 0.1.23

CLI for monitoring temperatures
Documentation
use crate::sensor_names::{CPU_NAMES, DISK_NAMES, TEMP_NAMES};
use anyhow::{anyhow, Result};
use core::f64;
use serde::Deserialize;
use std::{collections::BTreeMap, process::Command};

#[derive(Debug)]
pub struct SensorData {
    chips: BTreeMap<String, Sensor>,
}

impl SensorData {
    pub fn cpu_chip(&self) -> Option<&Sensor> {
        for cpu_name in CPU_NAMES {
            if let Some(chip) = self.chips.get(cpu_name) {
                return Some(chip);
            }
        }
        None
    }

    pub fn disk_chip(&self) -> Option<&Sensor> {
        for disk_name in DISK_NAMES {
            if let Some(chip) = self.chips.get(disk_name) {
                return Some(chip);
            }
        }
        None
    }
}

#[derive(Debug, Deserialize)]
pub struct Sensor {
    #[serde(rename = "Adapter")]
    _adapter: String,

    #[serde(rename = "Tctl", skip_serializing_if = "Option::is_none")]
    tctl: Option<BTreeMap<String, f64>>,

    #[serde(rename = "Tccd1", skip_serializing_if = "Option::is_none")]
    tccd1: Option<BTreeMap<String, f64>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    temp1: Option<BTreeMap<String, f64>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    temp2: Option<BTreeMap<String, f64>>,

    #[serde(rename = "Package id 0", skip_serializing_if = "Option::is_none")]
    package_id_0: Option<BTreeMap<String, f64>>,

    #[serde(rename = "Composite", skip_serializing_if = "Option::is_none")]
    composite: Option<BTreeMap<String, f64>>,
}

impl Sensor {
    pub fn temp(&self) -> Option<f64> {
        let temperatures = self.actual_sector()?;
        for temp_name in TEMP_NAMES {
            if let Some(temp) = temperatures.get(temp_name) {
                return Some(*temp);
            }
        }
        None
    }

    fn actual_sector(&self) -> Option<BTreeMap<String, f64>> {
        if self.tctl.is_some() {
            return self.tctl.clone();
        }

        if self.tccd1.is_some() {
            return self.tccd1.clone();
        }

        if self.temp1.is_some() {
            return self.temp1.clone();
        }

        if self.temp2.is_some() {
            return self.temp2.clone();
        }

        if self.package_id_0.is_some() {
            return self.package_id_0.clone();
        }

        if self.composite.is_some() {
            return self.composite.clone();
        }

        None
    }
}

pub fn sensors_data() -> Result<SensorData> {
    let output = Command::new("sensors").arg("-j").output()?;

    if output.status.success() {
        let json_output = String::from_utf8_lossy(&output.stdout).to_string();
        let sensors_data: Result<BTreeMap<String, Sensor>, serde_json::Error> =
            serde_json::from_str(&json_output);
        match sensors_data {
            Ok(chips) => Ok(SensorData { chips }),
            Err(err) => Err(anyhow!(err)),
        }
    } else {
        Err(anyhow!(String::from_utf8_lossy(&output.stderr).to_string()))
    }
}