mirror of
https://github.com/aristocratos/btop.git
synced 2024-06-18 10:25:46 +12:00
Merge pull request #689 from vsey/battery-power-2
This commit is contained in:
commit
77c758c349
|
@ -199,6 +199,8 @@ namespace Config {
|
|||
|
||||
{"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."},
|
||||
|
||||
{"show_battery_watts", "#* Show power stats of battery next to charge indicator."},
|
||||
|
||||
{"log_level", "#* Set loglevel for \"~/.config/btop/btop.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n"
|
||||
"#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."},
|
||||
#ifdef GPU_SUPPORT
|
||||
|
@ -293,6 +295,7 @@ namespace Config {
|
|||
{"net_auto", true},
|
||||
{"net_sync", true},
|
||||
{"show_battery", true},
|
||||
{"show_battery_watts", true},
|
||||
{"vim_keys", false},
|
||||
{"tty_mode", false},
|
||||
{"disk_free_priv", false},
|
||||
|
|
|
@ -706,6 +706,7 @@ namespace Cpu {
|
|||
if (Config::getB("show_battery") and has_battery) {
|
||||
static int old_percent{}; // defaults to = 0
|
||||
static long old_seconds{}; // defaults to = 0
|
||||
static float old_watts{}; // defaults to = 0
|
||||
static string old_status;
|
||||
static Draw::Meter bat_meter {10, "cpu", true};
|
||||
static const std::unordered_map<string, string> bat_symbols = {
|
||||
|
@ -715,16 +716,18 @@ namespace Cpu {
|
|||
{"unknown", "○"}
|
||||
};
|
||||
|
||||
const auto& [percent, seconds, status] = current_bat;
|
||||
const auto& [percent, watts, seconds, status] = current_bat;
|
||||
|
||||
if (redraw or percent != old_percent or seconds != old_seconds or status != old_status) {
|
||||
if (redraw or percent != old_percent or (watts != old_watts and Config::getB("show_battery_watts")) or seconds != old_seconds or status != old_status) {
|
||||
old_percent = percent;
|
||||
old_watts = watts;
|
||||
old_seconds = seconds;
|
||||
old_status = status;
|
||||
const string str_time = (seconds > 0 ? sec_to_dhms(seconds, true, true) : "");
|
||||
const string str_percent = to_string(percent) + '%';
|
||||
const string str_watts = (watts != -1 and Config::getB("show_battery_watts") ? fmt::format("{:.2f}", watts) + 'W' : "");
|
||||
const auto& bat_symbol = bat_symbols.at((bat_symbols.contains(status) ? status : "unknown"));
|
||||
const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + to_string(Config::getI("update_ms")).size();
|
||||
const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + str_watts.size() + to_string(Config::getI("update_ms")).size();
|
||||
const int current_pos = Term::width - current_len - 17;
|
||||
|
||||
if ((bat_pos != current_pos or bat_len != current_len) and bat_pos > 0 and not redraw)
|
||||
|
@ -734,7 +737,7 @@ namespace Cpu {
|
|||
|
||||
out += Mv::to(y, bat_pos) + title_left + Theme::c("title") + Fx::b + "BAT" + bat_symbol + ' ' + str_percent
|
||||
+ (Term::width >= 100 ? Fx::ub + ' ' + bat_meter(percent) + Fx::b : "")
|
||||
+ (not str_time.empty() ? ' ' + Theme::c("title") + str_time : " ") + Fx::ub + title_right;
|
||||
+ (not str_time.empty() ? ' ' + Theme::c("title") + str_time : "") + (not str_watts.empty() ? " " + Theme::c("title") + Fx::b + str_watts : "") + Fx::ub + title_right;
|
||||
}
|
||||
}
|
||||
else if (bat_pos > 0) {
|
||||
|
@ -2239,3 +2242,4 @@ namespace Draw {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -353,6 +353,11 @@ namespace Menu {
|
|||
"Can be both batteries and UPS.",
|
||||
"",
|
||||
"\"Auto\" for auto detection."},
|
||||
{"show_battery_watts",
|
||||
"Show battery power.",
|
||||
"",
|
||||
"Show discharge power when discharging.",
|
||||
"Show charging power when charging."},
|
||||
{"log_level",
|
||||
"Set loglevel for error.log",
|
||||
"",
|
||||
|
|
|
@ -178,7 +178,7 @@ namespace Cpu {
|
|||
extern string cpuName, cpuHz;
|
||||
extern vector<string> available_fields;
|
||||
extern vector<string> available_sensors;
|
||||
extern tuple<int, long, string> current_bat;
|
||||
extern tuple<int, float, long, string> current_bat;
|
||||
|
||||
struct cpu_info {
|
||||
std::unordered_map<string, deque<long long>> cpu_percent = {
|
||||
|
@ -213,7 +213,7 @@ namespace Cpu {
|
|||
auto get_cpuHz() -> string;
|
||||
|
||||
//* Get battery info from /sys
|
||||
auto get_battery() -> tuple<int, long, string>;
|
||||
auto get_battery() -> tuple<int, float, long, string>;
|
||||
}
|
||||
|
||||
namespace Mem {
|
||||
|
|
|
@ -207,7 +207,7 @@ namespace Cpu {
|
|||
string cpuName;
|
||||
string cpuHz;
|
||||
bool has_battery = true;
|
||||
tuple<int, long, string> current_bat;
|
||||
tuple<int, float, long, string> current_bat;
|
||||
|
||||
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
||||
|
||||
|
@ -373,10 +373,11 @@ namespace Cpu {
|
|||
return core_map;
|
||||
}
|
||||
|
||||
auto get_battery() -> tuple<int, long, string> {
|
||||
if (not has_battery) return {0, 0, ""};
|
||||
auto get_battery() -> tuple<int, float, long, string> {
|
||||
if (not has_battery) return {0, 0, 0, ""};
|
||||
|
||||
long seconds = -1;
|
||||
float watts = -1;
|
||||
uint32_t percent = -1;
|
||||
size_t size = sizeof(percent);
|
||||
string status = "discharging";
|
||||
|
@ -388,6 +389,10 @@ namespace Cpu {
|
|||
if (sysctlbyname("hw.acpi.battery.time", &seconds, &size, nullptr, 0) < 0) {
|
||||
seconds = 0;
|
||||
}
|
||||
size = sizeof(watts);
|
||||
if (sysctlbyname("hw.acpi.battery.rate", &watts, &size, nullptr, 0) < 0) {
|
||||
watts = -1;
|
||||
}
|
||||
int state;
|
||||
size = sizeof(state);
|
||||
if (sysctlbyname("hw.acpi.battery.state", &state, &size, nullptr, 0) < 0) {
|
||||
|
@ -402,7 +407,7 @@ namespace Cpu {
|
|||
}
|
||||
}
|
||||
|
||||
return {percent, seconds, status};
|
||||
return {percent, watts, seconds, status};
|
||||
}
|
||||
|
||||
auto collect(bool no_update) -> cpu_info & {
|
||||
|
|
|
@ -301,7 +301,7 @@ namespace Cpu {
|
|||
string cpuName;
|
||||
string cpuHz;
|
||||
bool has_battery = true;
|
||||
tuple<int, long, string> current_bat;
|
||||
tuple<int, float, long, string> current_bat;
|
||||
|
||||
const array time_names {
|
||||
"user"s, "nice"s, "system"s, "idle"s, "iowait"s,
|
||||
|
@ -671,13 +671,14 @@ namespace Cpu {
|
|||
}
|
||||
|
||||
struct battery {
|
||||
fs::path base_dir, energy_now, energy_full, power_now, status, online;
|
||||
fs::path base_dir, energy_now, charge_now, energy_full, charge_full, power_now, current_now, voltage_now, status, online;
|
||||
string device_type;
|
||||
bool use_energy = true;
|
||||
bool use_energy_or_charge = true;
|
||||
bool use_power = true;
|
||||
};
|
||||
|
||||
auto get_battery() -> tuple<int, long, string> {
|
||||
if (not has_battery) return {0, 0, ""};
|
||||
auto get_battery() -> tuple<int, float, long, string> {
|
||||
if (not has_battery) return {0, 0, 0, ""};
|
||||
static string auto_sel;
|
||||
static std::unordered_map<string, battery> batteries;
|
||||
|
||||
|
@ -709,19 +710,27 @@ namespace Cpu {
|
|||
}
|
||||
|
||||
if (fs::exists(bat_dir / "energy_now")) new_bat.energy_now = bat_dir / "energy_now";
|
||||
else if (fs::exists(bat_dir / "charge_now")) new_bat.energy_now = bat_dir / "charge_now";
|
||||
else new_bat.use_energy = false;
|
||||
else if (fs::exists(bat_dir / "charge_now")) new_bat.charge_now = bat_dir / "charge_now";
|
||||
else new_bat.use_energy_or_charge = false;
|
||||
|
||||
if (fs::exists(bat_dir / "energy_full")) new_bat.energy_full = bat_dir / "energy_full";
|
||||
else if (fs::exists(bat_dir / "charge_full")) new_bat.energy_full = bat_dir / "charge_full";
|
||||
else new_bat.use_energy = false;
|
||||
else if (fs::exists(bat_dir / "charge_full")) new_bat.charge_full = bat_dir / "charge_full";
|
||||
else new_bat.use_energy_or_charge = false;
|
||||
|
||||
if (not new_bat.use_energy and not fs::exists(bat_dir / "capacity")) {
|
||||
if (not new_bat.use_energy_or_charge and not fs::exists(bat_dir / "capacity")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fs::exists(bat_dir / "power_now")) new_bat.power_now = bat_dir / "power_now";
|
||||
else if (fs::exists(bat_dir / "current_now")) new_bat.power_now = bat_dir / "current_now";
|
||||
if (fs::exists(bat_dir / "power_now")) {
|
||||
new_bat.power_now = bat_dir / "power_now";
|
||||
}
|
||||
else if ((fs::exists(bat_dir / "current_now")) and (fs::exists(bat_dir / "current_now"))) {
|
||||
new_bat.current_now = bat_dir / "current_now";
|
||||
new_bat.voltage_now = bat_dir / "voltage_now";
|
||||
}
|
||||
else {
|
||||
new_bat.use_power = false;
|
||||
}
|
||||
|
||||
if (fs::exists(bat_dir / "AC0/online")) new_bat.online = bat_dir / "AC0/online";
|
||||
else if (fs::exists(bat_dir / "AC/online")) new_bat.online = bat_dir / "AC/online";
|
||||
|
@ -736,7 +745,7 @@ namespace Cpu {
|
|||
}
|
||||
if (batteries.empty()) {
|
||||
has_battery = false;
|
||||
return {0, 0, ""};
|
||||
return {0, 0, 0, ""};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -756,15 +765,9 @@ namespace Cpu {
|
|||
|
||||
int percent = -1;
|
||||
long seconds = -1;
|
||||
float watts = -1;
|
||||
|
||||
//? Try to get battery percentage
|
||||
if (b.use_energy) {
|
||||
try {
|
||||
percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1")));
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
if (percent < 0) {
|
||||
try {
|
||||
percent = stoll(readfile(b.base_dir / "capacity", "-1"));
|
||||
|
@ -772,9 +775,23 @@ namespace Cpu {
|
|||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
if (b.use_energy_or_charge and percent < 0) {
|
||||
try {
|
||||
percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1")));
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
if (b.use_energy_or_charge and percent < 0) {
|
||||
try {
|
||||
percent = round(100.0 * stoll(readfile(b.charge_now, "-1")) / stoll(readfile(b.charge_full, "1")));
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
if (percent < 0) {
|
||||
has_battery = false;
|
||||
return {0, 0, ""};
|
||||
return {0, 0, 0, ""};
|
||||
}
|
||||
|
||||
//? Get charging/discharging status
|
||||
|
@ -788,13 +805,23 @@ namespace Cpu {
|
|||
|
||||
//? Get seconds to empty
|
||||
if (not is_in(status, "charging", "full")) {
|
||||
if (b.use_energy and not b.power_now.empty()) {
|
||||
try {
|
||||
seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600);
|
||||
if (b.use_energy_or_charge ) {
|
||||
if (not b.power_now.empty()) {
|
||||
try {
|
||||
seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600);
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
else if (not b.current_now.empty()) {
|
||||
try {
|
||||
seconds = round((double)stoll(readfile(b.charge_now, "0")) / (double)stoll(readfile(b.current_now, "1")) * 3600);
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
|
||||
if (seconds < 0 and fs::exists(b.base_dir / "time_to_empty")) {
|
||||
try {
|
||||
seconds = stoll(readfile(b.base_dir / "time_to_empty", "0")) * 60;
|
||||
|
@ -804,7 +831,26 @@ namespace Cpu {
|
|||
}
|
||||
}
|
||||
|
||||
return {percent, seconds, status};
|
||||
//? Get power draw
|
||||
if (b.use_power) {
|
||||
if (not b.power_now.empty()) {
|
||||
try {
|
||||
watts = (float)stoll(readfile(b.energy_now, "-1")) / 1000000.0;
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
else if (not b.voltage_now.empty() and not b.current_now.empty()) {
|
||||
try {
|
||||
watts = (float)stoll(readfile(b.current_now, "-1")) / 1000000.0 * stoll(readfile(b.voltage_now, "1")) / 1000000.0;
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {percent, watts, seconds, status};
|
||||
}
|
||||
|
||||
auto collect(bool no_update) -> cpu_info& {
|
||||
|
|
|
@ -202,7 +202,7 @@ namespace Cpu {
|
|||
string cpuName;
|
||||
string cpuHz;
|
||||
bool has_battery = true;
|
||||
tuple<int, long, string> current_bat;
|
||||
tuple<int, float, long, string> current_bat;
|
||||
|
||||
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
||||
|
||||
|
@ -385,8 +385,8 @@ namespace Cpu {
|
|||
return core_map;
|
||||
}
|
||||
|
||||
auto get_battery() -> tuple<int, long, string> {
|
||||
if (not has_battery) return {0, 0, ""};
|
||||
auto get_battery() -> tuple<int, float, long, string> {
|
||||
if (not has_battery) return {0, 0, 0, ""};
|
||||
|
||||
long seconds = -1;
|
||||
uint32_t percent = -1;
|
||||
|
@ -417,7 +417,7 @@ namespace Cpu {
|
|||
}
|
||||
}
|
||||
|
||||
return {percent, seconds, status};
|
||||
return {percent, -1, seconds, status};
|
||||
}
|
||||
|
||||
auto collect(bool no_update) -> cpu_info & {
|
||||
|
|
|
@ -191,7 +191,7 @@ namespace Cpu {
|
|||
string cpuHz;
|
||||
bool has_battery = true;
|
||||
bool macM1 = false;
|
||||
tuple<int, long, string> current_bat;
|
||||
tuple<int, float, long, string> current_bat;
|
||||
|
||||
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
||||
|
||||
|
@ -407,8 +407,8 @@ namespace Cpu {
|
|||
~IOPSList_Wrap() { CFRelease(data); }
|
||||
};
|
||||
|
||||
auto get_battery() -> tuple<int, long, string> {
|
||||
if (not has_battery) return {0, 0, ""};
|
||||
auto get_battery() -> tuple<int, float, long, string> {
|
||||
if (not has_battery) return {0, 0, 0, ""};
|
||||
|
||||
uint32_t percent = -1;
|
||||
long seconds = -1;
|
||||
|
@ -447,7 +447,7 @@ namespace Cpu {
|
|||
has_battery = false;
|
||||
}
|
||||
}
|
||||
return {percent, seconds, status};
|
||||
return {percent, -1, seconds, status};
|
||||
}
|
||||
|
||||
auto collect(bool no_update) -> cpu_info & {
|
||||
|
|
Loading…
Reference in a new issue