libmedium 0.13.4

Library to interface with lm_sensors
Documentation
use std::fs;
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::{Path, PathBuf};

use temp_dir::TempDir;

pub struct VirtualHwmonBuilder {
    root: PathBuf,
    index: u16,
}

#[allow(dead_code)]
impl VirtualHwmonBuilder {
    pub fn create(
        root: impl AsRef<Path>,
        index: u16,
        name: &str,
        label: Option<&str>,
    ) -> VirtualHwmonBuilder {
        let path = root.as_ref().join(format!("hwmon{}", index));

        fs::create_dir_all(&path).unwrap();

        File::create(path.join("name"))
            .unwrap()
            .write(name.as_ref())
            .unwrap();

        File::create(path.join("update_interval"))
            .unwrap()
            .write("1000".as_bytes())
            .unwrap();

        if let Some(label) = label {
            File::create(path.join("label"))
                .unwrap()
                .write(label.as_ref())
                .unwrap();
        }

        VirtualHwmonBuilder {
            root: root.as_ref().to_path_buf(),
            index,
        }
    }

    pub fn add_temp(self, index: u16, functions: &[(&str, &str)]) -> VirtualHwmonBuilder {
        for (function, value) in functions {
            OpenOptions::new()
                .read(true)
                .write(true)
                .create(true)
                .truncate(true)
                .open(self.path().join(format!("temp{}{}", index, function)))
                .unwrap()
                .write(value.as_bytes())
                .unwrap();
        }

        self
    }

    pub fn add_fan(self, index: u16, functions: &[(&str, &str)]) -> VirtualHwmonBuilder {
        for (function, value) in functions {
            OpenOptions::new()
                .read(true)
                .write(true)
                .create(true)
                .truncate(true)
                .open(self.path().join(format!("fan{}{}", index, function)))
                .unwrap()
                .write(value.as_bytes())
                .unwrap();
        }

        self
    }

    pub fn add_pwm(self, index: u16, functions: &[(&str, &str)]) -> VirtualHwmonBuilder {
        for (function, value) in functions {
            OpenOptions::new()
                .read(true)
                .write(true)
                .create(true)
                .truncate(true)
                .open(self.path().join(format!("pwm{}{}", index, function)))
                .unwrap()
                .write(value.as_bytes())
                .unwrap();
        }

        self
    }

    pub fn path(&self) -> PathBuf {
        self.root.join(format!("hwmon{}", self.index))
    }
}

#[cfg(feature = "virtual_sensors")]
pub struct VirtualSensorBuilder {
    path: PathBuf,
}

#[cfg(feature = "virtual_sensors")]
#[allow(dead_code)]
impl VirtualSensorBuilder {
    pub fn create(path: impl AsRef<Path>, value: Option<&str>) -> VirtualSensorBuilder {
        let path = path.as_ref();

        fs::create_dir_all(path.parent().unwrap()).unwrap();

        File::create(path)
            .unwrap()
            .write(value.unwrap_or_default().as_bytes())
            .unwrap();

        VirtualSensorBuilder {
            path: path.to_path_buf(),
        }
    }

    pub fn path(&self) -> PathBuf {
        self.path.to_path_buf()
    }
}

#[test]
#[cfg(feature = "sync")]
fn test_parse() {
    use crate::sensors::sync_sensors::{temp::TempSensor, SyncSensor};
    use crate::units::{Raw, Temperature};

    let test_dir = TempDir::new().unwrap();

    VirtualHwmonBuilder::create(test_dir.path(), 0, "system", None)
        .add_fan(1, &[("_input", "1000")])
        .add_fan(2, &[("_input", "1000")])
        .add_pwm(1, &[("_enable", "1"), ("_mode", "1"), ("", "255")])
        .add_pwm(2, &[("_enable", "1"), ("_mode", "1"), ("", "255")])
        .add_temp(1, &[("_input", "40000"), ("_label", "temp1")])
        .add_temp(2, &[("_input", "60000"), ("_label", "temp2")]);
    VirtualHwmonBuilder::create(test_dir.path(), 1, "other", None)
        .add_fan(1, &[("_input", "1000")])
        .add_fan(2, &[("_input", "1000")])
        .add_pwm(1, &[("_enable", "1"), ("_mode", "1"), ("", "255")])
        .add_temp(1, &[("_input", "40000"), ("_label", "temp1")]);

    let hwmons = crate::hwmon::sync_hwmon::Hwmons::parse_path(test_dir.path()).unwrap();
    let hwmon0 = hwmons.hwmons_by_name("system").next().unwrap();
    let hwmon1 = hwmons.hwmons_by_name("other").next().unwrap();

    assert_eq!(hwmon0.name(), hwmons.hwmon_by_index(0).unwrap().name());
    assert_eq!(hwmon1.name(), hwmons.hwmon_by_index(1).unwrap().name());

    assert_eq!(hwmons.hwmon_by_index(2).is_none(), true);
    assert_eq!(hwmons.hwmons_by_name("alias").next().is_none(), true);

    assert_eq!(hwmon0.temps().len(), 2);
    assert_eq!(hwmon1.temps().len(), 1);
    assert_eq!(hwmon0.pwms().len(), 2);
    assert_eq!(hwmon1.pwms().len(), 1);

    hwmon0.pwms().get(&1u16).unwrap();
    hwmon0.pwms().get(&2u16).unwrap();
    hwmon1.pwms().get(&1u16).unwrap();

    assert_eq!(
        hwmon0.temps().get(&1u16).unwrap().read_input().unwrap(),
        Temperature::from_raw("40000").unwrap()
    );
    assert_eq!(
        hwmon0.temps().get(&2u16).unwrap().read_input().unwrap(),
        Temperature::from_raw("60000").unwrap()
    );
    assert_eq!(
        hwmon1.temps().get(&1u16).unwrap().read_input().unwrap(),
        Temperature::from_raw("40000").unwrap()
    );

    assert_eq!(hwmon0.temps().get(&1u16).unwrap().name(), "temp1");
    assert_eq!(hwmon0.temps().get(&2u16).unwrap().name(), "temp2");
    assert_eq!(hwmon1.temps().get(&1u16).unwrap().name(), "temp1");
}

