extern crate time; use comm; use comm::Channel; use config::Config; use std::fs::File; use std::io::SeekFrom; use std::io::prelude::*; use std::thread; trait Sensor { fn status(&mut self) -> String; } struct BatterySensor { charge_now: File, charge_full: File } impl BatterySensor { fn new(supply: &str) -> BatterySensor { let path = format!("/sys/class/power_supply/{}", supply); BatterySensor { charge_now: File::open(format!("{}/{}", path, "charge_now")).unwrap(), charge_full: File::open(format!("{}/{}", path, "charge_full")).unwrap() } } } impl Sensor for BatterySensor { fn status(&mut self) -> String { let mut s = String::new(); self.charge_now.read_to_string(&mut s).ok().expect("Could not read current charge"); let charge_now : u32 = s.trim().parse().ok().expect("Could not parse charge"); s.clear(); self.charge_full.read_to_string(&mut s).ok().expect("Could not read current charge"); let charge_full : u32 = s.trim().parse().ok().expect("Could not parse charge"); self.charge_now.seek(SeekFrom::Start(0)).ok(); self.charge_full.seek(SeekFrom::Start(0)).ok(); format!("{}%", charge_now / (charge_full / 100)) } } struct TempSensor { file: File } impl TempSensor { fn new(zone: &str) -> TempSensor { let path = format!("/sys/class/thermal/{}/temp", zone); TempSensor { file: File::open(path).unwrap() } } } impl Sensor for TempSensor { fn status(&mut self) -> String { let mut s = String::new(); self.file.read_to_string(&mut s).ok().expect("Could not read temperature stats"); let i : Option = s.trim().parse().ok(); self.file.seek(SeekFrom::Start(0)).ok().expect("Could not reread temperature"); match i { Some(i) => format!("{}°C", i/1000), None => "?°C".to_string(), } } } struct TimeSensor { format: String, is_utc: bool } impl TimeSensor { fn new(format: &str, is_utc: bool) -> TimeSensor { TimeSensor { format: format.to_string(), is_utc: is_utc } } } impl Sensor for TimeSensor { fn status(&mut self) -> String { let now = if self.is_utc { time::now_utc() } else { time::now() }; let time = time::strftime(&self.format, &now); time.unwrap() } } pub fn sensors(tx: &Channel, config: &Config) { let zone = config.lookup("sensors.thermal_zone").unwrap(); let zone = zone.as_str().unwrap(); let mut sensors: Vec> = vec![ Box::new(TempSensor::new(zone)), Box::new(TimeSensor::new("UTC %H:%M", true)), Box::new(TimeSensor::new("%Y-%m-%d %H:%M", false)) ]; let bat = config.lookup("sensors.battery"); let bat = bat.map(|bat| bat.as_str().unwrap()); bat.map(|bat| sensors.insert(0, Box::new(BatterySensor::new(bat)))); loop { let status = sensors.iter_mut() .map(|sensor| sensor.status()) .collect::>(); comm::send(tx, "sensors", &reduce(status)); thread::sleep_ms(1000); } } fn reduce(arr: Vec) -> String { let result = arr.into_iter() .fold("".to_string(), |acc, elem| format!("{} | {}", acc, elem)); if result.len() > 0 { result[3..].to_string() } else { result } }