sensors.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. extern crate time;
  2. use comm;
  3. use comm::Channel;
  4. use config::Config;
  5. use std::fs::File;
  6. use std::io::SeekFrom;
  7. use std::io::prelude::*;
  8. use std::thread;
  9. trait Sensor {
  10. fn status(&mut self) -> String;
  11. }
  12. struct BatterySensor {
  13. charge_now: File,
  14. charge_full: File
  15. }
  16. impl BatterySensor {
  17. fn new(supply: &str) -> BatterySensor {
  18. let path = format!("/sys/class/power_supply/{}", supply);
  19. BatterySensor {
  20. charge_now: File::open(format!("{}/{}", path, "charge_now")).unwrap(),
  21. charge_full: File::open(format!("{}/{}", path, "charge_full")).unwrap()
  22. }
  23. }
  24. }
  25. impl Sensor for BatterySensor {
  26. fn status(&mut self) -> String {
  27. let mut s = String::new();
  28. self.charge_now.read_to_string(&mut s).ok().expect("Could not read current charge");
  29. let charge_now : u32 = s.trim().parse().ok().expect("Could not parse charge");
  30. s.clear();
  31. self.charge_full.read_to_string(&mut s).ok().expect("Could not read current charge");
  32. let charge_full : u32 = s.trim().parse().ok().expect("Could not parse charge");
  33. self.charge_now.seek(SeekFrom::Start(0)).ok();
  34. self.charge_full.seek(SeekFrom::Start(0)).ok();
  35. format!("{}%", charge_now / (charge_full / 100))
  36. }
  37. }
  38. struct TempSensor {
  39. file: File
  40. }
  41. impl TempSensor {
  42. fn new(zone: &str) -> TempSensor {
  43. let path = format!("/sys/class/thermal/{}/temp", zone);
  44. TempSensor {
  45. file: File::open(path).unwrap()
  46. }
  47. }
  48. }
  49. impl Sensor for TempSensor {
  50. fn status(&mut self) -> String {
  51. let mut s = String::new();
  52. self.file.read_to_string(&mut s).ok().expect("Could not read temperature stats");
  53. let i : Option<u32> = s.trim().parse().ok();
  54. self.file.seek(SeekFrom::Start(0)).ok().expect("Could not reread temperature");
  55. match i {
  56. Some(i) => format!("{}°C", i/1000),
  57. None => "?°C".to_string(),
  58. }
  59. }
  60. }
  61. struct TimeSensor {
  62. format: String,
  63. is_utc: bool
  64. }
  65. impl TimeSensor {
  66. fn new(format: &str, is_utc: bool) -> TimeSensor {
  67. TimeSensor {
  68. format: format.to_string(),
  69. is_utc: is_utc
  70. }
  71. }
  72. }
  73. impl Sensor for TimeSensor {
  74. fn status(&mut self) -> String {
  75. let now =
  76. if self.is_utc {
  77. time::now_utc()
  78. }
  79. else {
  80. time::now()
  81. };
  82. let time = time::strftime(&self.format, &now);
  83. time.unwrap()
  84. }
  85. }
  86. pub fn sensors(tx: &Channel, config: &Config) {
  87. let zone = config.lookup("sensors.thermal_zone").unwrap();
  88. let zone = zone.as_str().unwrap();
  89. let mut sensors: Vec<Box<Sensor>> = vec![
  90. Box::new(TempSensor::new(zone)),
  91. Box::new(TimeSensor::new("UTC %H:%M", true)),
  92. Box::new(TimeSensor::new("%Y-%m-%d %H:%M", false))
  93. ];
  94. let bat = config.lookup("sensors.battery");
  95. let bat = bat.map(|bat| bat.as_str().unwrap());
  96. bat.map(|bat| sensors.insert(0, Box::new(BatterySensor::new(bat))));
  97. loop {
  98. let status = sensors.iter_mut()
  99. .map(|sensor| sensor.status())
  100. .collect::<Vec<String>>();
  101. comm::send(tx, "sensors", &reduce(status));
  102. thread::sleep_ms(1000);
  103. }
  104. }
  105. fn reduce(arr: Vec<String>) -> String {
  106. let result = arr.into_iter()
  107. .fold("".to_string(), |acc, elem| format!("{} | {}", acc, elem));
  108. if result.len() > 0 { result[3..].to_string() } else { result }
  109. }