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::async_hwmon::Hwmon;
use crate::sensors::SensorSubFunctionType;
use crate::units::Raw;
use async_trait::async_trait;
use tokio::fs::read_to_string;
use std::path::{Path, PathBuf};
#[async_trait]
pub trait AsyncSensor: Sensor + Sync {
async fn name(&self) -> String {
self.read_raw(SensorSubFunctionType::Label)
.await
.unwrap_or_else(|_| format!("{}{}", self.base(), self.index()))
}
async 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).await {
Ok(value) => states.insert(sub_type, value),
Err(e) => match e {
Error::SubtypeNotSupported { .. } => continue,
_ => return Err(e),
},
};
}
Ok(SensorState { states })
}
async fn read_raw(&self, sub_type: SensorSubFunctionType) -> Result<String> {
let path = self.subfunction_path(sub_type);
match read_to_string(&path).await {
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)),
},
}
}
}
#[cfg(feature = "writeable")]
#[async_trait]
pub trait AsyncWriteableSensor: AsyncSensor {
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()
}
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()
}
async fn write_raw(&self, sub_type: SensorSubFunctionType, raw_value: &str) -> Result<()> {
let path = self.subfunction_path(sub_type);
tokio::fs::write(&path, raw_value.as_bytes())
.await
.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),
})
}
async fn reset_history(&self) -> Result<()> {
self.write_raw(SensorSubFunctionType::ResetHistory, &true.to_raw())
.await
}
async 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::SubtypeNotSupported { sub_type });
}
self.write_state_lossy(state).await
}
async 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).await {
match e {
Error::SubtypeNotSupported { .. } => continue,
_ => return Err(e),
}
}
}
Ok(())
}
}
async fn inspect_sensor<S: AsyncSensor>(
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)
}
#[async_trait]
pub(crate) trait AsyncSensorExt: AsyncSensor + Sized {
async fn parse(hwmon: &crate::hwmon::async_hwmon::Hwmon, index: u16) -> Result<Self>;
}
#[cfg(test)]
mod tests;