mod helper_functions;
mod iterator;
use super::error::{Error, Result};
use helper_functions::*;
pub use iterator::{Iter, NamedIter};
use crate::parsing::{Error as ParsingError, Result as ParsingResult};
use crate::sensors::async_sensors::{
curr::*, energy::*, fan::*, humidity::*, intrusion::*, power::*, pwm::*, temp::*, voltage::*,
};
use crate::units::Raw;
use tokio::fs::read_to_string;
use std::{
cmp::Ordering,
collections::BTreeMap,
fmt::Debug,
io::ErrorKind as IoErrorKind,
path::{Path, PathBuf},
time::Duration,
};
#[derive(Debug, Clone)]
pub struct Hwmon {
name: String,
label: Option<String>,
path: PathBuf,
index: u16,
currents: BTreeMap<u16, CurrentSensorStruct>,
energies: BTreeMap<u16, EnergySensorStruct>,
fans: BTreeMap<u16, FanSensorStruct>,
humidities: BTreeMap<u16, HumiditySensorStruct>,
intrusions: BTreeMap<u16, IntrusionSensorStruct>,
powers: BTreeMap<u16, PowerSensorStruct>,
pwms: BTreeMap<u16, PwmSensorStruct>,
temps: BTreeMap<u16, TempSensorStruct>,
voltages: BTreeMap<u16, VoltageSensorStruct>,
}
impl Hwmon {
pub fn name(&self) -> &str {
&self.name
}
pub fn label(&self) -> Option<&str> {
self.label.as_deref()
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn index(&self) -> u16 {
self.index
}
pub fn device_path(&self) -> PathBuf {
self.path().join("device").canonicalize().unwrap()
}
pub async fn update_interval(&self) -> Result<Duration> {
let path = self.path().join("update_interval");
match read_to_string(&path).await {
Ok(s) => Duration::from_raw(&s).map_err(|e| Error::unit(e, path)),
Err(e) => {
if e.kind() == IoErrorKind::NotFound {
Err(Error::update_interval_not_available())
} else {
Err(Error::io(e, path))
}
}
}
}
pub async fn beep_enable(&self) -> Result<bool> {
let path = self.path().join("beep_enable");
match read_to_string(&path).await {
Ok(s) => bool::from_raw(&s).map_err(|e| Error::unit(e, path)),
Err(e) => {
if e.kind() == IoErrorKind::NotFound {
Err(Error::beep_enable())
} else {
Err(Error::io(e, path))
}
}
}
}
pub fn currents(
&self,
) -> &BTreeMap<u16, impl AsyncCurrentSensor + Clone + Send + Sync + 'static> {
&self.currents
}
pub fn energies(
&self,
) -> &BTreeMap<u16, impl AsyncEnergySensor + Clone + Send + Sync + 'static> {
&self.energies
}
pub fn fans(&self) -> &BTreeMap<u16, impl AsyncFanSensor + Clone + Send + Sync + 'static> {
&self.fans
}
pub fn humidities(
&self,
) -> &BTreeMap<u16, impl AsyncHumiditySensor + Clone + Send + Sync + 'static> {
&self.humidities
}
pub fn intrusions(
&self,
) -> &BTreeMap<u16, impl AsyncIntrusionSensor + Clone + Send + Sync + 'static> {
&self.intrusions
}
pub fn powers(&self) -> &BTreeMap<u16, impl AsyncPowerSensor + Clone + Send + Sync + 'static> {
&self.powers
}
pub fn pwms(&self) -> &BTreeMap<u16, impl AsyncPwmSensor + Clone + Send + Sync + 'static> {
&self.pwms
}
pub fn temps(&self) -> &BTreeMap<u16, impl AsyncTempSensor + Clone + Send + Sync + 'static> {
&self.temps
}
pub fn voltages(
&self,
) -> &BTreeMap<u16, impl AsyncVoltageSensor + Clone + Send + Sync + 'static> {
&self.voltages
}
pub fn current(
&self,
index: u16,
) -> Option<&(impl AsyncCurrentSensor + Clone + Send + Sync + 'static)> {
self.currents.get(&index)
}
pub fn energy(
&self,
index: u16,
) -> Option<&(impl AsyncEnergySensor + Clone + Send + Sync + 'static)> {
self.energies.get(&index)
}
pub fn fan(
&self,
index: u16,
) -> Option<&(impl AsyncFanSensor + Clone + Send + Sync + 'static)> {
self.fans.get(&index)
}
pub fn humidity(
&self,
index: u16,
) -> Option<&(impl AsyncHumiditySensor + Clone + Send + Sync + 'static)> {
self.humidities.get(&index)
}
pub fn intrusion(
&self,
index: u16,
) -> Option<&(impl AsyncIntrusionSensor + Clone + Send + Sync + 'static)> {
self.intrusions.get(&index)
}
pub fn power(
&self,
index: u16,
) -> Option<&(impl AsyncPowerSensor + Clone + Send + Sync + 'static)> {
self.powers.get(&index)
}
pub fn pwm(
&self,
index: u16,
) -> Option<&(impl AsyncPwmSensor + Clone + Send + Sync + 'static)> {
self.pwms.get(&index)
}
pub fn temp(
&self,
index: u16,
) -> Option<&(impl AsyncTempSensor + Clone + Send + Sync + 'static)> {
self.temps.get(&index)
}
pub fn voltage(
&self,
index: u16,
) -> Option<&(impl AsyncVoltageSensor + Clone + Send + Sync + 'static)> {
self.voltages.get(&index)
}
pub(crate) async fn try_from_path(path: impl Into<PathBuf>, index: u16) -> ParsingResult<Self> {
let path = path.into();
check_path(&path)?;
let mut hwmon = Self {
name: get_name(&path).await?,
label: get_label(&path).await.ok(),
path,
index,
currents: BTreeMap::new(),
energies: BTreeMap::new(),
fans: BTreeMap::new(),
humidities: BTreeMap::new(),
intrusions: BTreeMap::new(),
powers: BTreeMap::new(),
pwms: BTreeMap::new(),
temps: BTreeMap::new(),
voltages: BTreeMap::new(),
};
hwmon.currents = init_sensors(&hwmon, 1).await?;
hwmon.energies = init_sensors(&hwmon, 1).await?;
hwmon.fans = init_sensors(&hwmon, 1).await?;
hwmon.humidities = init_sensors(&hwmon, 1).await?;
hwmon.intrusions = init_sensors(&hwmon, 0).await?;
hwmon.powers = init_sensors(&hwmon, 1).await?;
hwmon.pwms = init_sensors(&hwmon, 1).await?;
hwmon.temps = init_sensors(&hwmon, 1).await?;
hwmon.voltages = init_sensors(&hwmon, 0).await?;
Ok(hwmon)
}
}
#[cfg(feature = "writeable")]
impl Hwmon {
pub async fn set_update_interval(&self, interval: Duration) -> Result<()> {
let path = self.path().join("update_interval");
match tokio::fs::write(&path, interval.to_raw().as_bytes()).await {
Ok(_) => Ok(()),
Err(e) => match e.kind() {
IoErrorKind::NotFound => Err(Error::update_interval_not_available()),
IoErrorKind::PermissionDenied => Err(Error::insufficient_rights(path)),
_ => Err(Error::io(e, path)),
},
}
}
pub async fn set_beep_enable(&self, beep_enable: bool) -> Result<()> {
let path = self.path().join("beep_enable");
match tokio::fs::write(&path, beep_enable.to_raw().as_bytes()).await {
Ok(_) => Ok(()),
Err(e) => match e.kind() {
IoErrorKind::NotFound => Err(Error::beep_enable()),
IoErrorKind::PermissionDenied => Err(Error::insufficient_rights(path)),
_ => Err(Error::io(e, path)),
},
}
}
pub fn writeable_currents(
&self,
) -> &BTreeMap<u16, impl AsyncWriteableCurrentSensor + Clone + Send + Sync + 'static> {
&self.currents
}
pub fn writeable_energies(
&self,
) -> &BTreeMap<u16, impl AsyncWriteableEnergySensor + Clone + Send + Sync + 'static> {
&self.energies
}
pub fn writeable_fans(
&self,
) -> &BTreeMap<u16, impl AsyncWriteableFanSensor + Clone + Send + Sync + 'static> {
&self.fans
}
pub fn writeable_humidities(
&self,
) -> &BTreeMap<u16, impl AsyncWriteableHumiditySensor + Clone + Send + Sync + 'static> {
&self.humidities
}
pub fn writeable_intrusions(
&self,
) -> &BTreeMap<u16, impl AsyncWriteableIntrusionSensor + Clone + Send + Sync + 'static> {
&self.intrusions
}
pub fn writeable_powers(
&self,
) -> &BTreeMap<u16, impl AsyncWriteablePowerSensor + Clone + Send + Sync + 'static> {
&self.powers
}
pub fn writeable_pwms(
&self,
) -> &BTreeMap<u16, impl AsyncWriteablePwmSensor + Clone + Send + Sync + 'static> {
&self.pwms
}
pub fn writeable_temps(
&self,
) -> &BTreeMap<u16, impl AsyncWriteableTempSensor + Clone + Send + Sync + 'static> {
&self.temps
}
pub fn writeable_voltages(
&self,
) -> &BTreeMap<u16, impl AsyncWriteableVoltageSensor + Clone + Send + Sync + 'static> {
&self.voltages
}
pub fn writeable_current(
&self,
index: u16,
) -> Option<&(impl AsyncWriteableCurrentSensor + Clone + Send + Sync + 'static)> {
self.currents.get(&index)
}
pub fn writeable_energy(
&self,
index: u16,
) -> Option<&(impl AsyncWriteableEnergySensor + Clone + Send + Sync + 'static)> {
self.energies.get(&index)
}
pub fn writeable_fan(
&self,
index: u16,
) -> Option<&(impl AsyncWriteableFanSensor + Clone + Send + Sync + 'static)> {
self.fans.get(&index)
}
pub fn writeable_humidity(
&self,
index: u16,
) -> Option<&(impl AsyncWriteableHumiditySensor + Clone + Send + Sync + 'static)> {
self.humidities.get(&index)
}
pub fn writeable_intrusion(
&self,
index: u16,
) -> Option<&(impl AsyncWriteableIntrusionSensor + Clone + Send + Sync + 'static)> {
self.intrusions.get(&index)
}
pub fn writeable_power(
&self,
index: u16,
) -> Option<&(impl AsyncWriteablePowerSensor + Clone + Send + Sync + 'static)> {
self.powers.get(&index)
}
pub fn writeable_pwm(
&self,
index: u16,
) -> Option<&(impl AsyncWriteablePwmSensor + Clone + Send + Sync + 'static)> {
self.pwms.get(&index)
}
pub fn writeable_temp(
&self,
index: u16,
) -> Option<&(impl AsyncWriteableTempSensor + Clone + Send + Sync + 'static)> {
self.temps.get(&index)
}
pub fn writeable_voltage(
&self,
index: u16,
) -> Option<&(impl AsyncWriteableVoltageSensor + Clone + Send + Sync + 'static)> {
self.voltages.get(&index)
}
}
impl PartialEq for Hwmon {
fn eq(&self, other: &Self) -> bool {
self.path.eq(other.path())
}
}
impl Eq for Hwmon {}
impl PartialOrd for Hwmon {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Hwmon {
fn cmp(&self, other: &Self) -> Ordering {
self.path.cmp(&other.path)
}
}
#[derive(Debug, Clone)]
pub struct Hwmons {
#[cfg(feature = "unrestricted_parsing")]
path: PathBuf,
hwmons: BTreeMap<u16, Hwmon>,
}
impl Hwmons {
pub async fn parse() -> ParsingResult<Self> {
Self::parse_path("/sys/class/hwmon/").await
}
pub fn hwmons_by_name<N: AsRef<str>>(&self, name: N) -> NamedIter<'_, N> {
NamedIter::new(self.iter(), name)
}
pub fn hwmon_by_index(&self, index: u16) -> Option<&Hwmon> {
self.hwmons.get(&index)
}
pub fn hwmon_by_device_path(&self, device_path: impl AsRef<Path>) -> Option<&Hwmon> {
self.hwmons
.values()
.find(move |&hwmon| hwmon.device_path() == device_path.as_ref())
}
pub fn iter(&self) -> Iter<'_> {
Iter::new(self.hwmons.iter())
}
#[cfg(feature = "unrestricted_parsing")]
pub async fn parse_unrestricted(path: impl AsRef<Path>) -> ParsingResult<Self> {
Self::parse_path(path).await
}
#[cfg(feature = "unrestricted_parsing")]
pub fn path(&self) -> &Path {
&self.path
}
pub(crate) async fn parse_path(path: impl AsRef<Path>) -> ParsingResult<Self> {
let path = path.as_ref();
let mut hwmons = Hwmons {
#[cfg(feature = "unrestricted_parsing")]
path: path.to_path_buf(),
hwmons: BTreeMap::new(),
};
let mut index;
for entry in path.read_dir().map_err(|e| ParsingError::hwmons(e, path))? {
let entry = entry.map_err(|e| ParsingError::hwmons(e, path))?;
let entry_path = entry.path();
if !entry_path.is_dir() {
continue;
}
let file_name = entry.file_name();
if let Some(index_str) = file_name.to_string_lossy().strip_prefix("hwmon") {
index = index_str
.parse()
.map_err(|e| ParsingError::hwmon_index(e, &entry_path))?;
} else {
continue;
}
hwmons
.hwmons
.insert(index, Hwmon::try_from_path(entry_path, index).await?);
}
Ok(hwmons)
}
}
#[cfg(test)]
mod tests;