Skip to content

Commit

Permalink
battery2: change battery symbol when discharging
Browse files Browse the repository at this point in the history
- according to its level
- popup notification when battery level < threshold
- formatting
  • Loading branch information
p1-gdd committed Jun 17, 2024
1 parent 9d66d81 commit 8c97d46
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 82 deletions.
32 changes: 27 additions & 5 deletions battery2/README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,46 @@
# battery2

Show the current status of your battery.
## Show the current status of your battery

### Plugged and full
![](images/full.png)

### Charging
![](images/charging.png)

![](images/unplugged.png)
### Discharging
![](images/unplugged_full.png)

![](images/unplugged_75.png)

![](images/unplugged_50.png)

![](images/unplugged_25.png)

![](images/unplugged_empty.png)

### Unknown status
![](images/unknown.png)

### No battery is present
![](images/nobattery.png)

# Dependencies
## Show the notification when below threshold

![](images/warning_threshold.png)

# Dependencies (Debian like)

fonts-font-awesome, acpi, python3
- `fonts-font-awesome`,
- `libnotify-bin`,
- `acpi`,
- `python3`

# Installation

To use with i3blocks, copy the blocklet configuration in the given `i3blocks.conf` into your i3blocks configuration file, the recommended config is
To use with `i3blocks`, copy the blocklet configuration in the given
`i3blocks.conf` into your i3blocks configuration file, the recommended
config is:

