Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add battery power draw for linux and freebsd #689

Merged
merged 27 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4c74a7c
Add current_now and voltage_now to battery struct and fix naming of
vsey Dec 13, 2023
b99008f
Introduce charge in addition to energy for laptops that use charge in…
vsey Dec 13, 2023
ee61700
add case of calculating the remaining battery time for current/charge
vsey Dec 13, 2023
ab294bf
add battery percentage calculation in charge case
vsey Dec 13, 2023
f6d8c4a
use capacity as default for battery percentage, less complicated and …
vsey Dec 13, 2023
b09f352
clean up if statement for battery percent calculation
vsey Dec 13, 2023
419a7d4
add power draw calculation for battery
vsey Dec 13, 2023
6e57511
add power to get_battery function output
vsey Dec 13, 2023
ddd4bec
Show wattage next to battery remaining time when wattage could be cal…
vsey Dec 13, 2023
1ad1418
remove redundant space
vsey Dec 13, 2023
7a188bf
round wattage to second decimal
vsey Dec 14, 2023
578b01e
add show_battery_power option to menu
vsey Dec 14, 2023
2934138
Only redraw battery indicator on power change if power change option …
vsey Dec 14, 2023
cd6c1b7
make discribtion in menu and settings clearer
vsey Dec 14, 2023
a81b514
add freebsd support for battery power
vsey Dec 15, 2023
0c706cd
make os compatible
vsey Dec 15, 2023
46743ab
Merge branch 'main' into battery-power-2
vsey Dec 17, 2023
5792216
Merge branch 'aristocratos:main' into battery-power-2
vsey Dec 17, 2023
9dd4379
Merge branch 'main' into battery-power-2
vsey Dec 25, 2023
63ce0ab
Merge branch 'aristocratos:main' into battery-power-2
vsey Dec 26, 2023
fb6af5d
Merge branch 'aristocratos:main' into battery-power-2
vsey Dec 29, 2023
b28c5ff
Merge branch 'main' into battery-power-2
vsey Jan 3, 2024
40cdb92
Merge branch 'aristocratos:main' into battery-power-2
vsey Jan 22, 2024
61105e4
Add battery power draw to battery inforamtion tuple for openbsd and s…
vsey Jan 22, 2024
c750543
Fix missing value in battery status tuple for openbsd
vsey Jan 22, 2024
0bb1d4b
Merge branch 'main' into battery-power-2
vsey Jan 30, 2024
f1f37ad
Merge branch 'main' into battery-power-2
aristocratos Feb 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/btop_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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},
Expand Down
12 changes: 8 additions & 4 deletions src/btop_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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)
Expand All @@ -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) {
Expand Down Expand Up @@ -2239,3 +2242,4 @@ namespace Draw {
}
}
}

5 changes: 5 additions & 0 deletions src/btop_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
"",
Expand Down
4 changes: 2 additions & 2 deletions src/btop_shared.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 {
Expand Down
13 changes: 9 additions & 4 deletions src/freebsd/btop_collect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"};

Expand Down Expand Up @@ -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";
Expand All @@ -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) {
Expand All @@ -402,7 +407,7 @@ namespace Cpu {
}
}

return {percent, seconds, status};
return {percent, watts, seconds, status};
}

auto collect(bool no_update) -> cpu_info & {
Expand Down
90 changes: 68 additions & 22 deletions src/linux/btop_collect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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";
Expand All @@ -736,7 +745,7 @@ namespace Cpu {
}
if (batteries.empty()) {
has_battery = false;
return {0, 0, ""};
return {0, 0, 0, ""};
}
}

Expand All @@ -756,25 +765,33 @@ namespace Cpu {

int percent = -1;
long seconds = -1;
float watts = -1;

//? Try to get battery percentage
if (b.use_energy) {
if (percent < 0) {
try {
percent = stoll(readfile(b.base_dir / "capacity", "-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.energy_now, "-1")) / stoll(readfile(b.energy_full, "1")));
}
catch (const std::invalid_argument&) { }
catch (const std::out_of_range&) { }
}
if (percent < 0) {
if (b.use_energy_or_charge and percent < 0) {
try {
percent = stoll(readfile(b.base_dir / "capacity", "-1"));
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
Expand All @@ -788,23 +805,52 @@ namespace Cpu {

//? Get seconds to empty
if (not is_in(status, "charging", "full")) {
if (b.use_energy and not b.power_now.empty()) {
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&) { }
}
}

if (seconds < 0 and fs::exists(b.base_dir / "time_to_empty")) {
try {
seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600);
seconds = stoll(readfile(b.base_dir / "time_to_empty", "0")) * 60;
}
catch (const std::invalid_argument&) { }
catch (const std::out_of_range&) { }
}
if (seconds < 0 and fs::exists(b.base_dir / "time_to_empty")) {
}

//? Get power draw
if (b.use_power) {
if (not b.power_now.empty()) {
try {
seconds = stoll(readfile(b.base_dir / "time_to_empty", "0")) * 60;
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, seconds, status};
return {percent, watts, seconds, status};
}

auto collect(bool no_update) -> cpu_info& {
Expand Down
8 changes: 4 additions & 4 deletions src/openbsd/btop_collect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"};

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -417,7 +417,7 @@ namespace Cpu {
}
}

return {percent, seconds, status};
return {percent, -1, seconds, status};
}

auto collect(bool no_update) -> cpu_info & {
Expand Down
8 changes: 4 additions & 4 deletions src/osx/btop_collect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"};

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 & {
Expand Down
Loading