feat: add battery conservation mode with Waybar toggle
All checks were successful
Update PKGBUILD version / update-pkgver (push) Successful in 2s

Laptops with charge_control_end_threshold support get a click-to-toggle
on the battery module (80% ↔ 100%). A ♥ icon appears when conservation
is active, hidden when inactive. State persists across reboots via
systemd oneshot service. udev rule grants wheel group write access
so no sudo is needed for toggling.
This commit is contained in:
nevaforget 2026-04-08 09:55:46 +02:00
parent 6a258151fa
commit 579a948449
8 changed files with 113 additions and 8 deletions

View File

@ -7,7 +7,16 @@ Reproduzierbares Arch-Linux-Setup basierend auf archinstall + Post-Install-Autom
- `config/` — archinstall-Konfiguration (inkl. custom-commands die das Repo nach /opt/moonarch klonen, root-owned)
- `scripts/` — Post-Install- und Helper-Scripts
- `packages/` — Paketlisten (offiziell + AUR), getrennt gepflegt
- `defaults/` — XDG-Configs, Shell-Config, Helper-Binaries, systemd User-Services, greetd/moongreet-Config, Wallpaper
- `defaults/` — XDG-Configs, Shell-Config, Helper-Binaries, systemd Services, udev-Regeln, greetd/moongreet-Config, Wallpaper
## Battery Conservation Mode
Laptops mit `charge_control_end_threshold`-Support (ThinkPad, Framework, etc.) erhalten einen Waybar-Toggle:
- Klick auf das Battery-Modul schaltet zwischen 80% und 100% Ladegrenze um
- Bei aktiver Conservation erscheint ein ♥-Icon neben der Battery-Anzeige
- Zustand wird in `/var/lib/moonarch/batsaver-threshold` persistiert und beim Boot via systemd-Service wiederhergestellt
- udev-Regel gibt Gruppe `wheel` Schreibzugriff auf den Threshold (kein sudo nötig)
- Auf Desktops ohne Battery-Support versteckt sich das Feature komplett
## Konventionen

View File

@ -1,5 +1,11 @@
# Decisions
## 2026-04-08 Battery conservation mode: udev + sysfs + Waybar toggle
- **Who**: Dominik, ClaudeCode
- **Why**: Laptops with `charge_control_end_threshold` support benefit from limiting charge to 80% to extend battery lifespan. Needed a user-friendly toggle without requiring sudo.
- **Tradeoffs**: udev RUN approach for permissions (group wheel gets write access) vs polkit/pkexec (password prompt on every toggle). Chose udev for seamless UX. State persisted in `/var/lib/moonarch/` (system-wide, not per-user) — acceptable since charge threshold is a hardware setting, not a user preference. Fixed 80% threshold instead of configurable — KISS, matches industry standard.
- **How**: udev rule grants wheel group write on `charge_control_end_threshold`. Toggle script writes sysfs + state file. systemd oneshot service restores on boot. Waybar shows ♥ icon when active, hidden when inactive. Click on battery module toggles.
## 2026-04-07 Walker theme: gtk-inherit → moonarch with fixed colors
- **Who**: Dominik, ClaudeCode
- **Why**: gtk-inherit theme relied on GTK4 color inheritance which works but doesn't update live when switching GTK themes (Walker service needs restart). Explicit color definitions make the theme self-contained and predictable.

View File

