//! :::::::::::::: //! /sys/class/power_supply/hidpp_battery_8/uevent //! :::::::::::::: //! POWER_SUPPLY_NAME=hidpp_battery_8 //! POWER_SUPPLY_TYPE=Battery //! POWER_SUPPLY_ONLINE=1 //! POWER_SUPPLY_STATUS=Discharging //! POWER_SUPPLY_SCOPE=Device //! POWER_SUPPLY_MODEL_NAME=M570 //! POWER_SUPPLY_MANUFACTURER=Logitech //! POWER_SUPPLY_SERIAL_NUMBER=1028-26-d9-b5-38 //! POWER_SUPPLY_CAPACITY=65 use std::collections::HashMap; use glob::glob; use i3monkit::{Block, Widget, WidgetUpdate}; use thiserror::Error; #[derive(Debug, Default)] pub struct PowerSupply {} const POWER_SUPPLY_GLOB: &'static str = "/sys/class/power_supply/*/uevent"; #[derive(Error, Debug)] enum PowerSupplyError { #[error("IO error {0}")] IoError(#[from] std::io::Error), #[error("glob error {0}")] GlobError(#[from] glob::GlobError), #[error("pattern error {0}")] PatternError(#[from] glob::PatternError), #[error("UTF-8 error {0}")] Utf8Error(#[from] std::str::Utf8Error), #[error("parse number error {0}")] ParseIntErro(#[from] std::num::ParseIntError), #[error("parse error {0}")] ParseError(String), } impl PowerSupply { fn get_update(&mut self) -> Result, PowerSupplyError> { const BATT_100: &'static str = ""; const BATT_75: &'static str = ""; const BATT_50: &'static str = ""; const BATT_25: &'static str = ""; const BATT_0: &'static str = ""; let mut res = Vec::new(); for ps in glob(POWER_SUPPLY_GLOB)? { let bytes = std::fs::read(&ps?)?; let values: HashMap<&str, &str> = std::str::from_utf8(&bytes)? .lines() .map(|l| { l.split_once('=').ok_or(PowerSupplyError::ParseError( "missing = in uevent line".to_string(), )) }) .collect::>()?; let cap: u32 = values .get("POWER_SUPPLY_CAPACITY") .unwrap_or(&"0") .parse()?; let power = if cap >= 90 { BATT_100 } else if cap >= 70 { BATT_75 } else if cap >= 40 { BATT_50 } else if cap >= 20 { BATT_25 } else { BATT_0 }; res.push(format!( "{} {}: {}", values .get("POWER_SUPPLY_MANUFACTURER") .unwrap_or(&"Unknown mfg"), values .get("POWER_SUPPLY_MODEL_NAME") .unwrap_or(&"Unknown model"), power, )); } Ok(res) } } impl Widget for PowerSupply { fn update(&mut self) -> Option { match self.get_update() { Ok(statuses) => { let mut data = Block::new(); data.use_pango(); for status in statuses { data.append_full_text(&status); } return Some(WidgetUpdate { refresh_interval: std::time::Duration::new(1, 0), data: Some(data), }); } Err(err) => eprintln!("Failed to update: {}", err), } None } }