init
This commit is contained in:
commit
02a46e5c59
170
battery.py
Executable file
170
battery.py
Executable file
@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
poly-battery-status-py: Generates a pretty status-bar string for multi-battery systems on Linux.
|
||||
Copyright (C) 2020 Falke Carlsen
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
|
||||
PSEUDO_FS_PATH = "/sys/class/power_supply/"
|
||||
CURRENT_CHARGE_FILENAME = "energy_now"
|
||||
MAX_CHARGE_FILENAME = "energy_full"
|
||||
POWER_DRAW_FILENAME = "power_now"
|
||||
TLP_THRESHOLD_PERCENTAGE = 1.0
|
||||
PERCENTAGE_FORMAT = ".2%"
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
# parsing threshold
|
||||
try:
|
||||
TLP_THRESHOLD_PERCENTAGE = float(sys.argv[1])
|
||||
except ValueError:
|
||||
print(f"[ERROR]: Could not convert '{sys.argv[1]}' into a float.")
|
||||
if len(sys.argv) > 2:
|
||||
# parsing formatting
|
||||
PERCENTAGE_FORMAT = sys.argv[2]
|
||||
|
||||
|
||||
class Status(Enum):
|
||||
CHARGING = 1
|
||||
DISCHARGING = 2
|
||||
PASSIVE = 3
|
||||
|
||||
|
||||
class Configuration:
|
||||
time_to_completion: int
|
||||
percentage: float
|
||||
status: Status
|
||||
|
||||
def __init__(self, time_to_completion, percentage, status):
|
||||
self.time_to_completion = time_to_completion
|
||||
self.percentage = percentage
|
||||
self.status = status
|
||||
|
||||
|
||||
class Battery:
|
||||
status: Status
|
||||
current_charge: int
|
||||
max_charge: int
|
||||
power_draw: int
|
||||
|
||||
def __init__(self, status, current_charge, max_charge, power_draw):
|
||||
self.Status = status
|
||||
self.current_charge = current_charge
|
||||
self.max_charge = max_charge
|
||||
self.power_draw = power_draw
|
||||
|
||||
|
||||
def get_configuration() -> Configuration:
|
||||
# get all batteries on system
|
||||
batteries = []
|
||||
for x in Path(PSEUDO_FS_PATH).iterdir():
|
||||
bat_name = str(x.parts[len(x.parts) - 1])
|
||||
if re.match("^BAT\d+$", bat_name):
|
||||
batteries.append(Battery(
|
||||
get_status(bat_name),
|
||||
get_current_charge(bat_name),
|
||||
get_max_charge(bat_name),
|
||||
get_power_draw(bat_name)))
|
||||
|
||||
# calculate global status, assumes that if a battery is not passive, it will be discharging or charging
|
||||
config_status = Status.PASSIVE
|
||||
for bat in batteries:
|
||||
if bat.Status == Status.CHARGING:
|
||||
config_status = Status.CHARGING
|
||||
break
|
||||
elif bat.Status == Status.DISCHARGING:
|
||||
config_status = Status.DISCHARGING
|
||||
break
|
||||
|
||||
# construct and return configuration
|
||||
return Configuration(calc_time(batteries, config_status), calc_percentage(batteries), config_status)
|
||||
|
||||
|
||||
def get_status(bat_name: str) -> Status:
|
||||
raw_status = Path(f"{PSEUDO_FS_PATH}{bat_name}/status").open().read().strip()
|
||||
if raw_status == "Unknown" or raw_status == "Full":
|
||||
return Status.PASSIVE
|
||||
elif raw_status == "Charging":
|
||||
return Status.CHARGING
|
||||
elif raw_status == "Discharging":
|
||||
return Status.DISCHARGING
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
|
||||
def get_current_charge(bat_name: str) -> int:
|
||||
return int(Path(f"{PSEUDO_FS_PATH}{bat_name}/{CURRENT_CHARGE_FILENAME}").open().read().strip())
|
||||
|
||||
|
||||
def get_max_charge(bat_name: str) -> int:
|
||||
return int(Path(f"{PSEUDO_FS_PATH}{bat_name}/{MAX_CHARGE_FILENAME}").open().read().strip())
|
||||
|
||||
|
||||
def get_power_draw(bat_name: str) -> int:
|
||||
return int(Path(f"{PSEUDO_FS_PATH}{bat_name}/{POWER_DRAW_FILENAME}").open().read().strip())
|
||||
|
||||
|
||||
def calc_time(batteries: list, status: Status) -> int:
|
||||
if status == Status.PASSIVE:
|
||||
return 0
|
||||
# get total metrics on configuration
|
||||
total_current_charge = sum([bat.current_charge for bat in batteries])
|
||||
total_max_charge = sum([bat.max_charge for bat in batteries])
|
||||
total_power_draw = sum([bat.power_draw for bat in batteries])
|
||||
if total_power_draw == 0:
|
||||
return 0
|
||||
if status == Status.DISCHARGING:
|
||||
# return number of seconds until empty
|
||||
return (total_current_charge / total_power_draw) * 3600
|
||||
elif status == Status.CHARGING:
|
||||
# return number of seconds until (optionally relatively) charged
|
||||
return (((total_max_charge * TLP_THRESHOLD_PERCENTAGE) - total_current_charge) / total_power_draw) * 3600
|
||||
|
||||
|
||||
def calc_percentage(batteries: list) -> float:
|
||||
total_max_charge = sum([bat.max_charge for bat in batteries])
|
||||
total_current_charge = sum([bat.current_charge for bat in batteries])
|
||||
return total_current_charge / total_max_charge
|
||||
|
||||
|
||||
def calc_display_time(status: Status, seconds: int) -> str:
|
||||
hours = int(seconds // 3600)
|
||||
minutes = int((seconds % 3600) / 60)
|
||||
if status == Status.PASSIVE:
|
||||
return ""
|
||||
|
||||
# assume charging initially if not passive
|
||||
direction = "+"
|
||||
if status == Status.DISCHARGING:
|
||||
direction = "-"
|
||||
|
||||
# format output digitally, e.g. (+0:09)
|
||||
return f" ({direction}{hours}:{minutes:02})"
|
||||
|
||||
|
||||
def print_status(config: Configuration):
|
||||
print(f" {config.percentage:{PERCENTAGE_FORMAT}}{calc_display_time(config.status, config.time_to_completion)}")
|
||||
|
||||
|
||||
def main():
|
||||
print_status(get_configuration())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
48
config
Normal file
48
config
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
# Guess the weather hourly
|
||||
#[weather]
|
||||
#command=curl -Ss 'https://wttr.in?0&T&Q' | cut -c 16- | head -2 | xargs echo
|
||||
#interval=3600
|
||||
#color=#A4C2F4
|
||||
|
||||
[cpu]
|
||||
command=top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1"%"}'
|
||||
interval=3
|
||||
label=
|
||||
color=#A7C080
|
||||
|
||||
[temp]
|
||||
command=sensors | grep Core | head -n 1 | cut -d ' ' -f 10 | cut -d '+' -f 2
|
||||
interval=10
|
||||
color=#E67E80
|
||||
|
||||
[battery]
|
||||
command=/home/dominic/.config/i3blocks/battery.py
|
||||
interval=5
|
||||
color=#7FBBB3
|
||||
|
||||
[volume]
|
||||
command=/home/dominic/.config/i3blocks/volume.sh
|
||||
label=
|
||||
interval=once
|
||||
signal=10
|
||||
color=#D699B6
|
||||
|
||||
[pkgs]
|
||||
command=apt-get -q -y --ignore-hold --allow-change-held-packages --allow-unauthenticated -s dist-upgrade | /bin/grep ^Inst | wc -l
|
||||
interval=43200
|
||||
label=
|
||||
color=#A7C080
|
||||
|
||||
[server_pkgs]
|
||||
command=ssh domdit.com checkupdates | wc -l
|
||||
interval=43200
|
||||
label=
|
||||
color=#E67E80
|
||||
|
||||
[time]
|
||||
command=date +"%D %I:%M"
|
||||
interval=5
|
||||
color=#D3C6AA
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user