@ -131,11 +131,15 @@ defaults/
moonarch-waybar-cpugov Waybar module: CPU governor status
moonarch-waybar-gpustat Waybar module: GPU utilization
moonarch-waybar-hidpp Waybar module: Logitech HID++ device battery
moonarch-waybar-batsaver Waybar module: battery conservation mode indicator
moonarch-batsaver-toggle Toggle battery charge limit (80% ↔ 100%)
shell/zshrc Zsh config: prompt, aliases, FZF, completion
etc/greetd/ greetd daemon + greeter Niri config
etc/moongreet/ moongreet configuration
etc/systemd/user/ Systemd user services (cliphist, kanshi, walker, nautilus)
etc/systemd/system/ System service (battery conservation restore on boot)
etc/udev/rules.d/ udev rules (battery threshold permissions)
backgrounds/wallpaper.jpg Default wallpaper (shared by desktop, greeter, lock screen)
```

View File

@ -0,0 +1,28 @@
#!/usr/bin/bash
# ABOUTME: Toggles battery conservation mode between 80% and 100% charge limit.
# ABOUTME: Writes to sysfs (immediate) and state file (persistence across reboots).
THRESHOLD_FILE="/sys/class/power_supply/BAT0/charge_control_end_threshold"
STATE_DIR="/var/lib/moonarch"
STATE_FILE="${STATE_DIR}/batsaver-threshold"
CONSERVATION_LIMIT=80
[[ -f "$THRESHOLD_FILE" ]] || exit 1
CURRENT=$(cat "$THRESHOLD_FILE")
if [[ "$CURRENT" -le "$CONSERVATION_LIMIT" ]]; then
NEW=100
else
NEW="$CONSERVATION_LIMIT"
fi
# Apply immediately
echo "$NEW" > "$THRESHOLD_FILE" || exit 1
# Persist for next boot
mkdir -p "$STATE_DIR"
echo "$NEW" > "$STATE_FILE"
# Signal Waybar to refresh the batsaver module (SIGRTMIN+9)
pkill -RTMIN+9 waybar

View File

@ -0,0 +1,19 @@
#!/usr/bin/bash
# ABOUTME: Waybar module showing battery conservation mode status.
# ABOUTME: Outputs heart icon when active (threshold ≤80), empty when inactive.
THRESHOLD_FILE="/sys/class/power_supply/BAT0/charge_control_end_threshold"
# No battery threshold support → no output → Waybar hides module
[[ -f "$THRESHOLD_FILE" ]] || exit 0
THRESHOLD=$(cat "$THRESHOLD_FILE")
if [[ "$THRESHOLD" -le 80 ]]; then
jq --compact-output -n \
--arg text "♥" \
--arg tooltip "Battery Conservation: ON (limit ${THRESHOLD}%)" \
--arg class "on" \
'{text: $text, tooltip: $tooltip, class: $class}'
fi
# Threshold > 80 → no output → Waybar hides module

View File

@ -0,0 +1,15 @@
# ABOUTME: Restores battery charge threshold from saved state on boot.
# ABOUTME: Only runs on laptops with threshold support and a saved state file.
[Unit]
Description=Restore battery conservation mode threshold
After=sysinit.target
ConditionPathExists=/sys/class/power_supply/BAT0/charge_control_end_threshold
ConditionPathExists=/var/lib/moonarch/batsaver-threshold
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'cat /var/lib/moonarch/batsaver-threshold > /sys/class/power_supply/BAT0/charge_control_end_threshold'
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,4 @@
# ABOUTME: udev rule granting wheel group write access to battery charge threshold.
# ABOUTME: Enables unprivileged toggling of conservation mode via moonarch-batsaver-toggle.
SUBSYSTEM=="power_supply", ATTR{type}=="Battery", RUN+="/bin/sh -c 'chgrp wheel /sys%p/charge_control_end_threshold 2>/dev/null; chmod g+w /sys%p/charge_control_end_threshold 2>/dev/null'"

View File

@ -21,7 +21,7 @@
"bluetooth",
"group/sound",
"backlight",
"battery",
"group/battery",
"group/indicators"
],
"group/indicators": {
@ -58,6 +58,13 @@
"transition-left-to-right": true
}
},
"group/battery": {
"orientation": "inherit",
"modules": [
"battery",
"custom/batsaver"
]
},
"group/sys": {
"orientation": "inherit",
"modules": [
@ -306,13 +313,26 @@
},
"format": "{capacity}% {icon}",
"format-icons": [
"",
"",
"",
"",
""
"󰂎",
"󰁺",
"󰁻",
"󰁼",
"󰁽",
"󰁾",
"󰁿",
"󰂀",
"󰂁",
"󰂂",
"󰁹"
],
"max-length": 25
"max-length": 25,
"on-click": "moonarch-batsaver-toggle"
},
"custom/batsaver": {
"exec": "moonarch-waybar-batsaver",
"return-type": "json",
"interval": 30,
"signal": 9
},
"bluetooth": {
// "controller": "controller1", // specify the alias of the controller if there are more than 1 on the system