```INI
[battery2]
Expand Down
201 changes: 124 additions & 77 deletions battery2/battery2
Original file line number Diff line number Diff line change
@@ -1,106 +1,153 @@
#!/usr/bin/env python3
#
# Copyright (C) 2016 James Murphy
# 2024 Gregory David
# Licensed under the GPL version 2 only
#
# A battery indicator blocklet script for i3blocks

from subprocess import check_output
import os
import re
import sys
from subprocess import CalledProcessError, check_output
from typing import Dict

config = dict(os.environ)
status = check_output(['acpi'], universal_newlines=True)

if not status:
# stands for no battery found
color = config.get("color_10", "red")
fulltext = "<span color='{}'><span font='FontAwesome'>\uf00d \uf240</span></span>".format(color)
percentleft = 100
else:
# if there is more than one battery in one laptop, the percentage left is
# available for each battery separately, although state and remaining
# time for overall block is shown in the status of the first battery
batteries = status.split("\n")
state_batteries=[]
commasplitstatus_batteries=[]
percentleft_batteries=[]
time = ""
for battery in batteries:
if battery!='':
CONFIG = dict(os.environ)
DISCHARGE_LEVEL = {
90: CONFIG.get("discharge_90", "\uf240"),
75: CONFIG.get("discharge_75", "\uf241"),
50: CONFIG.get("discharge_50", "\uf242"),
25: CONFIG.get("discharge_25", "\uf243"),
10: CONFIG.get("discharge_10", "\uf244"),
}
COLOR_LEVEL = {
90: CONFIG.get("color_90", "#FFFFFF"),
80: CONFIG.get("color_80", "#FFFF66"),
70: CONFIG.get("color_70", "#FFFF33"),
60: CONFIG.get("color_60", "#FFFF00"),
50: CONFIG.get("color_50", "#FFCC00"),
40: CONFIG.get("color_40", "#FF9900"),
30: CONFIG.get("color_30", "#FF6600"),
20: CONFIG.get("color_20", "#FF3300"),
10: CONFIG.get("color_10", "#FFFFFF"),
}
WARNING_THRESHOLD = int(CONFIG.get("warning_threshold", 10))
COLOR_CHARGING = CONFIG.get("color_charging", "yellow")
COLOR_NO_BATTERY = CONFIG.get("color_no_battery", "red")


def value_for_level(percent: int, level_mapping: Dict[int, str]):
"""Get symbol associated to a level percentage."""
levels = sorted(level_mapping.items(), reverse=True)
for lvl, sym in levels:
if lvl <= percent:
return sym
return levels[-1][1]


def discharge_level(percent: int):
"""Get battery symbol for given level percentage."""
return value_for_level(percent, DISCHARGE_LEVEL)


def color_level(percent: int):
"""Get color for given level percentage."""
return value_for_level(percent, COLOR_LEVEL)


def battery2():
"""Main entry point."""
try:
status = check_output(["acpi", "-b"], universal_newlines=True)
except (FileNotFoundError, CalledProcessError):
status = None

if not status:
percentleft = 100
content = discharge_level(percentleft)
if status is None:
content = "no ACPI process"
fulltext = f"<span color='{COLOR_NO_BATTERY}' font='FontAwesome'>\uf00d {content}</span>"
shorttext = fulltext
else:
# if there is more than one battery in one laptop, the percentage left is
# available for each battery separately, although state and remaining
# time for overall block is shown in the status of the first battery
batteries = status.split("\n")
state_batteries = []
commasplitstatus_batteries = []
percentleft_batteries = []
time = ""
for battery in batteries:
if not battery:
continue
state_batteries.append(battery.split(": ")[1].split(", ")[0])
commasplitstatus = battery.split(", ")
if not time:
time = commasplitstatus[-1].strip()
# check if it matches a time
time = re.match(r"(\d+):(\d+)", time)
timeleft = ""
if time:
time = ":".join(time.groups())
timeleft = " ({})".format(time)
else:
timeleft = ""
timeleft = f"({time})"

p = int(commasplitstatus[1].rstrip("%\n"))
if p>0:
if p > 0:
percentleft_batteries.append(p)
commasplitstatus_batteries.append(commasplitstatus)
state = state_batteries[0]
commasplitstatus = commasplitstatus_batteries[0]
if percentleft_batteries:
percentleft = int(sum(percentleft_batteries)/len(percentleft_batteries))
else:
state = state_batteries[0]
commasplitstatus = commasplitstatus_batteries[0]
percentleft = 0
if percentleft_batteries:
percentleft = int(sum(percentleft_batteries) / len(percentleft_batteries))

# stands for charging
color = config.get("color_charging", "yellow")
FA_LIGHTNING = "<span color='{}'><span font='FontAwesome'>\uf0e7</span></span>".format(color)
fa_plugged_in = "<span font='FontAwesome'>\uf1e6</span>"
fa_battery = f"<span font='FontAwesome'>{discharge_level(percentleft)}</span>"

# stands for plugged in
FA_PLUG = "<span font='FontAwesome'>\uf1e6</span>"
output = []
if state == "Discharging":
output.append(f"{fa_battery}")
elif state in ["Full", "Not charging"]:
timeleft = ""
output.append(f"{fa_plugged_in}")
elif state == "Charging":
output.append(
f"<span color='{COLOR_CHARGING}' font='FontAwesome'>\uf0e7</span>"
)
output.append(fa_plugged_in)
else:
# stands for unknown status of battery
timeleft = ""
output.append("<span font='FontAwesome'>\uf128</span>")
output.append(fa_battery)

# stands for using battery
FA_BATTERY = "<span font='FontAwesome'>\uf240</span>"
output.append(f"<span color='{color_level(percentleft)}'>{percentleft}%</span>")
shorttext = " ".join(output)
output.append(timeleft)
fulltext = " ".join(output)

# stands for unknown status of battery
FA_QUESTION = "<span font='FontAwesome'>\uf128</span>"
print(fulltext)
print(shorttext)

if percentleft < WARNING_THRESHOLD and state != "Charging":
check_output(
[
"notify-send",
"-u",
"critical",
"-a",
"i3blocks.battery2",
"-t",
"0",
"Warning",
f"Battery level <b>{percentleft}%</b> is below <b>{WARNING_THRESHOLD}%</b>, plug power or suspend system",
]
)
# exit code 33 will turn background red
return 33
return 0

if state == "Discharging":
fulltext = FA_BATTERY + " "
elif state == "Full":
fulltext = FA_PLUG + " "
timeleft = ""
elif state == "Unknown":
fulltext = FA_QUESTION + " " + FA_BATTERY + " "
timeleft = ""
else:
fulltext = FA_LIGHTNING + " " + FA_PLUG + " "

def color(percent):
if percent < 10:
# exit code 33 will turn background red
return config.get("color_10", "#FFFFFF")
if percent < 20:
return config.get("color_20", "#FF3300")
if percent < 30:
return config.get("color_30", "#FF6600")
if percent < 40:
return config.get("color_40", "#FF9900")
if percent < 50:
return config.get("color_50", "#FFCC00")
if percent < 60:
return config.get("color_60", "#FFFF00")
if percent < 70:
return config.get("color_70", "#FFFF33")
if percent < 80:
return config.get("color_80", "#FFFF66")
return config.get("color_full", "#FFFFFF")

form = '<span color="{}">{}%</span>'
fulltext += form.format(color(percentleft), percentleft)
fulltext += timeleft

print(fulltext)
print(fulltext)
if percentleft < 10:
exit(33)

if __name__ == "__main__":
sys.exit(battery2())
17 changes: 17 additions & 0 deletions battery2/i3blocks.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,20 @@
command=$SCRIPT_DIR/battery2
markup=pango
interval=30
warning_threshold=10
color_charging=yellow
color_no_battery=red
color_90=#FFFFFF
color_80=#FFFF66
color_70=#FFFF33
color_60=#FFFF00
color_50=#FFCC00
color_40=#FF9900
color_30=#FF6600
color_20=#FF3300
color_10=#FFFFFF
discharge_90=
discharge_75=
discharge_50=
discharge_25=
discharge_10=
Binary file removed battery2/images/unplugged.png
Binary file not shown.
Binary file added battery2/images/unplugged_25.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added battery2/images/unplugged_50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added battery2/images/unplugged_75.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added battery2/images/unplugged_empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added battery2/images/unplugged_full.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added battery2/images/warning_threshold.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 8c97d46

Please sign in to comment.