Add power supply widget based loosely on https://github.com/hastinbe/i3blocks-battery-plus/blob/master/battery-plus
This commit is contained in:
@@ -7,6 +7,7 @@ use structopt::StructOpt;
|
||||
use i3xs::widgets::cpu::CpuWidget;
|
||||
use i3xs::widgets::datetime::{DateTimeWidget, TimeColor};
|
||||
use i3xs::widgets::network::NetworkSpeedWidget;
|
||||
use i3xs::widgets::power::PowerSupply;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "i3xs", about = "Custom i3 status bar program.")]
|
||||
@@ -20,6 +21,7 @@ fn main() {
|
||||
|
||||
let opts = Opt::from_args();
|
||||
|
||||
bar.push(PowerSupply::default());
|
||||
bar.push(CpuWidget::new());
|
||||
|
||||
// Realtime upload/download rate for a interface
|
||||
|
||||
@@ -7,6 +7,7 @@ use structopt::StructOpt;
|
||||
use i3xs::widgets::cpu::CpuWidget;
|
||||
use i3xs::widgets::datetime::{DateTimeWidget, TimeColor};
|
||||
use i3xs::widgets::network::NetworkSpeedWidget;
|
||||
use i3xs::widgets::power::PowerSupply;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "i3xs", about = "Custom i3 status bar program.")]
|
||||
@@ -20,6 +21,7 @@ fn main() {
|
||||
|
||||
let opts = Opt::from_args();
|
||||
|
||||
bar.push(PowerSupply::default());
|
||||
bar.push(CpuWidget::new());
|
||||
|
||||
// Realtime upload/download rate for a interface
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod cpu;
|
||||
pub mod datetime;
|
||||
pub mod network;
|
||||
pub mod power;
|
||||
|
||||
107
src/widgets/power.rs
Normal file
107
src/widgets/power.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
//! ::::::::::::::
|
||||
//! /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<Vec<String>, 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::<Result<_, _>>()?;
|
||||
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!(
|
||||
"{} {}: <span face=\"pango:Font Awesome 5 Free\">{}</span>",
|
||||
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<WidgetUpdate> {
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user