Re-add battery stats

This commit is contained in:
NGnius (Graham) 2022-09-05 17:02:02 -04:00
parent db3f4a85c0
commit 26e781df25
10 changed files with 118 additions and 15 deletions

2
backend/Cargo.lock generated
View file

@ -567,7 +567,7 @@ dependencies = [
[[package]] [[package]]
name = "powertools-rs" name = "powertools-rs"
version = "1.0.0-beta4" version = "1.0.0-rc1"
dependencies = [ dependencies = [
"log", "log",
"serde", "serde",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "powertools-rs" name = "powertools-rs"
version = "1.0.0-beta4" version = "1.0.0-rc1"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View file

@ -6,7 +6,22 @@ use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
/// Current current (ha!) web method /// Current current (ha!) web method
pub fn current_now(_: super::ApiParameterType) -> super::ApiParameterType { pub fn current_now(_: super::ApiParameterType) -> super::ApiParameterType {
super::utility::map_result(crate::settings::Battery::current_now()) super::utility::map_result(crate::settings::Battery::read_current_now())
}
/// Charge now web method
pub fn charge_now(_: super::ApiParameterType) -> super::ApiParameterType {
super::utility::map_result(crate::settings::Battery::read_charge_now())
}
/// Charge full web method
pub fn charge_full(_: super::ApiParameterType) -> super::ApiParameterType {
super::utility::map_result(crate::settings::Battery::read_charge_full())
}
/// Charge design web method
pub fn charge_design(_: super::ApiParameterType) -> super::ApiParameterType {
super::utility::map_result(crate::settings::Battery::read_charge_design())
} }
/// Generate set battery charge rate web method /// Generate set battery charge rate web method

View file

@ -17,11 +17,14 @@ use usdpl_back::core::serdes::Primitive;
use usdpl_back::Instance; use usdpl_back::Instance;
fn main() -> Result<(), ()> { fn main() -> Result<(), ()> {
#[cfg(debug_assertions)]
let log_filepath = format!("/home/deck/{}.log", PACKAGE_NAME); let log_filepath = format!("/home/deck/{}.log", PACKAGE_NAME);
#[cfg(not(debug_assertions))]
let log_filepath = format!("/tmp/{}.log", PACKAGE_NAME);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
if std::path::Path::new(&log_filepath).exists() { if std::path::Path::new(&log_filepath).exists() {
std::fs::copy(&log_filepath, "/home/deck/powertools.log.old").unwrap(); std::fs::copy(&log_filepath, format!("/home/deck/{}.log.old", PACKAGE_NAME)).unwrap();
} }
} }
WriteLogger::init( WriteLogger::init(
@ -59,6 +62,9 @@ fn main() -> Result<(), ()> {
}) })
// battery API functions // battery API functions
.register("BATTERY_current_now", api::battery::current_now) .register("BATTERY_current_now", api::battery::current_now)
.register("BATTERY_charge_now", api::battery::charge_now)
.register("BATTERY_charge_full", api::battery::charge_full)
.register("BATTERY_charge_design", api::battery::charge_design)
.register( .register(
"BATTERY_set_charge_rate", "BATTERY_set_charge_rate",
api::battery::set_charge_rate(loaded_settings.battery.clone(), save_sender.clone()), api::battery::set_charge_rate(loaded_settings.battery.clone(), save_sender.clone()),

View file

@ -9,8 +9,13 @@ pub struct Battery {
state: crate::state::Battery, state: crate::state::Battery,
} }
const BATTERY_VOLTAGE: f64 = 7.7;
const BATTERY_CHARGE_RATE_PATH: &str = "/sys/class/hwmon/hwmon5/maximum_battery_charge_rate"; // write-only const BATTERY_CHARGE_RATE_PATH: &str = "/sys/class/hwmon/hwmon5/maximum_battery_charge_rate"; // write-only
const BATTERY_CURRENT_NOW_PATH: &str = "/sys/class/power_supply/BAT1/current_now"; // read-only const BATTERY_CURRENT_NOW_PATH: &str = "/sys/class/power_supply/BAT1/current_now"; // read-only
const BATTERY_CHARGE_NOW_PATH: &str = "/sys/class/hwmon/hwmon2/device/charge_now"; // read-only
const BATTERY_CHARGE_FULL_PATH: &str = "/sys/class/hwmon/hwmon2/device/charge_full"; // read-only
const BATTERY_CHARGE_DESIGN_PATH: &str = "/sys/class/hwmon/hwmon2/device/charge_full_design"; // read-only
impl Battery { impl Battery {
#[inline] #[inline]
@ -57,7 +62,7 @@ impl Battery {
} }
} }
pub fn current_now() -> Result<u64, SettingError> { pub fn read_current_now() -> Result<u64, SettingError> {
match usdpl_back::api::files::read_single::<_, u64, _>(BATTERY_CURRENT_NOW_PATH) { match usdpl_back::api::files::read_single::<_, u64, _>(BATTERY_CURRENT_NOW_PATH) {
Err((Some(e), None)) => Err(SettingError { Err((Some(e), None)) => Err(SettingError {
msg: format!("Failed to read from `{}`: {}", BATTERY_CURRENT_NOW_PATH, e), msg: format!("Failed to read from `{}`: {}", BATTERY_CURRENT_NOW_PATH, e),
@ -77,6 +82,63 @@ impl Battery {
} }
} }
pub fn read_charge_now() -> Result<f64, SettingError> {
match usdpl_back::api::files::read_single::<_, u64, _>(BATTERY_CHARGE_NOW_PATH) {
Err((Some(e), None)) => Err(SettingError {
msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_NOW_PATH, e),
setting: super::SettingVariant::Battery,
}),
Err((None, Some(e))) => Err(SettingError {
msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_NOW_PATH, e),
setting: super::SettingVariant::Battery,
}),
Err(_) => panic!(
"Invalid error while reading from `{}`",
BATTERY_CHARGE_NOW_PATH
),
// convert to Wh
Ok(val) => Ok((val as f64) / 1000000.0 * BATTERY_VOLTAGE),
}
}
pub fn read_charge_full() -> Result<f64, SettingError> {
match usdpl_back::api::files::read_single::<_, u64, _>(BATTERY_CHARGE_FULL_PATH) {
Err((Some(e), None)) => Err(SettingError {
msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_FULL_PATH, e),
setting: super::SettingVariant::Battery,
}),
Err((None, Some(e))) => Err(SettingError {
msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_FULL_PATH, e),
setting: super::SettingVariant::Battery,
}),
Err(_) => panic!(
"Invalid error while reading from `{}`",
BATTERY_CHARGE_NOW_PATH
),
// convert to Wh
Ok(val) => Ok((val as f64) / 1000000.0 * BATTERY_VOLTAGE),
}
}
pub fn read_charge_design() -> Result<f64, SettingError> {
match usdpl_back::api::files::read_single::<_, u64, _>(BATTERY_CHARGE_DESIGN_PATH) {
Err((Some(e), None)) => Err(SettingError {
msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_DESIGN_PATH, e),
setting: super::SettingVariant::Battery,
}),
Err((None, Some(e))) => Err(SettingError {
msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_DESIGN_PATH, e),
setting: super::SettingVariant::Battery,
}),
Err(_) => panic!(
"Invalid error while reading from `{}`",
BATTERY_CHARGE_NOW_PATH
),
// convert to Wh
Ok(val) => Ok((val as f64) / 1000000.0 * BATTERY_VOLTAGE),
}
}
pub fn system_default() -> Self { pub fn system_default() -> Self {
Self { Self {
charge_rate: None, charge_rate: None,

View file

@ -11,6 +11,6 @@ class Plugin:
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded # Asyncio-compatible long-running code, executed in a task when the plugin is loaded
async def _main(self): async def _main(self):
# startup # startup
#self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend"]) self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend"])
while True: while True:
await asyncio.sleep(1) await asyncio.sleep(1)

View file

@ -1,6 +1,6 @@
{ {
"name": "PowerTools", "name": "PowerTools",
"version": "1.0.0-alpha", "version": "1.0.0-rc1",
"description": "Power tweaks for power users", "description": "Power tweaks for power users",
"scripts": { "scripts": {
"build": "shx rm -rf dist && rollup -c", "build": "shx rm -rf dist && rollup -c",

View file

@ -1,5 +1,5 @@
{ {
"name": "PowerTools", "name": "PowerTools",
"author": "NGnius", "author": "NGnius",
"flags": ["root", "debug"], "flags": ["root", "debug"],
"publish": { "publish": {

View file

@ -36,6 +36,18 @@ export async function getBatteryCurrent(): Promise<number> {
return (await call_backend("BATTERY_current_now", []))[0]; return (await call_backend("BATTERY_current_now", []))[0];
} }
export async function getBatteryChargeNow(): Promise<number> {
return (await call_backend("BATTERY_charge_now", []))[0];
}
export async function getBatteryChargeFull(): Promise<number> {
return (await call_backend("BATTERY_charge_full", []))[0];
}
export async function getBatteryChargeDesign(): Promise<number> {
return (await call_backend("BATTERY_charge_design", []))[0];
}
export async function getBatteryChargeRate(): Promise<number> { export async function getBatteryChargeRate(): Promise<number> {
return (await call_backend("BATTERY_get_charge_rate", []))[0]; return (await call_backend("BATTERY_get_charge_rate", []))[0];
} }

View file

@ -37,6 +37,9 @@ const BACKEND_INFO = "VINFO";
const CURRENT_BATT = "BATTERY_current_now"; const CURRENT_BATT = "BATTERY_current_now";
const CHARGE_RATE_BATT = "BATTERY_charge_rate"; const CHARGE_RATE_BATT = "BATTERY_charge_rate";
const CHARGE_NOW_BATT = "BATTERY_charge_now";
const CHARGE_FULL_BATT = "BATTERY_charge_full";
const CHARGE_DESIGN_BATT = "BATTERY_charge_design"
const TOTAL_CPUS = "CPUs_total"; const TOTAL_CPUS = "CPUs_total";
const ONLINE_CPUS = "CPUs_online"; const ONLINE_CPUS = "CPUs_online";
@ -58,6 +61,9 @@ const reload = function() {
backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) }); backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) });
backend.resolve(backend.getBatteryChargeRate(), (rate: number) => { set_value(CHARGE_RATE_BATT, rate) }); backend.resolve(backend.getBatteryChargeRate(), (rate: number) => { set_value(CHARGE_RATE_BATT, rate) });
backend.resolve(backend.getBatteryChargeNow(), (rate: number) => { set_value(CHARGE_NOW_BATT, rate) });
backend.resolve(backend.getBatteryChargeFull(), (rate: number) => { set_value(CHARGE_FULL_BATT, rate) });
backend.resolve(backend.getBatteryChargeDesign(), (rate: number) => { set_value(CHARGE_DESIGN_BATT, rate) });
backend.resolve(backend.getCpuCount(), (count: number) => { set_value(TOTAL_CPUS, count)}); backend.resolve(backend.getCpuCount(), (count: number) => { set_value(TOTAL_CPUS, count)});
backend.resolve(backend.getCpusOnline(), (statii: boolean[]) => { backend.resolve(backend.getCpusOnline(), (statii: boolean[]) => {
@ -130,6 +136,8 @@ const reload = function() {
const periodicals = function() { const periodicals = function() {
backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) }); backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) });
backend.resolve(backend.getBatteryChargeNow(), (rate: number) => { set_value(CHARGE_NOW_BATT, rate) });
backend.resolve(backend.getBatteryChargeFull(), (rate: number) => { set_value(CHARGE_FULL_BATT, rate) });
backend.resolve(backend.getGeneralPersistent(), (value: boolean) => { set_value(PERSISTENT_GEN, value) }); backend.resolve(backend.getGeneralPersistent(), (value: boolean) => { set_value(PERSISTENT_GEN, value) });
backend.resolve(backend.getGeneralSettingsName(), (name: string) => { backend.resolve(backend.getGeneralSettingsName(), (name: string) => {
@ -457,30 +465,30 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
<div className={staticClasses.PanelSectionTitle}> <div className={staticClasses.PanelSectionTitle}>
Battery Battery
</div> </div>
{ false && <PanelSectionRow> <PanelSectionRow>
<div className={FieldWithSeparator}> <div className={FieldWithSeparator}>
<div className={gamepadDialogClasses.FieldLabelRow}> <div className={gamepadDialogClasses.FieldLabelRow}>
<div className={gamepadDialogClasses.FieldLabel}> <div className={gamepadDialogClasses.FieldLabel}>
Now (Charge) Now (Charge)
</div> </div>
<div className={gamepadDialogClasses.FieldChildren}> <div className={gamepadDialogClasses.FieldChildren}>
{/* TODO: (7.7 * chargeNowGlobal / 1000000).toFixed(1).toString() + " Wh (" + (100 * chargeNowGlobal / chargeFullGlobal).toFixed(1).toString() + "%)"*/} {get_value(CHARGE_NOW_BATT).toFixed(1)} Wh ({(100 * get_value(CHARGE_NOW_BATT) / get_value(CHARGE_FULL_BATT)).toFixed(1)}%)
</div> </div>
</div> </div>
</div> </div>
</PanelSectionRow>} </PanelSectionRow>
{ false && <PanelSectionRow> <PanelSectionRow>
<div className={FieldWithSeparator}> <div className={FieldWithSeparator}>
<div className={gamepadDialogClasses.FieldLabelRow}> <div className={gamepadDialogClasses.FieldLabelRow}>
<div className={gamepadDialogClasses.FieldLabel}> <div className={gamepadDialogClasses.FieldLabel}>
Max (Design) Max (Design)
</div> </div>
<div className={gamepadDialogClasses.FieldChildren}> <div className={gamepadDialogClasses.FieldChildren}>
{/* TODO: (7.7 * chargeFullGlobal / 1000000).toFixed(1).toString() + " Wh (" + (100 * chargeFullGlobal / chargeDesignGlobal).toFixed(1).toString() + "%)"*/} {get_value(CHARGE_FULL_BATT).toFixed(1)} Wh ({(100 * get_value(CHARGE_FULL_BATT) / get_value(CHARGE_DESIGN_BATT)).toFixed(1)}%)
</div> </div>
</div> </div>
</div> </div>
</PanelSectionRow>} </PanelSectionRow>
<PanelSectionRow> <PanelSectionRow>
<ToggleField <ToggleField
checked={get_value(CHARGE_RATE_BATT) != null} checked={get_value(CHARGE_RATE_BATT) != null}
@ -553,7 +561,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
<div className={FieldWithSeparator}> <div className={FieldWithSeparator}>
<div className={gamepadDialogClasses.FieldLabelRow}> <div className={gamepadDialogClasses.FieldLabelRow}>
<div className={gamepadDialogClasses.FieldLabel}> <div className={gamepadDialogClasses.FieldLabel}>
Now Playing Profile
</div> </div>
<div className={gamepadDialogClasses.FieldChildren}> <div className={gamepadDialogClasses.FieldChildren}>
{get_value(NAME_GEN)} {get_value(NAME_GEN)}