libmedium 0.13.4

Library to interface with lm_sensors
Documentation
//! Module containing the sync sensors and their functionality.

pub mod curr;
pub mod energy;
pub mod fan;
pub mod humidity;
pub mod intrusion;
pub mod power;
pub mod pwm;
pub mod temp;
pub mod voltage;

#[cfg(feature = "virtual_sensors")]
pub mod virt;

use super::{
    error::{Error, Result},
    Sensor, SensorState,
};

use crate::hwmon::sync_hwmon::Hwmon;
use crate::sensors::SensorSubFunctionType;
use crate::units::Raw;

use std::{
    fs::read_to_string,
    path::{Path, PathBuf},
    time::Duration,
};

/// Trait that all sync sensors must implement.
/// It contains the functionality to get a sensor's name, state or read subfunctions.
pub trait SyncSensor: Sensor {
    /// If this sensor has a label, its contents are returned.
    /// Otherwise a plain sensor descriptor is returned.
    fn name(&self) -> String {
        self.read_raw(SensorSubFunctionType::Label)
            .unwrap_or_else(|_| format!("{}{}", self.base(), self.index()))
    }

    /// Returns a SensorState struct that represents the state of all writeable shared_subfunctions of this sensor.
    fn state(&self) -> Result<SensorState> {
        let mut states = std::collections::HashMap::new();

        for &sub_type in SensorSubFunctionType::read_write_list() {
            match self.read_raw(sub_type) {
                Ok(value) => states.insert(sub_type, value),
                Err(e) => match e {
                    Error::SubtypeNotSupported { .. } => continue,
                    _ => return Err(e),
                },
            };
        }

        Ok(SensorState { states })
    }

    /// Reads this sensor's subfunction with the given type and returns its value as a raw string.
    /// You should usually prefer the specialized read functions like read_input, because they
    /// automatically convert the read value to the right type.
    /// Returns an error, if this sensor doesn't support the subtype.
    fn read_raw(&self, sub_type: SensorSubFunctionType) -> Result<String> {
        let path = self.subfunction_path(sub_type);

        match read_to_string(&path) {
            Ok(s) => Ok(s.trim().to_string()),
            Err(e) => match e.kind() {
                std::io::ErrorKind::NotFound => Err(Error::subtype_not_supported(sub_type)),
                std::io::ErrorKind::PermissionDenied => Err(Error::insufficient_rights(path)),
                _ => Err(Error::read(e, path)),
            },
        }
    }
}

/// Base trait that all writeable sensors must implement.
#[cfg(feature = "writeable")]
pub trait WriteableSensor: Sensor {
    /// Returns a list of all writeable subfunction types supported by this sensor.
    fn supported_write_sub_functions(&self) -> Vec<SensorSubFunctionType> {
        SensorSubFunctionType::write_list()
            .filter(|&s| {
                std::fs::OpenOptions::new()
                    .write(true)
                    .open(self.subfunction_path(s))
                    .is_ok()
            })
            .collect()
    }

    /// Returns a list of all readable and writeable subfunction types supported by this sensor.
    fn supported_read_write_sub_functions(&self) -> Vec<SensorSubFunctionType> {
        SensorSubFunctionType::read_write_list()
            .iter()
            .copied()
            .filter(|&s| {
                std::fs::OpenOptions::new()
                    .read(true)
                    .write(true)
                    .open(self.subfunction_path(s))
                    .is_ok()
            })
            .collect()
    }

    /// Writes the given raw string value to this sensor's subfunction with the given type.
    /// You should usually prefer the specialized write functions like write_enable, because they
    /// ensure that no type mismatches occur.
    /// Returns an error, if this sensor doesn't support the subtype.
    fn write_raw(&self, sub_type: SensorSubFunctionType, raw_value: &str) -> Result<()> {
        let path = self.subfunction_path(sub_type);

        std::fs::write(&path, raw_value.as_bytes()).map_err(|e| match e.kind() {
            std::io::ErrorKind::NotFound => Error::subtype_not_supported(sub_type),
            std::io::ErrorKind::PermissionDenied => Error::insufficient_rights(path),
            _ => Error::write(e, path),
        })
    }

    /// Resets this sensor's history.
    /// Returns an error if this functionality is not supported by the sensor.
    fn reset_history(&self) -> Result<()> {
        self.write_raw(SensorSubFunctionType::ResetHistory, &true.to_raw())
    }

    /// Writes the given state to this sensor.
    /// Returns an error and writes nothing if the given state contains one or more shared_subfunctions that this sensor does not support.
    fn write_state(&self, state: &SensorState) -> Result<()> {
        if let Some(&sub_type) = state
            .states
            .keys()
            .find(|s| !self.supported_write_sub_functions().contains(s))
        {
            return Err(Error::subtype_not_supported(sub_type));
        }

        self.write_state_lossy(state)
    }

    /// Writes the given state to this sensor.
    /// All subfunction types contained in the given state that are not supported by this sensor will be ignored.
    fn write_state_lossy(&self, state: &SensorState) -> Result<()> {
        for (&sub_type, raw_value) in &state.states {
            if let Err(e) = self.write_raw(sub_type, raw_value) {
                match e {
                    Error::SubtypeNotSupported { .. } => continue,
                    _ => return Err(e),
                }
            }
        }

        Ok(())
    }
}

fn inspect_sensor<S: Sensor>(sensor: S, primary_subfunction: SensorSubFunctionType) -> Result<S> {
    let primary_path = sensor.subfunction_path(primary_subfunction);

    if let Err(e) = primary_path.metadata() {
        return Err(Error::read(e, primary_path));
    }

    Ok(sensor)
}

pub(crate) trait SyncSensorExt: SyncSensor + Sized {
    fn parse(hwmon: &crate::hwmon::sync_hwmon::Hwmon, index: u16) -> Result<Self>;
}

#[cfg(test)]
mod tests;