From a49c88a7c6b7617006dd06184057473a8d78704a Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Mon, 10 Aug 2020 19:28:53 +0200 Subject: [PATCH] Add default state and command-line arguments It is now possible to manually set the different levels with command-line arguments. --- Cargo.lock | 74 ++++++++++++++++++++++++++++- Cargo.toml | 3 ++ src/battery_state.rs | 62 +++++++++++++++++-------- src/main.rs | 108 ++++++++++++++++++++++++++++--------------- 4 files changed, 190 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 397a84d..33a1752 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,14 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + [[package]] name = "arrayref" version = "0.3.6" @@ -12,6 +21,17 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.0.0" @@ -93,6 +113,21 @@ dependencies = [ "time", ] +[[package]] +name = "clap" +version = "2.33.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10040cdf04294b565d9e0319955430099ec3813a64c952b86a41200ad714ae48" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.2.1", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -158,6 +193,15 @@ dependencies = [ "wasi", ] +[[package]] +name = "hermit-abi" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +dependencies = [ + "libc", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -294,10 +338,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" [[package]] -name = "power-manager" +name = "pumopm" version = "0.1.0" dependencies = [ "battery", + "clap", "notify-rust", ] @@ -336,6 +381,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strum" version = "0.8.0" @@ -372,6 +423,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "time" version = "0.1.43" @@ -388,6 +448,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + [[package]] name = "unicode-xid" version = "0.0.4" @@ -404,6 +470,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "void" version = "1.0.2" diff --git a/Cargo.toml b/Cargo.toml index fae1ac0..5f75833 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,9 +5,12 @@ authors = ["Lucien Cartier-Tilet "] edition = "2018" description = "Simple power manager for systemd-based Linux" repository = "https://labs.phundrak.com/phundrak/pumopm" +license = "GPL-3.0-or-later" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] battery = "0.7.5" notify-rust = "4" +clap = "2.33" diff --git a/src/battery_state.rs b/src/battery_state.rs index be3e7e6..f51a4bc 100644 --- a/src/battery_state.rs +++ b/src/battery_state.rs @@ -1,21 +1,33 @@ -use notify_rust::{Notification, Hint, Urgency}; +use notify_rust::{Hint, Notification, Urgency}; pub struct BatteryState { - manager: battery::Manager, - battery: battery::Battery, - low_level: f32, - very_low_level: f32, - pub is_triggered_low: bool, + manager: battery::Manager, + battery: battery::Battery, + low_level: f32, + very_low_level: f32, + critical_level: f32, + refresh_rate: u8, + pub is_triggered_low: bool, pub is_triggered_very_low: bool, } +pub const DEFAULT_LOW: f32 = 25_f32; +pub const DEFAULT_VERY_LOW: f32 = 15_f32; +pub const DEFAULT_CRITICAL: f32 = 10_f32; +pub const DEFAULT_REFRESH: u8 = 5_u8; + impl BatteryState { - pub fn new(low_level: f32, very_low_level: f32) -> battery::Result { + pub fn new( + low_level: f32, + very_low_level: f32, + critical_level: f32, + refresh_rate: u8, + ) -> battery::Result { let manager = battery::Manager::new().unwrap(); let battery = match manager.batteries().unwrap().next() { Some(Ok(battery)) => battery, Some(Err(e)) => { - eprintln!("An error occured: {:?}", e); + eprintln!("An error occured: {}", e); return Err(e); } None => { @@ -30,17 +42,19 @@ impl BatteryState { battery, low_level, very_low_level, - is_triggered_low: false, + critical_level, + refresh_rate, + is_triggered_low: false, is_triggered_very_low: false, }) } fn get_charge(&self) -> f32 { - self.battery.state_of_charge().value * 100.0 + self.battery.state_of_charge().value * 100_f32 } fn reset_levels(&mut self) { - self.is_triggered_low = false; + self.is_triggered_low = false; self.is_triggered_very_low = false; } @@ -52,7 +66,8 @@ impl BatteryState { None => String::from("unknown"), }; let level = self.battery.state_of_charge().value * 100.0; - let message = format!("Battery level is low! {} left ({}%)", time, level); + let message = + format!("Battery level is low! {} left ({}%)", time, level); Notification::new() .summary("Low Battery") .body(message.as_str()) @@ -71,7 +86,10 @@ impl BatteryState { None => String::from("unknown"), }; let level = self.battery.state_of_charge().value * 100.0; - let message = format!("Battery level is very low! {} left ({}%)", time, level); + let message = format!( + "Battery level is very low! {} left ({}%)", + time, level + ); Notification::new() .summary("Low Battery") .body(message.as_str()) @@ -86,12 +104,10 @@ impl BatteryState { self.manager.refresh(&mut self.battery).unwrap(); use battery::State::{Discharging, Empty}; match self.battery.state() { - Discharging | Empty => { - match self.get_charge() { - x if x < self.very_low_level => self.trigger_very_low(), - x if x < self.low_level => self.trigger_low(), - _ => {}, - } + Discharging | Empty => match self.get_charge() { + x if x < self.very_low_level => self.trigger_very_low(), + x if x < self.low_level => self.trigger_low(), + _ => {} }, _ => self.reset_levels(), } @@ -100,6 +116,12 @@ impl BatteryState { impl Default for BatteryState { fn default() -> Self { - Self::new(15 as f32, 10 as f32).unwrap() + Self::new( + DEFAULT_LOW, + DEFAULT_VERY_LOW, + DEFAULT_CRITICAL, + DEFAULT_REFRESH, + ) + .unwrap() } } diff --git a/src/main.rs b/src/main.rs index 75c69cd..dab206e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,46 +1,82 @@ mod battery_state; -use std::{io, thread}; -use std::{process::Command, time::Duration}; +const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION"); +const AUTHORS: Option<&'static str> = option_env!("CARGO_PKG_AUTHORS"); + +use clap::{App, Arg}; +use std::{thread, time::Duration}; + +macro_rules! get_arg_value { + ($args:ident, $arg:literal, $type:ty, $default:ident) => { + match $args.value_of($arg) { + Some(value) => match value.parse::<$type>() { + Ok(ret) => ret, + Err(e) => { + eprintln!( + "Error parsing {}, using default. Error: {}", + value, e + ); + $default + } + }, + None => $default, + } + }; +} fn main() { - let mut battery = battery_state::BatteryState::default(); + let arguments = App::new("PumoPM") + .version(VERSION.unwrap_or("unknown")) + .author(AUTHORS.unwrap_or("Lucien Cartier-Tilet ")) + .about("Tiny custom power manager") + .arg(Arg::with_name("low-battery") + .short("l") + .long("low") + .value_name("LOW") + .help("Level at which the battery’s level is considered low") + .takes_value(true)) + .arg(Arg::with_name("very-low-battery") + .short("L") + .long("very-low") + .value_name("VERY LOW") + .help("Level at which the battery’s level is considered very low") + .takes_value(true)) + .arg(Arg::with_name("critical-battery") + .short("c") + .long("critical") + .value_name("CRITICAL") + .help("Level at which the battery’s level is considered critical") + .takes_value(true)) + .arg(Arg::with_name("refresh-rate") + .short("r") + .long("refresh-rate") + .value_name("REFRESH RATE") + .help("How often should the battery’s levels be read (in seconds)") + .takes_value(true)) + .get_matches(); + use battery_state::{ + DEFAULT_CRITICAL, DEFAULT_LOW, DEFAULT_REFRESH, DEFAULT_VERY_LOW, + }; + let low_battery = + get_arg_value!(arguments, "low-battery", f32, DEFAULT_LOW); + let very_low_battery = + get_arg_value!(arguments, "very-low-battery", f32, DEFAULT_VERY_LOW); + let critical_battery = + get_arg_value!(arguments, "critical-battery", f32, DEFAULT_CRITICAL); + let refresh_rate = + get_arg_value!(arguments, "refresh-rate", u8, DEFAULT_REFRESH); + + // let mut battery = battery_state::BatteryState::new(low_battery); + let mut battery = battery_state::BatteryState::new( + low_battery, + very_low_battery, + critical_battery, + refresh_rate, + ) + .unwrap(); loop { thread::sleep(Duration::from_secs(5)); battery.update(); } - - // loop { - // thread::sleep(Duration::from_secs(5)); - // manager.refresh(&mut battery)?; - // let charge = battery.state_of_charge().value; - - // // let charge = charge.value as f32 * 100.0; - - // // Notification::new() - // // .summary("Battery charge") - // // .body(format!("Current battery level is {}", charge).as_str()) - // // .hint(Hint::Category("battery".to_owned())) - // // .urgency(Urgency::Low) - // // .show() - // // .unwrap(); - - // // let result = match charge.value as f32 * 100.0 { - // // x if x < 5.0 => Command::new("sh") - // // .arg("systemctl") - // // .arg("hibernate") - // // .output(), - // // x if x < 10.0 => { - // // Notification::new() - // // .summary("Battery very low") - // // .body(format!("Current battery level is {}", x).as_str()) - // // .hint(Hint::Category("battery".to_owned())) - // // .urgency(Urgency::Critical) - // // .show().unwrap(); - // // }, - // // _ => Ok(()), - // // }; - - // } }