#[tokio::test]
#[cfg(feature = "async")]
async fn async_test_parse() {
    use crate::sensors::async_sensors::{temp::AsyncTempSensor, AsyncSensor};
    use crate::units::{Raw, Temperature};

    let test_dir = TempDir::new().unwrap();

    VirtualHwmonBuilder::create(test_dir.path(), 0, "system", None)
        .add_fan(1, &[("_input", "1000")])
        .add_fan(2, &[("_input", "1000")])
        .add_pwm(1, &[("_enable", "1"), ("_mode", "1"), ("", "255")])
        .add_pwm(2, &[("_enable", "1"), ("_mode", "1"), ("", "255")])
        .add_temp(1, &[("_input", "40000"), ("_label", "temp1")])
        .add_temp(2, &[("_input", "60000"), ("_label", "temp2")]);
    VirtualHwmonBuilder::create(test_dir.path(), 1, "other", None)
        .add_fan(1, &[("_input", "1000")])
        .add_fan(2, &[("_input", "1000")])
        .add_pwm(1, &[("_enable", "1"), ("_mode", "1"), ("", "255")])
        .add_temp(1, &[("_input", "40000"), ("_label", "temp1")]);

    let hwmons = crate::hwmon::async_hwmon::Hwmons::parse_path(test_dir.path())
        .await
        .unwrap();
    let hwmon0 = hwmons.hwmons_by_name("system").next().unwrap();
    let hwmon1 = hwmons.hwmons_by_name("other").next().unwrap();

    assert_eq!(hwmon0.name(), hwmons.hwmon_by_index(0).unwrap().name());
    assert_eq!(hwmon1.name(), hwmons.hwmon_by_index(1).unwrap().name());

    assert_eq!(hwmons.hwmon_by_index(2).is_none(), true);
    assert_eq!(hwmons.hwmons_by_name("alias").next().is_none(), true);

    assert_eq!(hwmon0.temps().len(), 2);
    assert_eq!(hwmon1.temps().len(), 1);
    assert_eq!(hwmon0.pwms().len(), 2);
    assert_eq!(hwmon1.pwms().len(), 1);

    hwmon0.pwms().get(&1u16).unwrap();
    hwmon0.pwms().get(&2u16).unwrap();
    hwmon1.pwms().get(&1u16).unwrap();

    assert_eq!(
        hwmon0
            .temps()
            .get(&1u16)
            .unwrap()
            .read_input()
            .await
            .unwrap(),
        Temperature::from_raw("40000").unwrap()
    );
    assert_eq!(
        hwmon0
            .temps()
            .get(&2u16)
            .unwrap()
            .read_input()
            .await
            .unwrap(),
        Temperature::from_raw("60000").unwrap()
    );
    assert_eq!(
        hwmon1
            .temps()
            .get(&1u16)
            .unwrap()
            .read_input()
            .await
            .unwrap(),
        Temperature::from_raw("40000").unwrap()
    );

    assert_eq!(hwmon0.temps().get(&1u16).unwrap().name().await, "temp1");
    assert_eq!(hwmon0.temps().get(&2u16).unwrap().name().await, "temp2");
    assert_eq!(hwmon1.temps().get(&1u16).unwrap().name().await, "temp1");
}