Detailed battery status is now presented in a dialogue. Quick battery status should actually work now.

This commit is contained in:
Storm Dragon
2026-06-21 23:28:49 -04:00
parent 65a03eb441
commit d3fb549fd1
4 changed files with 160 additions and 159 deletions
+6 -2
View File
@@ -132,7 +132,8 @@ In Panel Mode, single keypresses launch different information panels:
| `s` | Show system information | | `s` | Show system information |
| `r` | Open reminder panel | | `r` | Open reminder panel |
| `n` | Launch notes application | | `n` | Launch notes application |
| `b` | Open bluetooth. *requires blueman be installed at the time of your i3 config generation* | | `b` | Open Bluetooth *(requires blueman during i3 config generation)* |
| `@MODKEY@` + `b` | Speak a quick battery status |
| `Shift` + `b` | Show detailed battery information | | `Shift` + `b` | Show detailed battery information |
| `m` | Launch password manager | | `m` | Launch password manager |
| `p` | Show power options | | `p` | Show power options |
@@ -150,7 +151,10 @@ The system information panel (`s` key in Panel Mode) displays vital system stati
- Memory usage - Memory usage
- Disk space - Disk space
- Network status - Network status
- Battery level (if applicable)
### Battery Information
The battery report has two modes. Press `@MODKEY@` + `b` in Panel Mode for a concise spoken announcement of charge level and charging state. Press `Shift` + `b` in Panel Mode for the detailed report, shown in a reviewable text dialog instead of spoken aloud, so the full details can be navigated with the arrow keys: charge, status, health, chemistry, voltage, current, power draw, and cycle count when the hardware exposes them. The quick report is also available with `Alt` + `b` in Ratpoison Mode. If `acpi` is installed it is used for the report, otherwise I38 reads `/sys/class/power_supply` directly. In the detailed dialog, press `Control` + `Home` to jump back to the top of the text.
### Weather Panel ### Weather Panel
+13
View File
@@ -116,6 +116,19 @@ You can apply the same configuration to GTK2 apps. Create or edit ~/.gtkrc-2.0
- -x: Generate ~/.xinitrc and ~/.xprofile. - -x: Generate ~/.xinitrc and ~/.xprofile.
- -X: Generate ~/.xprofile only. - -X: Generate ~/.xprofile only.
## Dependency Helpers
Distro-specific dependency helpers live in `extra/`. On Arch Linux, run:
```bash
extra/arch-linux.sh
```
The helper checks I38's required packages, asks which missing provider
applications to install, adds lightweight optional feature packages, then
installs the selected package list at the end. Optional packages that need
manual choice, such as Tesseract language data, are skipped.
## Development ## Development
Enable the tracked pre-commit hooks once after cloning: Enable the tracked pre-commit hooks once after cloning:
+3
View File
@@ -1360,6 +1360,9 @@ $(if command -v blueman-manager &> /dev/null ; then
echo "bindsym b exec --no-startup-id blueman-manager, mode \"default\"" echo "bindsym b exec --no-startup-id blueman-manager, mode \"default\""
fi) fi)
# Quick battery status bound to the configured mod key+b
bindsym \$mod+b exec --no-startup-id ${i3Path}/scripts/battery_status.sh, mode "default"
# Detailed battery information bound to Shift+b # Detailed battery information bound to Shift+b
bindsym Shift+b exec --no-startup-id ${i3Path}/scripts/battery_status.sh --detailed, mode "default" bindsym Shift+b exec --no-startup-id ${i3Path}/scripts/battery_status.sh --detailed, mode "default"
+138 -157
View File
@@ -10,91 +10,71 @@
# You should have received a copy of the GNU General Public License along with I38. If not, see <https://www.gnu.org/licenses/>. # You should have received a copy of the GNU General Public License along with I38. If not, see <https://www.gnu.org/licenses/>.
# Battery status reporting.
# Simple mode (default, Panel Mode mod+b): speaks a concise status as a quick
# announcement. Detailed mode (-d/--detailed, Panel Mode Shift+b): shows
# the full report in a screen reader accessible yad text-info dialog so it can
# be reviewed with the arrow keys.
# Parse command line arguments # Parse command line arguments
detailedMode=0 detailedMode=0
if [[ "$1" == "-d" ]] || [[ "$1" == "--detailed" ]]; then if [[ "$1" == "-d" ]] || [[ "$1" == "--detailed" ]]; then
detailedMode=1 detailedMode=1
fi fi
# Read a sysfs attribute safely, stripping trailing newlines. Returns empty if
# the attribute file does not exist or cannot be read.
read_attribute() {
local path="$1"
[[ -f "$path" ]] && cat "$path" 2>/dev/null | tr -d '\n'
}
get_battery_details() { get_battery_details() {
local batteryPath="$1" local batteryPath="$1"
local batteryName="${batteryPath##*/}" local batteryName="${batteryPath##*/}"
local modelName="" local modelName
local manufacturer="" local manufacturer
local capacity="" local capacity
local status="" local status
local health="" local health
local cycleCount="" local cycleCount
local technology="" local technology
local voltage="" local voltage
local current="" local current
local power="" local power
local deviceName
local output="" local output=""
# Get model name if available modelName="$(read_attribute "${batteryPath}/model_name")"
if [[ -f "${batteryPath}/model_name" ]]; then manufacturer="$(read_attribute "${batteryPath}/manufacturer")"
modelName="$(cat "${batteryPath}/model_name" 2>/dev/null | tr -d '\n')" capacity="$(read_attribute "${batteryPath}/capacity")"
status="$(read_attribute "${batteryPath}/status")"
health="$(read_attribute "${batteryPath}/capacity_level")"
cycleCount="$(read_attribute "${batteryPath}/cycle_count")"
technology="$(read_attribute "${batteryPath}/technology")"
# Voltage (microvolts -> volts)
local voltageUv
voltageUv="$(read_attribute "${batteryPath}/voltage_now")"
if [[ -n "$voltageUv" ]] && [[ "$voltageUv" =~ ^[0-9]+$ ]]; then
voltage="$(awk "BEGIN {printf \"%.2f\", $voltageUv/1000000}")"
fi fi
# Get manufacturer if available # Current (microamps -> amps)
if [[ -f "${batteryPath}/manufacturer" ]]; then local currentUa
manufacturer="$(cat "${batteryPath}/manufacturer" 2>/dev/null | tr -d '\n')" currentUa="$(read_attribute "${batteryPath}/current_now")"
if [[ -n "$currentUa" ]] && [[ "$currentUa" =~ ^[0-9]+$ ]]; then
current="$(awk "BEGIN {printf \"%.2f\", $currentUa/1000000}")"
fi fi
# Get capacity (charge percentage) # Power (microwatts -> watts)
if [[ -f "${batteryPath}/capacity" ]]; then local powerUw
capacity="$(cat "${batteryPath}/capacity" 2>/dev/null | tr -d '\n')" powerUw="$(read_attribute "${batteryPath}/power_now")"
fi if [[ -n "$powerUw" ]] && [[ "$powerUw" =~ ^[0-9]+$ ]]; then
power="$(awk "BEGIN {printf \"%.2f\", $powerUw/1000000}")"
# Get status (Charging, Discharging, Full, etc.)
if [[ -f "${batteryPath}/status" ]]; then
status="$(cat "${batteryPath}/status" 2>/dev/null | tr -d '\n')"
fi
# Get health/capacity level if available
if [[ -f "${batteryPath}/capacity_level" ]]; then
health="$(cat "${batteryPath}/capacity_level" 2>/dev/null | tr -d '\n')"
fi
# Get cycle count if available
if [[ -f "${batteryPath}/cycle_count" ]]; then
cycleCount="$(cat "${batteryPath}/cycle_count" 2>/dev/null | tr -d '\n')"
fi
# Get technology (Li-ion, Li-poly, etc.)
if [[ -f "${batteryPath}/technology" ]]; then
technology="$(cat "${batteryPath}/technology" 2>/dev/null | tr -d '\n')"
fi
# Get voltage (in microvolts, convert to volts)
if [[ -f "${batteryPath}/voltage_now" ]]; then
local voltageUv
voltageUv="$(cat "${batteryPath}/voltage_now" 2>/dev/null | tr -d '\n')"
if [[ -n "$voltageUv" ]] && [[ "$voltageUv" =~ ^[0-9]+$ ]]; then
voltage="$(awk "BEGIN {printf \"%.2f\", $voltageUv/1000000}")"
fi
fi
# Get current (in microamps, convert to amps)
if [[ -f "${batteryPath}/current_now" ]]; then
local currentUa
currentUa="$(cat "${batteryPath}/current_now" 2>/dev/null | tr -d '\n')"
if [[ -n "$currentUa" ]] && [[ "$currentUa" =~ ^[0-9]+$ ]]; then
current="$(awk "BEGIN {printf \"%.2f\", $currentUa/1000000}")"
fi
fi
# Get power (in microwatts, convert to watts)
if [[ -f "${batteryPath}/power_now" ]]; then
local powerUw
powerUw="$(cat "${batteryPath}/power_now" 2>/dev/null | tr -d '\n')"
if [[ -n "$powerUw" ]] && [[ "$powerUw" =~ ^[0-9]+$ ]]; then
power="$(awk "BEGIN {printf \"%.2f\", $powerUw/1000000}")"
fi
fi fi
# Build readable device name # Build readable device name
local deviceName="$batteryName"
if [[ -n "$manufacturer" ]] && [[ -n "$modelName" ]]; then if [[ -n "$manufacturer" ]] && [[ -n "$modelName" ]]; then
deviceName="$manufacturer $modelName" deviceName="$manufacturer $modelName"
elif [[ -n "$modelName" ]]; then elif [[ -n "$modelName" ]]; then
@@ -102,116 +82,117 @@ get_battery_details() {
elif [[ -n "$manufacturer" ]]; then elif [[ -n "$manufacturer" ]]; then
deviceName="$manufacturer Battery" deviceName="$manufacturer Battery"
else else
# Try to make the battery name more readable
deviceName="${batteryName//BAT/Battery }" deviceName="${batteryName//BAT/Battery }"
deviceName="${deviceName//hid-/}" deviceName="${deviceName//hid-/}"
deviceName="${deviceName//_/ }" deviceName="${deviceName//_/ }"
fi fi
# Build the output string
output="$deviceName" output="$deviceName"
[[ -n "$capacity" ]] && output="${output}"$'\n'"Charge: ${capacity}%"
if [[ -n "$capacity" ]]; then [[ -n "$status" ]] && output="${output}"$'\n'"Status: ${status,,}"
output="$output, ${capacity}%" [[ -n "$health" ]] && output="${output}"$'\n'"Health: ${health,,}"
fi [[ -n "$technology" ]] && output="${output}"$'\n'"Type: $technology"
[[ -n "$voltage" ]] && output="${output}"$'\n'"Voltage: ${voltage} V"
if [[ -n "$status" ]]; then [[ -n "$current" ]] && output="${output}"$'\n'"Current: ${current} A"
output="$output, ${status,,}" [[ -n "$power" ]] && output="${output}"$'\n'"Power: ${power} W"
fi [[ -n "$cycleCount" ]] && output="${output}"$'\n'"Cycles: $cycleCount"
if [[ -n "$health" ]]; then
output="$output, health: ${health,,}"
fi
if [[ -n "$technology" ]]; then
output="$output, type: $technology"
fi
if [[ -n "$voltage" ]]; then
output="$output, voltage: ${voltage}V"
fi
if [[ -n "$current" ]]; then
output="$output, current: ${current}A"
fi
if [[ -n "$power" ]]; then
output="$output, power: ${power}W"
fi
if [[ -n "$cycleCount" ]]; then
output="$output, cycles: $cycleCount"
fi
echo "$output" echo "$output"
} }
# Simple battery status (default mode) # Concise one-line report for the simple spoken announcement.
get_battery_simple() { get_battery_simple() {
local batteryPath="$1" local batteryPath="$1"
local bat="${batteryPath##*/}" local batteryName="${batteryPath##*/}"
bat="${bat//BAT/Battery }" local status
bat="${bat}: $( { cat "${batteryPath}/status";echo -n ", "; cat "${batteryPath}/capacity"; } | tr -d \\n) percent." local capacity
echo "$bat" local deviceName
status="$(read_attribute "${batteryPath}/status")"
capacity="$(read_attribute "${batteryPath}/capacity")"
deviceName="${batteryName//BAT/Battery }"
if [[ -n "$status" ]] && [[ -n "$capacity" ]]; then
echo "${deviceName}: ${status,,}, ${capacity}%"
elif [[ -n "$capacity" ]]; then
echo "${deviceName}: ${capacity}%"
fi
} }
# Main script
if [[ $detailedMode -eq 1 ]]; then if [[ $detailedMode -eq 1 ]]; then
# Detailed mode # Detailed mode: show the full report in a reviewable yad text-info dialog.
if command -v acpi &> /dev/null; then batteryInfoText=""
# Try acpi first for more detailed info
batteryInfo=""
while IFS= read -r line; do
if [[ -n "$batteryInfo" ]]; then
batteryInfo="${batteryInfo}. "
fi
batteryInfo="${batteryInfo}${line}"
done < <(acpi -V 2>/dev/null | grep -i battery)
if [[ -n "$batteryInfo" ]]; then
spd-say -P important -Cw "$batteryInfo"
exit 0
fi
fi
# Fallback to /sys/class/power_supply for detailed info
batteryCount=0 batteryCount=0
batteryOutput=""
while IFS= read -r batteryPath; do # Append a non-empty battery block, separating batteries with a blank line.
if [[ -e "${batteryPath}/capacity" ]] || [[ -e "${batteryPath}/status" ]]; then add_battery_block() {
batteryDetails="$(get_battery_details "$batteryPath")" local block="$1"
[[ -z "$block" ]] && return
if [[ -n "$batteryDetails" ]]; then batteryCount=$((batteryCount + 1))
((batteryCount++)) if [[ -n "$batteryInfoText" ]]; then
if [[ -n "$batteryOutput" ]]; then batteryInfoText="${batteryInfoText}"$'\n\n'
batteryOutput="${batteryOutput}. "
fi
batteryOutput="${batteryOutput}${batteryDetails}"
fi
fi fi
done < <(find /sys/class/power_supply -type l 2>/dev/null) batteryInfoText="${batteryInfoText}${block}"
}
# Prefer acpi -V, fall back to /sys/class/power_supply.
if command -v acpi &> /dev/null; then
acpiInfo=""
while IFS= read -r line; do
[[ -z "$line" ]] && continue
if [[ -n "$acpiInfo" ]]; then
acpiInfo="${acpiInfo}"$'\n'
fi
acpiInfo="${acpiInfo}${line}"
done < <(acpi -V 2>/dev/null | grep -i battery)
add_battery_block "$acpiInfo"
fi
if [[ $batteryCount -eq 0 ]]; then if [[ $batteryCount -eq 0 ]]; then
spd-say -P important -Cw "No battery information available" while IFS= read -r batteryPath; do
else if [[ -e "${batteryPath}/capacity" ]] || [[ -e "${batteryPath}/status" ]]; then
spd-say -P important -Cw "$batteryOutput" add_battery_block "$(get_battery_details "$batteryPath")"
fi
done < <(find /sys/class/power_supply -type l 2>/dev/null)
fi fi
else
# Simple mode (default) if [[ $batteryCount -eq 0 ]]; then
if command -v acpi &> /dev/null; then batteryInfoText="No battery information available."
bat="$(acpi -b)"
spd-say -P important -Cw "$bat"
else
find /sys/class/power_supply -type l -exec bash -c '
for i ; do
if [[ -e "$i/capacity" ]]; then
bat="${i##*/}"
bat="${bat//BAT/Battery }"
bat="${bat}: $( { cat "${i}/status";echo -n ", "; cat "${i}/capacity"; } | tr -d \\n) percent."
spd-say -P important -Cw "$bat"
fi
done
' _ {} \;
fi fi
displayText="Battery Information (Detailed)
${batteryInfoText}
End of text. Press Control+Home to return to the beginning."
echo "$displayText" | yad --pname=I38Battery \
--title="I38 Battery Information" \
--text-info \
--show-cursor \
--width=450 \
--height=400 \
--center \
--button="Close:0"
exit $?
fi fi
# Simple mode: speak a concise status as a quick announcement.
announcement=""
if command -v acpi &> /dev/null; then
announcement="$(acpi -b 2>/dev/null)"
else
while IFS= read -r batteryPath; do
if [[ -e "${batteryPath}/capacity" ]]; then
block="$(get_battery_simple "$batteryPath")"
[[ -n "$block" ]] && announcement="${announcement:+$announcement. }$block"
fi
done < <(find /sys/class/power_supply -type l 2>/dev/null)
fi
if [[ -z "$announcement" ]]; then
announcement="No battery information available."
fi
spd-say -P important -Cw "$announcement"
exit $?